From 4d3b4892230c82a1f9c90bea738d9d5cd63b965d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 16 Nov 2023 09:52:59 +1030 Subject: [PATCH] pytest: fix tests in assumption that listchannels will no longer show private gossip. Some can only be changed once that is true, but some can be removed/amended already. Signed-off-by: Rusty Russell --- tests/test_gossip.py | 135 ++++++------------------------------------ tests/test_opening.py | 5 +- tests/test_pay.py | 22 ++++--- tests/test_plugin.py | 18 ++++-- 4 files changed, 48 insertions(+), 132 deletions(-) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index c4ed0999dc41..56a4ca847032 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1555,104 +1555,30 @@ def test_getroute_exclude(node_factory, bitcoind): l1.rpc.getroute(l4.info['id'], 1, 1, exclude=[chan_l2l3, l5.info['id'], chan_l2l4]) -def test_gossip_store_local_channels(node_factory, bitcoind): - l1, l2 = node_factory.line_graph(2, wait_for_announce=False) - - # We see this channel, even though it's not announced, because it's local. - wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2) - - l2.stop() - l1.restart() - - # We should still see local channels! - time.sleep(3) # Make sure store is loaded - chans = l1.rpc.listchannels()['channels'] - assert len(chans) == 2 - - # Now compact store - l1.rpc.call('dev-compact-gossip-store') - l1.restart() - - time.sleep(3) # Make sure store is loaded - # We should still see local channels! - chans = l1.rpc.listchannels()['channels'] - assert len(chans) == 2 - - -def test_gossip_store_private_channels(node_factory, bitcoind): - l1, l2 = node_factory.line_graph(2, announce_channels=False) - - # We see this channel, even though it's not announced, because it's local. - wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2) - - l2.stop() - l1.restart() - - # We should still see local channels! - time.sleep(3) # Make sure store is loaded - chans = l1.rpc.listchannels()['channels'] - assert len(chans) == 2 - - # Now compact store - l1.rpc.call('dev-compact-gossip-store') - l1.restart() - - time.sleep(3) # Make sure store is loaded - # We should still see local channels! - chans = l1.rpc.listchannels()['channels'] - assert len(chans) == 2 - - def setup_gossip_store_test(node_factory, bitcoind): - l1, l2, l3 = node_factory.line_graph(3, fundchannel=False) - - # Create channel. - scid23, _ = l2.fundchannel(l3, 10**6) - - # Have that channel announced. - mine_funding_to_announce(bitcoind, [l1, l2, l3]) - # Make sure we've got node_announcements - wait_for(lambda: ['alias' in n for n in l2.rpc.listnodes()['nodes']] == [True, True]) + l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True) # Now, replace the one channel_update, so it's past the node announcements. l2.rpc.setchannel(l3.info['id'], 20, 1000) - # Old base feerate is 1. - wait_for(lambda: sum([c['base_fee_millisatoshi'] for c in l2.rpc.listchannels()['channels']]) == 21) + l3.rpc.setchannel(l2.info['id'], 21, 1001) - # Create another channel, which will stay private. - scid12, _ = l1.fundchannel(l2, 10**6) - - # FIXME: We assume that private announcements are in gossip_store! - l2.wait_channel_active(scid12) - - # Now insert channel_update for previous channel; now they're both past the - # node announcements. - l3.rpc.setchannel(l2.info['id'], feebase=20, feeppm=1000) - wait_for(lambda: [c['base_fee_millisatoshi'] for c in l2.rpc.listchannels(scid23)['channels']] == [20, 20]) + # Wait for it to hit l1's gossip store. + wait_for(lambda: sorted([c['fee_per_millionth'] for c in l1.rpc.listchannels()['channels']]) == [10, 10, 1000, 1001]) - # Replace both (private) updates for scid12. - l1.rpc.setchannel(l2.info['id'], feebase=20, feeppm=1000) - l2.rpc.setchannel(l1.info['id'], feebase=20, feeppm=1000) - wait_for(lambda: [c['base_fee_millisatoshi'] for c in l2.rpc.listchannels(scid12)['channels']] == [20, 20]) - - # Records in store now looks (something) like: - # DELETED: private channel_announcement (scid23) - # DELETED: private channel_update (scid23/0) - # DELETED: private channel_update (scid23/1) - # delete channel (scid23) + # Records in l2's store now looks (something) like: + # channel_announcement (scid12) + # channel_amount + # channel_update (scid12/0) + # channel_update (scid12/1) + # node_announcement (l1) + # node_announcement (l2) # channel_announcement (scid23) # channel_amount # DELETED: channel_update (scid23/0) # DELETED: channel_update (scid23/1) # node_announcement - # node_announcement - # channel_update (scid23) - # private channel_announcement (scid12) - # DELETED: private channel_update (scid12/0) - # DELETED: private channel_update (scid12/1) - # channel_update (scid23) - # private_channel_update (scid12) - # private_channel_update (scid12) + # channel_update (scid23/0) + # channel_update (scid23/1) return l2 @@ -1750,13 +1676,15 @@ def test_gossip_store_compact_on_load(node_factory, bitcoind): l2.restart() # These appear before we're fully started, so will already in log: - line = l2.daemon.is_in_log(r'gossip_store_compact_offline: .* deleted, 9 copied') + # FIXME: this will change! + line = l2.daemon.is_in_log(r'gossip_store_compact_offline: .* deleted, .* copied') m = re.search(r'gossip_store_compact_offline: (.*) deleted', line) # We can have private re-tranmissions, but at minumum we had a deleted private # channel message and two private updates, then two deleted updates. assert int(m.group(1)) >= 5 - assert l2.daemon.is_in_log(r'gossip_store: Read 2/4/2/0 cannounce/cupdate/nannounce/cdelete from store \(0 deleted\) in [0-9]* bytes') + # FIXME: this will change! + assert l2.daemon.is_in_log(r'gossip_store: Read 2/4/[23]/0 cannounce/cupdate/nannounce/cdelete from store \(0 deleted\) in [0-9]* bytes') def test_gossip_announce_invalid_block(node_factory, bitcoind): @@ -2169,35 +2097,6 @@ def test_close_12_block_delay(node_factory, bitcoind): wait_for(lambda: l4.rpc.listchannels(source=l2.info['id'])['channels'] == []) -def test_gossip_private_updates(node_factory, bitcoind): - """Check that private channel updates are properly added and deleted from - the gossip store. - - """ - l1, l2 = node_factory.get_nodes(2) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - scid, _ = l1.fundchannel(l2, 10**6, None, False) - bitcoind.generate_block(5) - - l1.wait_local_channel_active(scid) - l2.wait_local_channel_active(scid) - - l2.rpc.setchannel(l1.info['id'], feebase=11) - wait_for(lambda: sum([c['base_fee_millisatoshi'] for c in l1.rpc.listchannels()['channels']]) == 12) - l2.rpc.setchannel(l1.info['id'], feebase=12) - wait_for(lambda: sum([c['base_fee_millisatoshi'] for c in l1.rpc.listchannels()['channels']]) == 13) - l2.rpc.setchannel(l1.info['id'], feebase=13) - wait_for(lambda: sum([c['base_fee_millisatoshi'] for c in l1.rpc.listchannels()['channels']]) == 14) - l2.rpc.setchannel(l1.info['id'], feebase=14) - wait_for(lambda: sum([c['base_fee_millisatoshi'] for c in l1.rpc.listchannels()['channels']]) == 15) - l2.rpc.setchannel(l1.info['id'], feebase=15) - wait_for(lambda: sum([c['base_fee_millisatoshi'] for c in l1.rpc.listchannels()['channels']]) == 16) - l1.restart() - - wait_for(lambda: l1.daemon.is_in_log(r'gossip_store_compact_offline: 5 deleted, 3 copied')) - - def test_gossip_not_dying(node_factory, bitcoind): l1 = node_factory.get_node() l2, l3 = node_factory.line_graph(2, wait_for_announce=True) diff --git a/tests/test_opening.py b/tests/test_opening.py index e8926e3596a8..40f56710b04d 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1835,7 +1835,8 @@ def test_zeroconf_forward(node_factory, bitcoind): # And now try the other way around: zeroconf channel first # followed by a public one. - wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 4) + # Make sure it l3 sees l1->l2 + wait_for(lambda: len(l3.rpc.listchannels(source=l1.info['id'])['channels']) == 1) # Make sure all htlcs completely settled! wait_for(lambda: (p['htlcs'] == [] for p in l2.rpc.listpeerchannels()['channels'])) @@ -2011,7 +2012,7 @@ def test_scid_alias_private(node_factory, bitcoind): scid12 = chan['short_channel_id'] # Make sure it sees both sides of private channel in gossmap! - wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 4) + wait_for(lambda: 'remote' in only_one(l3.rpc.listpeerchannels(l2.info['id'])['channels'])['updates']) # BOLT #2: # - if `channel_type` has `option_scid_alias` set: diff --git a/tests/test_pay.py b/tests/test_pay.py index 0892b88b951b..66ae923f6841 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -259,8 +259,6 @@ def test_pay_disconnect(node_factory, bitcoind): inv = l2.rpc.invoice(123000, 'test_pay_disconnect', 'description') rhash = inv['payment_hash'] - wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True, True]) - # Can't use `pay` since that'd notice that we can't route, due to disabling channel_update route = l1.rpc.getroute(l2.info['id'], 123000, 1)["route"] @@ -2045,7 +2043,8 @@ def channel_get_config(scid): assert channel['minimum_htlc_out_msat'] == 17 assert channel['maximum_htlc_out_msat'] == 133337 - # wait for gossip and check if l1 sees new fees in listchannels + # wait for gossip and check if l1 sees new fees in listchannels after mining + bitcoind.generate_block(5) wait_for(lambda: [c['base_fee_millisatoshi'] for c in l1.rpc.listchannels(scid)['channels']] == [DEF_BASE, 1337]) wait_for(lambda: [c['fee_per_millionth'] for c in l1.rpc.listchannels(scid)['channels']] == [DEF_PPM, 137]) wait_for(lambda: [c['htlc_minimum_msat'] for c in l1.rpc.listchannels(scid)['channels']] == [0, 17]) @@ -2448,10 +2447,19 @@ def test_setchannel_all(node_factory, bitcoind): # now try to set all (two) channels using wildcard syntax result = l1.rpc.setchannel("all", 0xDEAD, 0xBEEF, 0xBAD, 0xCAFE) - wait_for(lambda: [c['base_fee_millisatoshi'] for c in l1.rpc.listchannels(scid2)['channels']] == [DEF_BASE, 0xDEAD]) - wait_for(lambda: [c['fee_per_millionth'] for c in l1.rpc.listchannels(scid2)['channels']] == [DEF_PPM, 0xBEEF]) - wait_for(lambda: [c['base_fee_millisatoshi'] for c in l1.rpc.listchannels(scid3)['channels']] == [0xDEAD, DEF_BASE]) - wait_for(lambda: [c['fee_per_millionth'] for c in l1.rpc.listchannels(scid3)['channels']] == [0xBEEF, DEF_PPM]) + channel_after = {"htlc_minimum_msat": Millisatoshi(0xBAD), + "htlc_maximum_msat": Millisatoshi(0xCAFE), + "cltv_expiry_delta": 6, + "fee_base_msat": Millisatoshi(0xDEAD), + "fee_proportional_millionths": 0xBEEF} + + # We should see these updates immediately. + assert only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['updates']['local'] == channel_after + assert only_one(l1.rpc.listpeerchannels(l3.info['id'])['channels'])['updates']['local'] == channel_after + + # Peer should see them soon (once we sent) + wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['updates']['remote'] == channel_after) + wait_for(lambda: only_one(l3.rpc.listpeerchannels()['channels'])['updates']['remote'] == channel_after) # Don't assume order! assert len(result['channels']) == 2 diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 5feaa780e497..3c803a112c2d 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -4,6 +4,7 @@ from hashlib import sha256 from pyln.client import RpcError, Millisatoshi from pyln.proto import Invoice +from pyln.testing.utils import FUNDAMOUNT from utils import ( only_one, sync_blockheight, TIMEOUT, wait_for, TEST_NETWORK, expected_peer_features, expected_node_features, @@ -1874,18 +1875,25 @@ def test_hook_crash(node_factory, executor, bitcoind): l1 = node_factory.get_node() nodes = [node_factory.get_node() for _ in perm] + # For simplicity, give us N UTXOs to spend. + addr = l1.rpc.newaddr('p2tr')['p2tr'] + for n in nodes: + bitcoind.rpc.sendtoaddress(addr, (FUNDAMOUNT + 5000) / 10**8) + bitcoind.generate_block(1, wait_for_mempool=len(nodes)) + sync_blockheight(bitcoind, [l1]) + # Start them in any order and we should still always end up with each # plugin being called and ultimately the `pay` call should succeed: for plugins, n in zip(perm, nodes): for p in plugins: n.rpc.plugin_start(p) - l1.openchannel(n, 10**6, confirm=False, wait_for_announce=False) + l1.connect(n) + l1.rpc.fundchannel(n.info['id'], FUNDAMOUNT) - # Mine final openchannel tx first. - sync_blockheight(bitcoind, [l1] + nodes) - mine_funding_to_announce(bitcoind, [l1] + nodes, wait_for_mempool=1) + # Mine txs first. + mine_funding_to_announce(bitcoind, [l1] + nodes, num_blocks=6, wait_for_mempool=len(nodes)) - wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2 * len(perm)) + wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2 * len(nodes)) # Start an RPC call that should error once the plugin crashes. f1 = executor.submit(nodes[0].rpc.hold_rpc_call)