pytest: update "real gossip map" tests to a recent snapshot.

We delete the test_xpay_maxfee test which required the specific
topology.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2026-02-04 22:08:36 +10:30
parent 95b63e4738
commit 96adac48ab
6 changed files with 40 additions and 110 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -1431,17 +1431,27 @@ def test_min_htlc_after_excess(node_factory, bitcoind):
final_cltv=10)
# These were obviously having a bad day at the time of the snapshot:
canned_gossmap_badnodes = {
19: "We could not find a usable set of paths. The shortest path is 103x1x0->0x2134x0->0x333x988->19x333x16169, but 0x2134x0/0 exceeds htlc_maximum_msat ~1000448msat",
53: "We could not find a usable set of paths. The destination has disabled 177 of 177 channels, leaving capacity only 0msat of 4003677000msat.",
69: "We could not find a usable set of paths. The destination has disabled 151 of 151 channels, leaving capacity only 0msat of 9092303000msat.",
72: "We could not find a usable set of paths. The destination has disabled 146 of 146 channels, leaving capacity only 0msat of 1996000000msat.",
86: "We could not find a usable set of paths. The destination has disabled 131 of 131 channels, leaving capacity only 0msat of 162000000msat.",
}
@pytest.mark.slow_test
def test_real_data(node_factory, bitcoind):
# Route from Rusty's node to the top nodes
# From tests/data/gossip-store-2024-09-22-node-map.xz:
# Me: 3301:024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605:BLUEIRON
# So we make l2 node 3301.
# From tests/data/gossip-store-2026-02-03-node-map.xz:
# Me: 2134:024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605:BLUEIRON
# So we make l2 node 2134.
outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-')
nodeids = subprocess.check_output(['devtools/gossmap-compress',
'decompress',
'--node-map=3301=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2024-09-22.compressed',
'--node-map=2134=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2026-02-03.compressed',
outfile.name]).decode('utf-8').splitlines()
# This is in msat, but is also the size of channel we create.
@@ -1457,34 +1467,21 @@ def test_real_data(node_factory, bitcoind):
'askrene-timeout': TIMEOUT},
{'allow_warning': True}])
# These were obviously having a bad day at the time of the snapshot:
badnodes = {
# 62:03dbe3fedd4f6e7f7020c69e6d01453d5a69f9faa1382901cf3028f1e997ef2814:BTC_👽👽👽👽👽👽
62: " marked disabled by gossip message",
# This one has 151 channels, with peers each only connected to it. An island!
# 76:0298906458987af756e2a43b208c03499c4d2bde630d4868dda0ea6a184f87c62a:0298906458987af756e2
76: "There is no connection between source and destination at all",
# 80:02d246c519845e7b23b02684d64ca23b750958e0307f9519849ee2535e3637999a:SLIMYRAGE-
80: " marked disabled by gossip message",
# 97:034a5fdb2df3ce1bfd2c2aca205ce9cfeef1a5f4af21b0b5e81c453080c30d7683:🚶LightningTransact
97: r"We could not find a usable set of paths\. The shortest path is 103x1x0->0x3301x1646->0x1281x2323->97x1281x33241, but 97x1281x33241/1 isn't big enough to carry 100000000msat\.",
}
# CI, it's slow.
if SLOW_MACHINE:
limit = 25
expected = (6, 25, 1568821, 144649, 91)
expected = (9, 24, 1935647, 219066, 89)
else:
limit = 100
expected = (9, 96, 6565466, 668476, 90)
expected = (11, 95, 8026484, 925406, 89)
fees = {}
for n in range(0, limit):
# 0.5% is the norm
MAX_FEE = AMOUNT // 200
if n in badnodes:
with pytest.raises(RpcError, match=badnodes[n]):
if n in canned_gossmap_badnodes:
with pytest.raises(RpcError, match=canned_gossmap_badnodes[n]):
l1.rpc.getroutes(source=l1.info['id'],
destination=nodeids[n],
amount_msat=AMOUNT,
@@ -1552,14 +1549,14 @@ def test_real_data(node_factory, bitcoind):
@pytest.mark.slow_test
def test_real_biases(node_factory, bitcoind):
# Route from Rusty's node to the top 100.
# From tests/data/gossip-store-2024-09-22-node-map.xz:
# Me: 3301:024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605:BLUEIRON
# So we make l2 node 3301.
# From tests/data/gossip-store-2026-02-03-node-map.xz:
# Me: 2134:024b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605:BLUEIRON
# So we make l2 node 2134.
outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-')
nodeids = subprocess.check_output(['devtools/gossmap-compress',
'decompress',
'--node-map=3301=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2024-09-22.compressed',
'--node-map=2134=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2026-02-03.compressed',
outfile.name]).decode('utf-8').splitlines()
# This is in msat, but is also the size of channel we create.
@@ -1573,26 +1570,13 @@ def test_real_biases(node_factory, bitcoind):
'dev-throttle-gossip': None},
{'allow_warning': True}])
# These were obviously having a bad day at the time of the snapshot:
badnodes = {
# 62:03dbe3fedd4f6e7f7020c69e6d01453d5a69f9faa1382901cf3028f1e997ef2814:BTC_👽👽👽👽👽👽
62: " marked disabled by gossip message",
# This one has 151 channels, with peers each only connected to it. An island!
# 76:0298906458987af756e2a43b208c03499c4d2bde630d4868dda0ea6a184f87c62a:0298906458987af756e2
76: "There is no connection between source and destination at all",
# 80:02d246c519845e7b23b02684d64ca23b750958e0307f9519849ee2535e3637999a:SLIMYRAGE-
80: " marked disabled by gossip message",
# 97:034a5fdb2df3ce1bfd2c2aca205ce9cfeef1a5f4af21b0b5e81c453080c30d7683:🚶LightningTransact
97: r"We could not find a usable set of paths\. The shortest path is 103x1x0->0x3301x1646->0x1281x2323->97x1281x33241, but 97x1281x33241/1 isn't big enough to carry 100000000msat\.",
}
# CI, it's slow.
if SLOW_MACHINE:
limit = 25
expected = ({1: 6, 2: 6, 4: 7, 8: 12, 16: 14, 32: 19, 64: 25, 100: 25}, 0)
expected = ({1: 6, 2: 7, 4: 12, 8: 13, 16: 18, 32: 23, 64: 24, 100: 24}, 0)
else:
limit = 100
expected = ({1: 22, 2: 25, 4: 36, 8: 53, 16: 69, 32: 80, 64: 96, 100: 96}, 0)
expected = ({1: 26, 2: 33, 4: 48, 8: 57, 16: 77, 32: 90, 64: 95, 100: 95}, 0)
l1.rpc.askrene_create_layer('biases')
num_changed = {}
@@ -1604,7 +1588,7 @@ def test_real_biases(node_factory, bitcoind):
# 0.5% is the norm
MAX_FEE = AMOUNT // 200
if n in badnodes:
if n in canned_gossmap_badnodes:
continue
route = l1.rpc.getroutes(source=l1.info['id'],
@@ -1638,13 +1622,6 @@ def test_real_biases(node_factory, bitcoind):
amount_after = amount_through_chan(chan, route2['routes'])
if amount_after < amount_before:
num_changed[bias] += 1
else:
# We bias -4 against 83x88x31908/0 going to node 83, and this is violated.
# Both routes contain three paths, all via 83x88x31908/0.
# The first amounts 49490584, 1018832, 49490584,
# The second amounts 25254708, 25254708, 49490584,
# Due to fees and rounding, we actually spend 1msat more on the second case!
assert (n, bias, chan) == (83, 4, '83x88x31908/0')
# Undo bias
l1.rpc.askrene_bias_channel(layer='biases', short_channel_id_dir=chan, bias=0)
@@ -1677,8 +1654,8 @@ def test_askrene_fake_channeld(node_factory, bitcoind):
outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-')
nodeids = subprocess.check_output(['devtools/gossmap-compress',
'decompress',
'--node-map=3301=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2024-09-22.compressed',
'--node-map=2134=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2026-02-03.compressed',
outfile.name]).decode('utf-8').splitlines()
AMOUNT = 100_000_000
@@ -1705,7 +1682,7 @@ def test_askrene_fake_channeld(node_factory, bitcoind):
l1.rpc.askrene_create_layer('test_askrene_fake_channeld')
for n in range(0, 100):
if n in (62, 76, 80, 97):
if n in canned_gossmap_badnodes:
continue
print(f"PAYING Node #{n}")

View File

@@ -213,6 +213,10 @@ def test_xpay_selfpay(node_factory):
l1.rpc.xpay(b12)
# These were obviously having a bad day at the time of the snapshot:
canned_gossmap_badnodes = [19, 53, 69, 72, 86]
@pytest.mark.slow_test
@unittest.skipIf(TEST_NETWORK != 'regtest', '29-way split for node 17 is too dusty on elements')
@pytest.mark.parametrize("slow_mode", [False, True])
@@ -220,10 +224,11 @@ def test_xpay_fake_channeld(node_factory, bitcoind, chainparams, slow_mode):
outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-')
nodeids = subprocess.check_output(['devtools/gossmap-compress',
'decompress',
'--node-map=3301=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2024-09-22.compressed',
'--node-map=2134=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2026-02-03.compressed',
outfile.name]).decode('utf-8').splitlines()
AMOUNT = 100_000_000
# 100,000sat gave no failures at all, which is not very interesting!
AMOUNT = 500_000_000
# l2 will warn l1 about its invalid gossip: ignore.
# We throttle l1's gossip to avoid massive log spam.
@@ -254,7 +259,7 @@ def test_xpay_fake_channeld(node_factory, bitcoind, chainparams, slow_mode):
l1.rpc.setconfig('xpay-slow-mode', slow_mode)
failed_parts = []
for n in range(0, 100):
if n in (62, 76, 80, 97):
if n in canned_gossmap_badnodes:
continue
print(f"PAYING Node #{n}")
@@ -289,7 +294,7 @@ def test_xpay_fake_channeld(node_factory, bitcoind, chainparams, slow_mode):
failed_parts_retry = []
for n in range(0, 100):
if n in (62, 76, 80, 97):
if n in canned_gossmap_badnodes:
continue
print(f"PAYING Node #{n}")
@@ -537,58 +542,6 @@ def test_xpay_preapprove(node_factory):
l1.rpc.xpay(inv)
@unittest.skipIf(TEST_NETWORK != 'regtest', 'too dusty on elements')
@pytest.mark.slow_test
def test_xpay_maxfee(node_factory, bitcoind, chainparams):
"""Test which shows that we don't excees maxfee"""
outfile = tempfile.NamedTemporaryFile(prefix='gossip-store-')
subprocess.check_output(['devtools/gossmap-compress',
'decompress',
'--node-map=3301=033845802d25b4e074ccfd7cd8b339a41dc75bf9978a034800444b51d42b07799a',
'tests/data/gossip-store-2024-09-22.compressed',
outfile.name]).decode('utf-8').splitlines()
AMOUNT = 100_000_000
# l2 will warn l1 about its invalid gossip: ignore.
# We throttle l1's gossip to avoid massive log spam.
l1, l2 = node_factory.line_graph(2,
# This is in sats, so 1000x amount we send.
fundamount=AMOUNT,
opts=[{'gossip_store_file': outfile.name,
'subdaemon': 'channeld:../tests/plugins/channeld_fakenet',
'allow_warning': True,
'dev-throttle-gossip': None,
# This can be more than 10 seconds under CI!
'askrene-timeout': 60},
{'allow_bad_gossip': True}])
# l1 needs to know l2's shaseed for the channel so it can make revocations
hsmfile = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, "hsm_secret")
# Needs peer node id and channel dbid (1, it's the first channel), prints out:
# "shaseed: xxxxxxx\n"
shaseed = subprocess.check_output(["tools/lightning-hsmtool", "dumpcommitments", l1.info['id'], "1", "0", hsmfile]).decode('utf-8').strip().partition(": ")[2]
l1.rpc.dev_peer_shachain(l2.info['id'], shaseed)
# This one triggers the bug!
n = 59
maxfee = 57966
preimage_hex = bytes([n + 100]).hex() + '00' * 31
hash_hex = sha256(bytes.fromhex(preimage_hex)).hexdigest()
inv = subprocess.check_output(["devtools/bolt11-cli",
"encode",
n.to_bytes(length=8, byteorder=sys.byteorder).hex() + '01' * 24,
f"currency={chainparams['bip173_prefix']}",
f"p={hash_hex}",
"9=020000", # option_basic_mpp
f"s={'00' * 32}",
f"d=Paying node {n} with maxfee",
f"amount={AMOUNT}msat"]).decode('utf-8').strip()
ret = l1.rpc.xpay(invstring=inv, maxfee=maxfee)
fee = ret['amount_sent_msat'] - ret['amount_msat']
assert fee <= maxfee
def test_xpay_maxdelay(node_factory):
l1, l2 = node_factory.line_graph(2, wait_for_announce=True)