Hi all,
At present, BOLT-3 commitment transactions provide a two-layer
pay-to-self path, so that you can reduce the three options:
1) pay-to-them due to revoked commitment
2) pay-to-me due to timeout (or: preimage known)
3) pay-to-them due to preimage known (or: timeout)
to just the two options:
1) pay-to-them due to revoked commitment
2) pay-to-me due to timeout (or: preimage known)
This allows the `to_self_delay` and the HTLC timeout (and hence the
`cltv_expiry_delta`) to be chosen independently.
As it stands, both the original eltoo proposal [0] and the
ANYPREVOUT-based sketch [1] don't have this property, which means that
either the `cltv_expiry_delta` needs to take the `to_self_delay` into
account, or you risk not being able to claim funds to cover payments
you forward.
[0] https://blockstream.com/eltoo.pdf
[1]
https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-May/001996.html
I think if we drop the commitment to the input value from
ANYPREVOUTANYSCRIPT signatures, it's possible to come up with a scheme
that preserves the other benefits of eltoo while also having the same
benefits BOLT-3 currently achieves. I think for eltoo it needs to be a
channel-wide "shared_delay" rather than a "to_self" delay, so I'll use
that.
Here's the setup. We have four types of transaction:
* funding transaction, posted on-chain as part of channel setup
* update transaction, posted on-chain to close the channel at a
given state
* revocable claim transaction, posted on-chain to reveal a preimage
or establish a timeout has passed
* settlement transaction, to actually claim funds
As with eltoo, if a stale update transaction is posted, it can be spent
via any subsequent update transaction with no penalty. The revocable
claim transactions have roughly the same goal as the second layer BOLT-3
transactions, that is going from:
1) spent by a later update transaction
2) pay-to-me due to timeout (or: preimage known)
3) pay-to-them due to preimage known (or: timeout)
to
1) spent by a later update transaction
2) pay-to-me due to timeout (or: preimage known)
In detail:
* Get a pubkey from each peer (A, B), and calculate P=MuSig(A,B).
* Each state update involves constructing and calculating signatures
for new update transactions, revocable claim transactions and
settlement transactions.
* The update transaction has k+2 outputs, where k is the number of open
PTLCs. Each PTLC output pays to P as the internal key, and:
IF CODESEP [i] ELSE [500e6+n+1] CLTV ENDIF DROP OP_1 CHECKSIG
as the script. i varies from 1..k; n is the state counter, starting
at 1 and counting up.
Each balance output pays to P as the internal key and:
IF CODESEP IF [balance_pubkey_n] [shared_delay] CSV ELSE OP_1 OP_0 ENDIF
ELSE OP_1 [500e6+n+1] CLTV ENDIF
DROP CHECKSIG
as the script.
The signature that allows an update tx to spend a previous update tx
is calculated using ALL|ANYPREVOUTANYSCRIPT, a locktime of 500e6+n,
with the key P, and codesep_pos=0x_.
* For each output of the update tx and each party that can spend it,
we also construct a revocable claim transaction. These are designed
to update a single output of each PTLC, and their output pays to P
as the internal key, and the script:
IF [i*P+p] CODESEP ELSE [500e6+n+1] CLTV ENDIF DROP OP_1 CHECKSIG
(swapping the position of the CODESEP opcode, and encoding both i and
p in the script -- P is the number of peers in the channel, so 2
here, and p is an identifier for each peer so either 0 or 1; i=1..k
for HTLCs, i=0 for the balances)
The signature that allows this tx to be applied to the update tx
is calculated as SINGLE|ANYPREVOUT, with the script committed and
codesep_pos=1. This signature should be made conditional for each
PTLC, either by being an adaptor signature requiring the point preimage
to be added, or by having a locktime given.
* For each revocable claim transaction, we also construct a settlement
transaction. The outputs of the settlement transactions are just
an address for whichever peer receives the funds.
These are also done by SINGLE|ANYPREVOUT signatures, with nSequence
set to the shared_delay. There's no locktime or adaptor signatures
needed here, since they were taken care of for the revocable claim
transaction. The signatures commit to the respective scripts, and
set codesep_pos to either 1 or 2 depending on whether a revocable
claim is being spent or not.
* The funding transaction pays to internal key P, with tapscript:
"OP_1 CHECKSIGVERIFY 500e6 CLTV"
Then: to spend from the funding transaction cooperatively, you make a
new SIGHASH_ALL signature based the output key Q for the funding tx.
If you can't do that, you post two transactions: the latest update tx,
and another tx that includes any revocable claim tx's you can already
claim and an input to cover fees, and any change from