mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-23 15:04:19 +01:00
gossipd: don't close non-local channels immediately, add 12 block delay.
This adds a new "chan_dying" message to the gossip_store, but since we already changed the minor version in this PR, we don't bump it again. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Added: Protocol: We now delay forgetting funding-spent channels for 12 blocks (as per latest BOLTs, to support splicing in future).
This commit is contained in:
@@ -4085,7 +4085,7 @@ def test_multichan(node_factory, executor, bitcoind):
|
||||
l2.rpc.close(l3.info['id'])
|
||||
|
||||
l2.rpc.close(scid23b)
|
||||
bitcoind.generate_block(1, wait_for_mempool=1)
|
||||
bitcoind.generate_block(13, wait_for_mempool=1)
|
||||
sync_blockheight(bitcoind, [l1, l2, l3])
|
||||
|
||||
# Gossip works as expected.
|
||||
@@ -4130,14 +4130,14 @@ def test_multichan(node_factory, executor, bitcoind):
|
||||
"state": "RCVD_REMOVE_ACK_REVOCATION"},
|
||||
{"short_channel_id": scid12,
|
||||
"id": 2,
|
||||
"expiry": 123,
|
||||
"expiry": 135,
|
||||
"direction": "out",
|
||||
"amount_msat": Millisatoshi(100001001),
|
||||
"payment_hash": inv3['payment_hash'],
|
||||
"state": "RCVD_REMOVE_ACK_REVOCATION"},
|
||||
{"short_channel_id": scid12,
|
||||
"id": 3,
|
||||
"expiry": 123,
|
||||
"expiry": 135,
|
||||
"direction": "out",
|
||||
"amount_msat": Millisatoshi(100001001),
|
||||
"payment_hash": inv4['payment_hash'],
|
||||
|
||||
@@ -96,7 +96,7 @@ def test_block_backfill(node_factory, bitcoind, chainparams):
|
||||
|
||||
# Now close the channel and make sure `l3` cleans up correctly:
|
||||
txid = l1.rpc.close(l2.info['id'])['txid']
|
||||
bitcoind.generate_block(1, wait_for_mempool=txid)
|
||||
bitcoind.generate_block(13, wait_for_mempool=txid)
|
||||
wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 0)
|
||||
|
||||
|
||||
|
||||
@@ -559,8 +559,9 @@ def test_gossip_persistence(node_factory, bitcoind):
|
||||
# channel from their network view
|
||||
l1.rpc.dev_fail(l2.info['id'])
|
||||
|
||||
# We need to wait for the unilateral close to hit the mempool
|
||||
bitcoind.generate_block(1, wait_for_mempool=1)
|
||||
# We need to wait for the unilateral close to hit the mempool,
|
||||
# and 12 blocks for nodes to actually forget it.
|
||||
bitcoind.generate_block(13, wait_for_mempool=1)
|
||||
|
||||
wait_for(lambda: active(l1) == [scid23, scid23])
|
||||
wait_for(lambda: active(l2) == [scid23, scid23])
|
||||
@@ -1391,7 +1392,7 @@ def test_gossip_notices_close(node_factory, bitcoind):
|
||||
|
||||
txid = l2.rpc.close(l3.info['id'])['txid']
|
||||
wait_for(lambda: only_one(l2.rpc.listpeers(l3.info['id'])['peers'])['channels'][0]['state'] == 'CLOSINGD_COMPLETE')
|
||||
bitcoind.generate_block(1, txid)
|
||||
bitcoind.generate_block(13, txid)
|
||||
|
||||
wait_for(lambda: l1.rpc.listchannels()['channels'] == [])
|
||||
wait_for(lambda: l1.rpc.listnodes()['nodes'] == [])
|
||||
@@ -2097,7 +2098,7 @@ def test_topology_leak(node_factory, bitcoind):
|
||||
|
||||
# Close and wait for gossip to catchup.
|
||||
txid = l2.rpc.close(l3.info['id'])['txid']
|
||||
bitcoind.generate_block(1, txid)
|
||||
bitcoind.generate_block(13, txid)
|
||||
|
||||
wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2)
|
||||
|
||||
@@ -2122,3 +2123,45 @@ def test_parms_listforwards(node_factory):
|
||||
|
||||
assert len(forwards_new) == 0
|
||||
assert len(forwards_dep) == 0
|
||||
|
||||
|
||||
@pytest.mark.developer("gossip without DEVELOPER=1 is slow")
|
||||
def test_close_12_block_delay(node_factory, bitcoind):
|
||||
l1, l2, l3, l4 = node_factory.line_graph(4, wait_for_announce=True)
|
||||
|
||||
# Close l1-l2
|
||||
txid = l1.rpc.close(l2.info['id'])['txid']
|
||||
bitcoind.generate_block(1, txid)
|
||||
|
||||
# But l4 doesn't believe it immediately.
|
||||
l4.daemon.wait_for_log("channel .* closing soon due to the funding outpoint being spent")
|
||||
|
||||
# Close l2-l3 one block later.
|
||||
txid = l2.rpc.close(l3.info['id'])['txid']
|
||||
bitcoind.generate_block(1, txid)
|
||||
l4.daemon.wait_for_log("channel .* closing soon due to the funding outpoint being spent")
|
||||
|
||||
# BOLT #7:
|
||||
# - once its funding output has been spent OR reorganized out:
|
||||
# - SHOULD forget a channel after a 12-block delay.
|
||||
|
||||
# That implies 12 blocks *after* spending, i.e. 13 blocks deep!
|
||||
|
||||
# 12 blocks deep, l4 still sees it
|
||||
bitcoind.generate_block(10)
|
||||
sync_blockheight(bitcoind, [l4])
|
||||
assert len(l4.rpc.listchannels(source=l1.info['id'])['channels']) == 1
|
||||
|
||||
# 13 blocks deep does it.
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: l4.rpc.listchannels(source=l1.info['id'])['channels'] == [])
|
||||
|
||||
# Other channel still visible.
|
||||
assert len(l4.rpc.listchannels(source=l2.info['id'])['channels']) == 1
|
||||
|
||||
# Restart: it remembers channel is dying.
|
||||
l4.restart()
|
||||
|
||||
# One more block, it's forgotten too.
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: l4.rpc.listchannels(source=l2.info['id'])['channels'] == [])
|
||||
|
||||
@@ -363,7 +363,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind):
|
||||
# It will use an explicit exposeprivatechannels even if it thinks its a dead-end
|
||||
l0.rpc.close(l1.info['id'])
|
||||
l0.wait_for_channel_onchain(l1.info['id'])
|
||||
bitcoind.generate_block(1)
|
||||
bitcoind.generate_block(13)
|
||||
wait_for(lambda: l2.rpc.listchannels(scid_dummy)['channels'] == [])
|
||||
|
||||
inv = l2.rpc.invoice(amount_msat=123456, label="inv7", description="?", exposeprivatechannels=scid)
|
||||
|
||||
Reference in New Issue
Block a user