From 70c4ac6d74aff01cc80808c4eb051977f37d6bc2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 16 Sep 2019 14:43:15 +0930 Subject: [PATCH] gossipd: suppress our own too-close node_announcement messages. Never make them less than gossip_min_interval apart. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 37 +++++++++++++++++++++++++++++-------- tests/test_gossip.py | 5 +++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index cab92c54e..9fde64133 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -151,6 +151,9 @@ struct daemon { /* Channels we've heard about, but don't know. */ struct short_channel_id *unknown_scids; + + /* Timer until we can send a new node_announcement */ + struct oneshot *node_announce_timer; }; /*~ How gossipy do we ask a peer to be? */ @@ -569,22 +572,39 @@ static void update_own_node_announcement(struct daemon *daemon) u8 *msg, *nannounce, *err; struct node *self = get_node(daemon->rstate, &daemon->id); - /* BOLT #7: - * - * The origin node: - * - MUST set `timestamp` to be greater than that of any previous - * `node_announcement` it has previously created. - */ - if (self && self->bcast.index && timestamp <= self->bcast.timestamp) - timestamp = self->bcast.timestamp + 1; + /* Discard existing timer. */ + daemon->node_announce_timer = tal_free(daemon->node_announce_timer); /* Make unsigned announcement. */ nannounce = create_node_announcement(tmpctx, daemon, NULL, timestamp); /* If it's the same as the previous, nothing to do. */ if (self && self->bcast.index) { + u32 next; + if (!nannounce_different(daemon->rstate->gs, self, nannounce)) return; + + /* BOLT #7: + * + * The origin node: + * - MUST set `timestamp` to be greater than that of any + * previous `node_announcement` it has previously created. + */ + /* We do better: never send them within more than 5 minutes. */ + next = self->bcast.timestamp + daemon->gossip_min_interval; + + if (timestamp < next) { + status_debug("node_announcement: delaying %u secs", + next - timestamp); + daemon->node_announce_timer + = new_reltimer(&daemon->timers, + daemon, + time_from_sec(next - timestamp), + update_own_node_announcement, + daemon); + return; + } } /* Ask hsmd to sign it (synchronous) */ @@ -3447,6 +3467,7 @@ int main(int argc, char *argv[]) list_head_init(&daemon->peers); daemon->unknown_scids = tal_arr(daemon, struct short_channel_id, 0); daemon->gossip_missing = NULL; + daemon->node_announce_timer = NULL; /* Note the use of time_mono() here. That's a monotonic clock, which * is really useful: it can only be used to measure relative events diff --git a/tests/test_gossip.py b/tests/test_gossip.py index c3a1a32a3..b7aecb5b9 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -967,6 +967,8 @@ def test_node_reannounce(node_factory, bitcoind): l1.stop() l1.daemon.opts['alias'] = 'SENIORBEAM' + # It won't update within 5 seconds, so sleep. + time.sleep(5) l1.start() # Wait for l1 to send us its own node_announcement. @@ -984,6 +986,9 @@ def test_node_reannounce(node_factory, bitcoind): # l1 should retransmit it exactly the same (no timestamp change!) l2.daemon.wait_for_log(r'{}.*\[IN\] {}'.format(l1.info['id'], nannouncement)) + # Won't have queued up another one, either. + assert not l1.daemon.is_in_log('node_announcement: delaying') + def test_gossipwith(node_factory): l1, l2 = node_factory.line_graph(2, wait_for_announce=True)