From dbe8ac3b221c6e53625836cb3ddecec36e5bcd90 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 11 Aug 2023 12:35:49 +0930 Subject: [PATCH] gossipd: reduce gossip self-advertizement if we have many peers/channels. dump_our_gossip() is mainly useful for propagating our gossip when we are poorly connected, not when we have many peers. @whitslack reported excessive memory use queueing messages on a large node, so we limit it beyond the first 5 peers, to 5 channels each. This assumes we have ~ the same number of peers as channels, which is probably reasonable. In the long term, we should move this to connectd, which is properly equipped to trickle out these messages. Signed-off-by: Rusty Russell Fixes: #6540 --- gossipd/gossipd.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index c0b708442..554a82b28 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -419,6 +419,9 @@ update_node_annoucement: maybe_send_own_node_announce(daemon, false); } +/* Statistically, how many peers to we tell about each channel? */ +#define GOSSIP_SPAM_REDUNDANCY 5 + /* BOLT #7: * - if the `gossip_queries` feature is negotiated: * - MUST NOT relay any gossip messages it did not generate itself, @@ -430,15 +433,16 @@ update_node_annoucement: static void dump_our_gossip(struct daemon *daemon, struct peer *peer) { struct node *me; - struct chan_map_iter i; - struct chan *chan; + struct chan_map_iter it; + const struct chan *chan, **chans = tal_arr(tmpctx, const struct chan *, 0); + size_t num_to_send; /* Find ourselves; if no channels, nothing to send */ me = get_node(daemon->rstate, &daemon->id); if (!me) return; - for (chan = first_chan(me, &i); chan; chan = next_chan(me, &i)) { + for (chan = first_chan(me, &it); chan; chan = next_chan(me, &it)) { /* Don't leak private channels, unless it's with you! */ if (!is_chan_public(chan)) { int dir = half_chan_idx(me, chan); @@ -452,6 +456,26 @@ static void dump_our_gossip(struct daemon *daemon, struct peer *peer) continue; } + tal_arr_expand(&chans, chan); + } + + /* Just in case we have many peers and not all are connecting or + * some other corner case, send everything to first few. */ + if (peer_node_id_map_count(daemon->peers) <= GOSSIP_SPAM_REDUNDANCY) + num_to_send = tal_count(chans); + else { + if (tal_count(chans) < GOSSIP_SPAM_REDUNDANCY) + num_to_send = tal_count(chans); + else { + /* Pick victims at random */ + tal_arr_randomize(chans, const struct chan *); + num_to_send = GOSSIP_SPAM_REDUNDANCY; + } + } + + for (size_t i = 0; i < num_to_send; i++) { + chan = chans[i]; + /* Send channel_announce */ queue_peer_from_store(peer, &chan->bcast);