pytest: update "real gossip map" tests to a recent snapshot.
What changed, and why it matters
This commit only updates test data and test expectations. It replaces old Lightning Network gossip snapshots with newer ones, adjusts test numbers to match the new snapshot, and removes one test that depended on the old topology. There is no change to production code, no bug fix, and no security-relevant behavior.
No security action needed. Treat as routine test maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit updates integration tests in tests/test_askrene.py and tests/test_xpay.py to use a fresh real-world gossip snapshot (2026-02-03 instead of 2024-09-22). It deletes the old compressed gossip store and node map, adds the new ones, updates node index mappings (3301 -> 2134), refreshes expected route counts/fees, refactors bad-node lists into a shared constant, raises a test payment amount to get more interesting failures, and removes test_xpay_maxfee because it relied on the specific old topology. No C/lightningd source code is modified.
Changed components
tests/test_askrene.pytests/test_xpay.pytests/data/gossip-store-2024-09-22-node-map.xztests/data/gossip-store-2024-09-22.compressedtests/data/gossip-store-2026-02-03-node-map.xztests/data/gossip-store-2026-02-03.compressedInspect captured patch +40 / −110
diff --git a/tests/data/gossip-store-2024-09-22-node-map.xz b/tests/data/gossip-store-2024-09-22-node-map.xz
deleted file mode 100644
index a12cf619..00000000
Binary files a/tests/data/gossip-store-2024-09-22-node-map.xz and /dev/null differ
diff --git a/tests/data/gossip-store-2024-09-22.compressed b/tests/data/gossip-store-2024-09-22.compressed
deleted file mode 100644
index 3f955dd0..00000000
Binary files a/tests/data/gossip-store-2024-09-22.compressed and /dev/null differ
diff --git a/tests/data/gossip-store-2026-02-03-node-map.xz b/tests/data/gossip-store-2026-02-03-node-map.xz
new file mode 100644
index 00000000..80707aa7
Binary files /dev/null and b/tests/data/gossip-store-2026-02-03-node-map.xz differ
diff --git a/tests/data/gossip-store-2026-02-03.compressed b/tests/data/gossip-store-2026-02-03.compressed
new file mode 100644
index 00000000..fe641c1d
Binary files /dev/null and b/tests/data/gossip-store-2026-02-03.compressed differ
diff --git a/tests/test_askrene.py b/tests/test_askrene.py
index 15bb02b3..ae1c2771 100644
--- a/tests/test_askrene.py
+++ b/tests/test_askrene.py
@@ -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}")
diff --git a/tests/test_xpay.py b/tests/test_xpay.py
index 5fe02275..4fb9381a 100644
--- a/tests/test_xpay.py
+++ b/tests/test_xpay.py
@@ -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)
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.