Eltoo is a mechanism to perform off-chain state updates to a payment channel (or more generally: a state channel). The idea is to combine the following:
- have an incremental number attached to each state update;
- allow any state with a higher incremental number to replace the current state;
- have a timelock on any effective use of the state; that is, any spending condition that requires a certain state should be timelocked, in order to allow other parties in the protocol to publish the latest state, if an attempt to use an old state is performed.
In the following, we assume the case of a 2-party protocol; however, it might be possible to generalize to multiple parties.
Adding an opcode like OP_CHECKSIGFROMSTACK
would allow an easy mechanism for eltoo replacement: parties in the contract simply sign the hash of (i, state_i). One spending condition of the contract allows to replace the current state (i, state_i) with (j, state_j) as long as j > i, and the state is signed by both parties. Any other spending conditions that depends on the validity of the published state is timelocked, to allow the other party to update the state if necessary.
Trivial.
Without CSFS
, one can use the fraud proof machinery to simulate CSFS
.
Interesting that it's possible in theory, but not desirable in practice for such a simple primitive.
In the current semantics of MATT, there is no way to access and work with arbitrary signed data within Script.
In order to obviate to this, we can however take advantage of the data embedding logic for inputs of the transaction, in order to allow a UTXO (containing the state channel contract) to perform on-chain eltoo-style replacement.
Requirement: The semantics of CHECKCONTRACTVERIFY
(CCV
) must allow inspecting other inputs, rather than just the current input or an output as originally proposed.
These (virtual) UTXOs are used to pre-sign specific transactions that can be used to perform an off-chain state update. In order to update the channel to some new state (i, state_i)
, Alice and Bob would sign transactions sending both DataAnchor
UTXOs to a Update
utxo with committed data (i, state_i)
. The only spending path is a script with a key MuSig2(Alice_update_pk, Bob_update_pk)
, and it checks that the output is an [Onchain](i, state_i)
script below.
[Update](i, state_i)
- (keypath) NUMS
MuSig2(Alice_update_pk, Bob_update_pk) CHECKSIG
, then send to[Onchain](i, state_i))
usingCCV
Remark: could be more efficient to use CTV instead of CCV here! However, the ctv-hash
would need to be added in the embedded data, as the taptree of [Update]
is referenced in the [Offchain]
script spend, and must be immutable across state updates.
A channel is created by first signing transactions spending the (virtual) anchor UTXOs to an [Update](0, state_0)
output, then committing funds to a UTXO [Offchain]
that contains the following spending conditions:
[Offchain]
(off-chain execution)
- (keypath) a MuSig2 aggregate key of both parties.
- If spent together with a
[Update]
script with embedded data(i, state_i)
, send to[Onchain](i, state_i)
This is the structure of the Onchain
version of the channel:
[Onchain](i, state_i)
- (keypath) a MuSig2 aggregate key of both parties.
- If spent together with a
[Update]
script with embedded data(j, state_j)
, andj > i
, send to[Onchain](j, state_j)
- TODO: add application-specific timelocked spending conditions based on the current state
Both parties choose one of their UTXOs and they lock it (that is, not spend it) until off-chain execution is in progress.
Alice creates a transaction spending this UTXO to [Update](0, state_0)
.
Bob does the same.
They both presign the spend of these (virtual) UTXOs with ANYONECANPAY
using the script path, and with first output [Onchain](0, state_0)
In order to update the state to (i+1, state_{i+1})
off-chain, the parties would pre-sign a spend of the other party's (virtual) [Update](i+1, state_{i+1})
with SIGHASH_ANYONECANPAY
, with first output [Onchain](i, state_i)
.
Note: in a state channel, the party who's "turn" is to move would sign the other party's virtual Update
first; in a payment channel, the party whose balance is decreasing signs the other party's Update
first.
Alice and Bob use the keypath of [Offchain]
to close the channel. In the cooperative case, just two P2TR transactions go on-chain, with no script spends.
The party that wants to move the contract on-chain publishes:
- the presigned transaction spending their locked UTXO to create the last
[Update](i, state_i)
- a transaction spending the
[Offchain]
UTXO using the script path, together with theUpdate
tx, creating the[Onchain](i, state_i)
UTXO
Note: a third party could spend the [Update](i, state_i)
due to ANYONECANPAY
, therefore preventing the normal spending of the [Offchain]
UTXO; however, this is pointless since they would have to create the expected [Onchain](i, state_i)
output thanks to the CCV in the [Update]
UTXO, which can therefore continue the contract execution as expected.
The keypath allows parties to move the contract back off-chain if cooperation is restored.