Skip to content

Commit

Permalink
gossipd: control gossip level so we don't get flooded by peers.
Browse files Browse the repository at this point in the history
We seek a certain number of peers at each level of gossip; 3 "flood"
if we're missing gossip, 2 at 24 hours past to catch recent gossip, and
8 with current gossip.  The rest are given a filter which causes them
not to gossip to us at all.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jun 12, 2019
1 parent f5ea57d commit 6830233
Showing 1 changed file with 82 additions and 6 deletions.
88 changes: 82 additions & 6 deletions gossipd/gossipd.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ struct daemon {
struct short_channel_id *unknown_scids;
};

/*~ How gossipy do we ask a peer to be? */
enum gossip_level {
/* Give us everything since epoch */
GOSSIP_HIGH,
/* Give us everything from 24 hours ago. */
GOSSIP_MEDIUM,
/* Give us everything from now. */
GOSSIP_LOW,
/* Give us nothing. */
GOSSIP_NONE,
};

/* What are our targets for each gossip level? (including levels above).
*
* If we're missing gossip: 3 high.
* Otherwise, 2 medium, and 8 low. Rest no limit..
*/
static const size_t gossip_level_targets[] = { 3, 2, 8, SIZE_MAX };

/* This represents each peer we're gossiping with */
struct peer {
/* daemon->peers */
Expand Down Expand Up @@ -157,6 +176,9 @@ struct peer {
u32 range_blocks_remaining;
struct short_channel_id *query_channel_scids;

/* Are we asking this peer to give us lot of gossip? */
enum gossip_level gossip_level;

/* The daemon_conn used to queue messages to/from the peer. */
struct daemon_conn *dc;
};
Expand Down Expand Up @@ -312,6 +334,22 @@ static bool encode_short_channel_ids_end(u8 **encoded, size_t max_bytes)
return tal_count(*encoded) <= max_bytes;
}

/*~ We have different levels of gossipiness, depending on our needs. */
static u32 gossip_start(enum gossip_level gossip_level)
{
switch (gossip_level) {
case GOSSIP_HIGH:
return 0;
case GOSSIP_MEDIUM:
return time_now().ts.tv_sec - 24 * 3600;
case GOSSIP_LOW:
return time_now().ts.tv_sec;
case GOSSIP_NONE:
return UINT32_MAX;
}
abort();
}

/* BOLT #7:
*
* A node:
Expand All @@ -323,16 +361,23 @@ static void setup_gossip_range(struct peer *peer)
u8 *msg;

/*~ Without the `gossip_queries` feature, gossip flows automatically. */
if (!peer->gossip_queries_feature)
if (!peer->gossip_queries_feature) {
/* This peer is gossipy whether we want it or not! */
return;
}

/*~ We need to ask for something to start the gossip flowing: we ask
* for everything from 1970 to 2106; this is horribly naive. We
* should be much smarter about requesting only what we don't already
* have. */
status_trace("Setting peer %s to gossip level %s",
type_to_string(tmpctx, struct node_id, &peer->id),
peer->gossip_level == GOSSIP_HIGH ? "HIGH"
: peer->gossip_level == GOSSIP_MEDIUM ? "MEDIUM"
: peer->gossip_level == GOSSIP_LOW ? "LOW"
: peer->gossip_level == GOSSIP_NONE ? "NONE"
: "INVALID");
/*~ We need to ask for something to start the gossip flowing. */
msg = towire_gossip_timestamp_filter(peer,
&peer->daemon->chain_hash,
0, UINT32_MAX);
gossip_start(peer->gossip_level),
UINT32_MAX);
queue_peer_msg(peer, take(msg));
}

Expand Down Expand Up @@ -1669,6 +1714,35 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
return daemon_conn_read_next(conn, peer->dc);
}

/* What gossip level do we set for this to meet our target? */
static enum gossip_level peer_gossip_level(const struct daemon *daemon,
bool gossip_queries_feature)
{
struct peer *peer;
size_t gossip_levels[ARRAY_SIZE(gossip_level_targets)];
enum gossip_level glevel;

/* Old peers always give us a flood. */
if (!gossip_queries_feature)
return GOSSIP_HIGH;

/* Figure out how many we have at each level. */
memset(gossip_levels, 0, sizeof(gossip_levels));
list_for_each(&daemon->peers, peer, list)
gossip_levels[peer->gossip_level]++;

/* If we're missing gossip, try to fill GOSSIP_HIGH */
if (daemon->gossip_missing != NULL)
glevel = GOSSIP_HIGH;
else
glevel = GOSSIP_MEDIUM;

while (gossip_levels[glevel] >= gossip_level_targets[glevel])
glevel++;

return glevel;
}

/*~ This is where connectd tells us about a new peer, and we hand back an fd for
* it to send us messages via peer_msg_in above */
static struct io_plan *connectd_new_peer(struct io_conn *conn,
Expand Down Expand Up @@ -1723,6 +1797,8 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
peer->scid_query_outstanding = false;
peer->query_channel_blocks = NULL;
peer->num_pings_outstanding = 0;
peer->gossip_level = peer_gossip_level(daemon,
peer->gossip_queries_feature);

/* We keep a list so we can find peer by id */
list_add_tail(&peer->daemon->peers, &peer->list);
Expand Down

0 comments on commit 6830233

Please sign in to comment.