From 53dd6cd44a7590602f70d4d2695e99e8b34db343 Mon Sep 17 00:00:00 2001 From: Alex Myers Date: Tue, 8 Aug 2023 16:46:59 -0500 Subject: [PATCH] pytest: test gossip_store loading of spam node announcement before channel update --- tests/test_gossip.py | 94 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index cc87b4100..b20cc2a31 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -2383,3 +2383,97 @@ def test_dump_own_gossip(node_factory): # We should get exactly what we expected. assert expect == [] + + +@pytest.mark.xfail +@pytest.mark.developer("needs --dev-gossip-time") +@unittest.skipIf( + TEST_NETWORK != 'regtest', + "Channel announcement contains genesis hash, receiving node discards on mismatch" +) +def test_read_spam_nannounce(node_factory, bitcoind): + """issue #6531 lead to a node announcement not being deleted from + the gossip_store.""" + """broadcastable and spam node announcements should be loaded properly when + reading the gossip_store - even when they are both pending a channel + update.""" + opts = {'dev-gossip-time': 1691773540} + l1 = node_factory.get_node(start=False, opts=opts) + canned_store = ( + "0c" # Gossip store version byte + "0000" # length flags + "01b0" # length + "d163af25" # checksum + "64d66a3a" # timestamp + # Channel announcement + "010000335733f5942df5d950eb8766dee3a9d6626922844ed6ae7a110dd7e7edc32e3f6f3d9ac5cdea23ce25bb8dbf761fd3d5fc56c05b6856316d12e9d32ca0f08c69ca0306fe716e7b5151317d6440b7373d9fbc646ead48f2163f2b6d511afe6a79c75551c2620fc80974f2f864329d9778a08cdfbc9f2c9c1344c432702c66807cfb4db69b80fae8c33c70143d948b36614d620891bee2df99c86bc62207c17e3b9186214c0ccff2ded5598accc90eb1d5b2f7a83cd7f68d712ea047d8019f343063b0a236356a387146f58fa832ddc13c4714522cbb503f5f3ca8fcec6602be2438ad3f98fa0ceed58fe3a066d385fcacd98c704b2a8e98a3e20bf76b35b736000006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0000670000010000022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d029053521d6ea7a52cdd55f733d0fb2d077c0373b0053b5b810d927244061b757302d6063d022691b2490ab454dee73a57c6ff5d308352b461ece69f3c284f2c2412" + # Channel Amount + "0000000a911183f600000000" + "100500000000000f4240" + # broadcastable node announcement (rgb=000001) + "0000009533d9cf8c64d66a44" + "010108f4e25debdd74d0f52b7f1da5dbd82f429d057f48e3d2ed49fcc65cfe3e185c086c1a83d8f3bb15dc0cc852d80390c24cd1fe6d288b91eb55cf98c4a9baf7c0000788a0000a0269a264d66a44022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d5900000153494c454e544152544953542d3536392d67303030643963302d6d6f646465640000" + # Rate-limited node announcment (rgb=000002) + "2000009519aa897a64d66a49" + "0101685f67556cd0a87e04c6d1e9daa4e31dcf14f881d6f1231b1bee8adf6666977b6b9baa497e91d2b6daae726cde69e3faf924d9c95d0ca6b374d6693d4fc0d648000788a0000a0269a264d66a49022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d5900000253494c454e544152544953542d3536392d67303030643963302d6d6f646465640000" + # Channel Update + "0000008a0234021c64d66a61" + "010242ce9d9e79f939399ea1291c04fffcafdfa911246464a4b48c16b7b816dd57b4168562a6c519eb31c37718b68bdfc6345d7c2db663b8b04a3558ce7736c5b61706226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000067000001000064d66a6101000006000000000000000000000015000003e8000000003b023380" + # Channel Update + "0000008acd55fcb264d66a61" + "01023f5dd1f69f675a71d2a7a34956b26f12c4fe9ee287a8449a3eb7b756c583e3bb1334a8eb7c3e148d0f43e08b95c50017ba62da9a7843fe4850a3cb3c74dc5e2c06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000067000001000064d66a6101010006000000000000000000000015000003e8000000003b023380" + ) + with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), 'wb') as f: + f.write(bytearray.fromhex(canned_store)) + + bitcoind.generate_block(1) + tx = bitcoind.rpc.createrawtransaction( + [], + [ + # Fundrawtransaction will fill in the first output with the change + {"bcrt1qpd7nwe3jrt07st89uy82nn2xrmqtxyzqpty5ygt6w546lf6n0wcskswjvh": 0.01000000} + ] + ) + tx = bitcoind.rpc.fundrawtransaction(tx, {'changePosition': 0})['hex'] + tx = bitcoind.rpc.signrawtransactionwithwallet(tx)['hex'] + txid = bitcoind.rpc.sendrawtransaction(tx) + wait_for(lambda: txid in bitcoind.rpc.getrawmempool()) + bitcoind.generate_block(6) + l1.start() + # retrieves node info originating from the spam announcement + node_info = l1.rpc.listnodes('022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59') + assert only_one(node_info['nodes'])['color'] == '000002' + + out = subprocess.run(['devtools/gossipwith', + '--initial-sync', + '--timeout-after={}'.format(int(math.sqrt(TIMEOUT) + 1)), + '--hex', + '{}@localhost:{}'.format(l1.info['id'], l1.port)], + check=True, + timeout=TIMEOUT, stdout=subprocess.PIPE).stdout.decode() + + received_broadcastable = False + received_spam = False + for message in out.splitlines(): + gos = subprocess.run(['devtools/decodemsg', message], check=True, + timeout=TIMEOUT, + stdout=subprocess.PIPE).stdout.decode() + + for line in gos.splitlines(): + if 'rgb_color=[000001]' in line: + received_broadcastable = True + if 'rgb_color=[000002]' in line: + received_spam = True + + assert received_broadcastable + assert not received_spam + # Send a new node announcement. It should replace both. + subprocess.run(['devtools/gossipwith', + '--max-messages=0', + '{}@localhost:{}'.format(l1.info['id'], l1.port), + # color=000003 + '0101273fd2c58deb4c3bd98610079657219a5c8291d6a85c3607eae895f25e08babd6e45edd1e62f719b20526ed1c8fc3c7d9e7e3fafa4f24e4cb64872d041a13503000788a0000a0269a264d66a4e022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d5900000353494c454e544152544953542d3536392d67303030643963302d6d6f646465640000'], + check=True, timeout=TIMEOUT) + l1.daemon.wait_for_log('Received node_announcement') + l1.restart() + assert not l1.daemon.is_in_log('BROKEN')