Skip to content

Commit

Permalink
pytest: fix tests in assumption that listchannels will no longer show…
Browse files Browse the repository at this point in the history
… private gossip.

Some can only be changed once that is true, but some can be removed/amended already.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Nov 15, 2023
1 parent f72eed0 commit 4d3b489
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 132 deletions.
135 changes: 17 additions & 118 deletions tests/test_gossip.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions tests/test_opening.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']))
Expand Down Expand Up @@ -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:
Expand Down
22 changes: 15 additions & 7 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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
Expand Down
18 changes: 13 additions & 5 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 4d3b489

Please sign in to comment.