From 918478b0ef5e377dd991557ec5fcd9bb2e331d3f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 8 Oct 2019 11:55:24 +1030 Subject: [PATCH] gossipd: use timestamp information to detect stale scids. If we have nothing better to do, ask about stale channels. Signed-off-by: Rusty Russell --- gossipd/seeker.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/gossipd/seeker.c b/gossipd/seeker.c index 4029711c5..e5699ebae 100644 --- a/gossipd/seeker.c +++ b/gossipd/seeker.c @@ -42,6 +42,9 @@ enum seeker_state { /* Asking a peer for unknown scids. */ ASKING_FOR_UNKNOWN_SCIDS, + + /* Asking a peer for stale scids. */ + ASKING_FOR_STALE_SCIDS, }; /* Passthrough helper for HTABLE_DEFINE_TYPE */ @@ -283,19 +286,20 @@ static void scid_query_done(struct peer *peer, bool complete) probe_random_scids(seeker, false); } -static void seek_any_unknown_scids(struct seeker *seeker) +/* Returns true if there were scids to seek. */ +static bool seek_any_unknown_scids(struct seeker *seeker) { struct peer *peer; struct short_channel_id *scids; /* Nothing we need to know about? */ if (scid_map_count(&seeker->unknown_scids) == 0) - return; + return false; /* No peers can answer? Try again later. */ peer = random_peer(seeker->daemon, peer_can_take_scid_query); if (!peer) - return; + return false; set_state(seeker, ASKING_FOR_UNKNOWN_SCIDS); selected_peer(seeker, peer); @@ -306,6 +310,66 @@ static void seek_any_unknown_scids(struct seeker *seeker) status_failed(STATUS_FAIL_INTERNAL_ERROR, "seeker: quering %zu scids is too many?", tal_count(scids)); + return true; +} + +/* Turns stale_scid_map into two arrays, and removes from map */ +static struct short_channel_id *stale_scids_remove(const tal_t *ctx, + struct seeker *seeker, + u8 **query_flags) +{ + struct stale_scid_map *map = &seeker->stale_scids; + struct short_channel_id *scids; + const struct stale_scid *s; + size_t i, max; + struct stale_scid_map_iter it; + + /* Marshal into an array: we can fit 7000 comfortably (8 byte scid, 1 byte flag). */ + if (stale_scid_map_count(map) < 7000) + max = stale_scid_map_count(map); + else + max = 7000; + + scids = tal_arr(ctx, struct short_channel_id, max); + *query_flags = tal_arr(ctx, u8, max); + + for (i = 0, s = stale_scid_map_first(map, &it); i < max; i++) { + scids[i] = s->scid; + (*query_flags)[i] = s->query_flag; + stale_scid_map_del(map, s); + tal_free(s); + } + assert(i == tal_count(scids)); + return scids; +} + +static bool seek_any_stale_scids(struct seeker *seeker) +{ + struct peer *peer; + struct short_channel_id *scids; + u8 *query_flags; + + /* Nothing we need to know about? */ + if (stale_scid_map_count(&seeker->stale_scids) == 0) + return false; + + /* No peers can answer? Try again later. */ + peer = random_peer(seeker->daemon, peer_can_take_scid_query); + if (!peer) + return false; + + set_state(seeker, ASKING_FOR_STALE_SCIDS); + selected_peer(seeker, peer); + + /* This is best-effort, so this consumes them as well. */ + scids = stale_scids_remove(tmpctx, seeker, &query_flags); + + if (!query_short_channel_ids(seeker->daemon, peer, scids, query_flags, + scid_query_done)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "seeker: quering %zu scids is too many?", + tal_count(scids)); + return true; } static void check_unknown_scid_query(struct seeker *seeker) @@ -727,6 +791,25 @@ static void check_nannounce_probing(struct seeker *seeker) peer_gossip_probe_nannounces(seeker); } +static void check_stale_scid_query(struct seeker *seeker) +{ + struct peer *peer = seeker->random_peer_softref; + + /* Did peer die? */ + if (!peer) { + probe_random_scids(seeker, true); + return; + } + + if (!peer_made_progress(seeker)) { + status_unusual("Bad gossip: peer %s has only moved gossip %zu->%zu for scid stale probe, hanging up on it", + type_to_string(tmpctx, struct node_id, &peer->id), + seeker->prev_gossip_count, peer->gossip_counter); + tal_free(peer); + + probe_random_scids(seeker, true); + } +} /* Periodic timer to see how our gossip is going. */ static void seeker_check(struct seeker *seeker) @@ -746,6 +829,9 @@ static void seeker_check(struct seeker *seeker) case ASKING_FOR_UNKNOWN_SCIDS: check_unknown_scid_query(seeker); break; + case ASKING_FOR_STALE_SCIDS: + check_stale_scid_query(seeker); + break; case PROBING_NANNOUNCES_NEED_PEER: peer_gossip_probe_nannounces(seeker); break; @@ -753,7 +839,8 @@ static void seeker_check(struct seeker *seeker) check_nannounce_probing(seeker); break; case NORMAL: - seek_any_unknown_scids(seeker); + if (!seek_any_unknown_scids(seeker)) + seek_any_stale_scids(seeker); break; } @@ -789,6 +876,7 @@ void seeker_setup_peer_gossip(struct seeker *seeker, struct peer *peer) case PROBING_NANNOUNCES: case NORMAL: case ASKING_FOR_UNKNOWN_SCIDS: + case ASKING_FOR_STALE_SCIDS: normal_gossip_start(seeker, peer); return; }