Eltoo Onchain
Eltoo is a proposal to make LN contracts symmetric and thus easier to settle. They remove the need for exchange of keys to invalidate previous transactions.
With Eltoo, payments in the LN are still routed using HTLCs, however, old states of channels become cleaner to invalidate and manage.
The eltoo paper describes the solution by first describing an on chain solution to invalidate previous states of contracts. Later they describe how this can be be done off-chain.
This example covers transactions to show of the onchain eltoo protocol will work.
In the script below, we make extensive use of transitions to describe multiple branches of execution.
Simple case: Settlement Immediately Spends From Setup
We run the following transitions to capture this case.
-
setup
-
bob_creates_settlement
-
alice_broadcasts_setup_tx
-
alice_signs_settlement
-
alice_broadcasts_settlement
Create a New Update
Create an update and a new settlement, and finally spend the settlement. In this case, the setup is spent by an update which is spent by the settlement.
-
reset
-
setup
-
bob_creates_settlement
-
alice_broadcasts_setup_tx
-
create_new_update
-
create_new_settlement
-
broadcast_new_update
-
broadcast_new_settlemen
Can’t Spend Settlement Before Confirming Update
Capture the case where a settlement fails to be spent before the update has confirmed
-
reset
-
setup
-
bob_creates_settlement
-
alice_broadcasts_setup_tx
-
create_new_update
-
create_new_settlement
-
broadcast_new_settlement_fail
Source
Here is the complete source code describing all the transitions above.
@alice = key :new
@alice_settlement_key = key :new
@bob = key :new
@bob_settlement_key = key :new
@update_script = %(
OP_IF
2 @alice_settlement_key @bob_settlement_key 2 OP_CHECKMULTISIGVERIFY 10 OP_CSV
OP_ELSE
2 @alice @bob 2 OP_CHECKMULTISIG
OP_ENDIF
)
transition :setup do
extend_chain to: @alice, num_blocks: 101
@alice_input_tx = spendable_coinbase_for @alice
@setup_tx = transaction inputs: [{ tx: @alice_input_tx, vout: 0, script_sig: 'sig:_skip' }],
outputs: [{ script: @update_script, amount: 49.999.sats }]
assert_not_mempool_accept @setup_tx
end
transition :bob_creates_settlement do
@settlement_tx = transaction inputs: [{ tx: @setup_tx,
vout: 0,
script_sig: 'sig:multi(_empty,@bob_settlement_key) 0x01',
csv: 10 }],
outputs: [{ descriptor: 'wpkh(@alice)',
amount: 49.998.sats }]
end
transition :alice_broadcasts_setup_tx do
# Alice signs the funding transaction and broadcasts it
update_script_sig for_tx: @setup_tx, at_index: 0, with_script_sig: 'sig:wpkh(@alice)'
broadcast @setup_tx
confirm transaction: @setup_tx, to: @bob
end
transition :alice_signs_settlement do
update_script_sig for_tx: @settlement_tx, at_index: 0,
with_script_sig: 'sig:multi(@alice_settlement_key,@bob_settlement_key) 0x01'
extend_chain num_blocks: 10
assert_mempool_accept @settlement_tx
end
transition :alice_broadcasts_settlement do
broadcast @settlement_tx
confirm transaction: @settlement_tx
end
transition :create_new_update do
# new update transaction spending setup tx
@update_tx = transaction inputs: [{ tx: @setup_tx, vout: 0, script_sig: 'sig:multi(@alice,@bob) ""' }],
outputs: [{ script: @update_script, amount: 49.998.sats }]
assert_mempool_accept @update_tx
end
transition :broadcast_new_update do
broadcast @update_tx
confirm transaction: @update_tx
end
transition :create_new_settlement do
# new settlement transaction spending update tx
@new_settlement_tx = transaction inputs: [{ tx: @update_tx, vout: 0,
script_sig: 'sig:multi(_empty,@bob_settlement_key) 0x01', csv: 10 }],
outputs: [{ descriptor: 'wpkh(@alice)', amount: 48.997.sats },
{ descriptor: 'wpkh(@bob)', amount: 1.sats }]
assert_not_mempool_accept @new_settlement_tx
end
transition :broadcast_new_settlement do
update_script_sig for_tx: @new_settlement_tx, at_index: 0,
with_script_sig: 'sig:multi(@alice_settlement_key,@bob_settlement_key) 0x01'
extend_chain num_blocks: 10
broadcast @new_settlement_tx
confirm transaction: @new_settlement_tx
end
transition :broadcast_new_settlement_fails do
update_script_sig for_tx: @new_settlement_tx, at_index: 0,
with_script_sig: 'sig:multi(@alice_settlement_key,@bob_settlement_key) 0x01'
extend_chain num_blocks: 10
assert_not_mempool_accept @new_settlement_tx
end
# Simple case: settlement immediately spends from setup
run_transitions :setup,
:bob_creates_settlement,
:alice_broadcasts_setup_tx,
:alice_signs_settlement,
:alice_broadcasts_settlement
# Create an update and a new settlement, and finally spend the settlement.
# In this case, the setup is spent by an update which is spent by the settlement.
run_transitions :reset,
:setup,
:bob_creates_settlement,
:alice_broadcasts_setup_tx,
:create_new_update,
:create_new_settlement,
:broadcast_new_update,
:broadcast_new_settlement
# Capture the case where a settlement fails to be spent before the
# update has confirmed
run_transitions :reset,
:setup,
:bob_creates_settlement,
:alice_broadcasts_setup_tx,
:create_new_update,
:create_new_settlement,
:broadcast_new_settlement_fails