From c4f259d179478b4605c2f58a1906e66db4ae5bc5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 5 Aug 2024 16:17:39 +0930 Subject: [PATCH] lightningd: --experimental-gossip-status option. This activates the logic, by enabling the feature bit. Changelog-EXPERIMENTAL: Protocol: `gossip_status` support (https://github.com/lightning/bolts/pull/1186) Signed-off-by: Rusty Russell --- doc/lightningd-config.5.md | 4 +++ lightningd/options.c | 12 +++++++ tests/test_gossip.py | 72 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index b1545fd5db63..12ae8ce92298 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -799,7 +799,11 @@ protocol to update channel types. At the moment, we only support setting `option_static_remotekey` to ancient channels. The peer must also support this option. +* **experimental-gossip-status** + Specifying this option means we send (and answer) `gossip_status`: a +simply protocol to catch peers which are missing the bulk of gossip, as +described in ([bolt][bolt] #1186). BUGS ---- diff --git a/lightningd/options.c b/lightningd/options.c index 2954ffeae016..3cb2f363b1dc 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -1313,6 +1313,14 @@ static char *opt_set_anchor_zero_fee_htlc_tx(struct lightningd *ld) return NULL; } +static char *opt_set_gossip_status(struct lightningd *ld) +{ + feature_set_or(ld->our_features, + take(feature_set_for_feature(NULL, + OPTIONAL_FEATURE(OPT_GOSSIP_STATUS)))); + return NULL; +} + static char *opt_set_offers(struct lightningd *ld) { ld->config.exp_offers = true; @@ -1516,6 +1524,10 @@ static void register_opts(struct lightningd *ld) opt_register_early_noarg("--experimental-anchors", opt_set_anchor_zero_fee_htlc_tx, ld, opt_hidden); + opt_register_early_noarg("--experimental-gossip-status", + opt_set_gossip_status, ld, + "EXPERIMENTAL: Send and process gossip_status messages for gossip bootstrap"); + clnopt_witharg("--announce-addr-dns", OPT_EARLY|OPT_SHOWBOOL, opt_set_bool_arg, opt_show_bool, &ld->announce_dns, diff --git a/tests/test_gossip.py b/tests/test_gossip.py index e294939adc7b..d79713b2ad0f 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -2207,3 +2207,75 @@ def test_generate_gossip_store(node_factory): expected = sorted(expected, key=lambda x: x['source'] + x['destination']) assert lchans == expected + + +def test_gossip_status(node_factory, chainparams): + # Since we respond if we have > 100 more than them, we need a big gossmap. + l1 = node_factory.get_node(start=False) + chans = [GenChannel(0, i) for i in range(1, 102)] + gsfile, nodemap = generate_gossip_store(chans) + shutil.copy(gsfile.name, os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store')) + + l1.daemon.opts['experimental-gossip-status'] = None + l1.start() + + assert len(l1.rpc.listchannels()['channels']) == 101 * 2 + + # If I say I have 1/102/1, you won't give me anything. + out = subprocess.run(['devtools/gossipwith', + '--no-gossip', + '--hex', + '--network={}'.format(TEST_NETWORK), + '--timeout-after={}'.format(int(math.sqrt(TIMEOUT) + 1)), + '{}@localhost:{}'.format(l1.info['id'], l1.port), + # BOLT-gossip_status #7: + # 1. type: 267 (`gossip_status`) + # 2. data: + # * [`chain_hash`:`chain_hash`] + # * [`bigsize`:`num_channel_announcements`] + # * [`bigsize`:`num_channel_updates`] + # * [`bigsize`:`num_node_announcements`] + '763B' + chainparams['chain_hash'] + '016601'], + check=True, + timeout=TIMEOUT, stdout=subprocess.PIPE).stdout.split() + + # No channel_announcments, channel_updates or node_announcements + assert [m for m in out if m.startswith(b'0100') or m.startswith(b'0101') or m.startswith(b'0102')] == [] + + # If I say I have 0 channel_announcments, you spew gossip... + out = subprocess.run(['devtools/gossipwith', + '--no-gossip', + '--hex', + '--network={}'.format(TEST_NETWORK), + '--timeout-after={}'.format(int(math.sqrt(TIMEOUT) + 1)), + '{}@localhost:{}'.format(l1.info['id'], l1.port), + # BOLT-gossip_status #7: + # 1. type: 267 (`gossip_status`) + # 2. data: + # * [`chain_hash`:`chain_hash`] + # * [`bigsize`:`num_channel_announcements`] + # * [`bigsize`:`num_channel_updates`] + # * [`bigsize`:`num_node_announcements`] + '763B' + chainparams['chain_hash'] + '00CA01'], + check=True, + timeout=TIMEOUT, stdout=subprocess.PIPE).stdout.split() + assert len([m for m in out if m.startswith(b'0100') or m.startswith(b'0101') or m.startswith(b'0102')]) == 303 + + # If I say I have 101 channel_updates, you spew gossip... + out = subprocess.run(['devtools/gossipwith', + '--no-gossip', + '--hex', + '--network={}'.format(TEST_NETWORK), + '--timeout-after={}'.format(int(math.sqrt(TIMEOUT) + 1)), + '{}@localhost:{}'.format(l1.info['id'], l1.port), + # BOLT-gossip_status #7: + # 1. type: 267 (`gossip_status`) + # 2. data: + # * [`chain_hash`:`chain_hash`] + # * [`bigsize`:`num_channel_announcements`] + # * [`bigsize`:`num_channel_updates`] + # * [`bigsize`:`num_node_announcements`] + '763B' + chainparams['chain_hash'] + '656501'], + check=True, + timeout=TIMEOUT, stdout=subprocess.PIPE).stdout.split() + assert len([m for m in out if m.startswith(b'0100') or m.startswith(b'0101') or m.startswith(b'0102')]) == 303