From fd2d74aa9b18f377bc1089b916259b561a069320 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 22 Sep 2019 11:51:19 +0930 Subject: [PATCH] gossipd: defer asking about txouts until we're synced or they're 6 deep. The first one means we don't discard channels just because we're not synced, and the second is implied by the spec: don't accept channel_announcement if the channel isn't 6 deep. Since LND defers in such cases, we do too (unless it's newer than the current block, in which case we simply discard). Otherwise there's a risk that a slow node might discard valid gossip. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 39 +++++++++++++++++++++++++++--- gossipd/gossipd.h | 3 +++ gossipd/routing.c | 14 +++++++++++ gossipd/routing.h | 1 + gossipd/test/run-crc32_of_update.c | 1 + gossipd/test/run-extended-info.c | 1 + 6 files changed, 55 insertions(+), 4 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index ae16d9978..965864278 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -547,12 +547,24 @@ static const u8 *handle_channel_announcement_msg(struct peer *peer, /* If it's OK, tells us the short_channel_id to lookup; it notes * if this is the unknown channel the peer was looking for (in * which case, it frees and NULLs that ptr) */ - err = handle_channel_announcement(peer->daemon->rstate, msg, &scid); + err = handle_channel_announcement(peer->daemon->rstate, msg, + peer->daemon->current_blockheight, + &scid); if (err) return err; - else if (scid) - daemon_conn_send(peer->daemon->master, - take(towire_gossip_get_txout(NULL, scid))); + else if (scid) { + /* We give them some grace period, in case we don't know about + * block yet. */ + if (peer->daemon->current_blockheight == 0 + || !is_scid_depth_announceable(scid, + peer->daemon->current_blockheight)) { + tal_arr_expand(&peer->daemon->deferred_txouts, *scid); + } else { + daemon_conn_send(peer->daemon->master, + take(towire_gossip_get_txout(NULL, + scid))); + } + } return NULL; } @@ -2350,6 +2362,24 @@ static struct io_plan *new_blockheight(struct io_conn *conn, { if (!fromwire_gossip_new_blockheight(msg, &daemon->current_blockheight)) master_badmsg(WIRE_GOSSIP_NEW_BLOCKHEIGHT, msg); + + /* Check if we can now send any deferred queries. */ + for (size_t i = 0; i < tal_count(daemon->deferred_txouts); i++) { + const struct short_channel_id *scid + = &daemon->deferred_txouts[i]; + + if (!is_scid_depth_announceable(scid, + daemon->current_blockheight)) + continue; + + /* short_channel_id is deep enough, now ask about it. */ + daemon_conn_send(daemon->master, + take(towire_gossip_get_txout(NULL, scid))); + + tal_arr_remove(&daemon->deferred_txouts, i); + i--; + } + return daemon_conn_read_next(conn, daemon->master); } @@ -2885,6 +2915,7 @@ int main(int argc, char *argv[]) daemon = tal(NULL, struct daemon); list_head_init(&daemon->peers); daemon->unknown_scids = tal_arr(daemon, struct short_channel_id, 0); + daemon->deferred_txouts = tal_arr(daemon, struct short_channel_id, 0); daemon->gossip_missing = NULL; daemon->node_announce_timer = NULL; daemon->current_blockheight = 0; /* i.e. unknown */ diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index f9d3e2514..fcb3a6a96 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -54,6 +54,9 @@ struct daemon { /* Timer until we can send a new node_announcement */ struct oneshot *node_announce_timer; + + /* Channels we have an announce for, but aren't deep enough. */ + struct short_channel_id *deferred_txouts; }; /* Search for a peer. */ diff --git a/gossipd/routing.c b/gossipd/routing.c index db20cec99..37fd92cf8 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -1602,6 +1602,7 @@ bool routing_add_channel_announcement(struct routing_state *rstate, u8 *handle_channel_announcement(struct routing_state *rstate, const u8 *announce TAKES, + u32 current_blockheight, const struct short_channel_id **scid) { struct pending_cannouncement *pending; @@ -1636,6 +1637,19 @@ u8 *handle_channel_announcement(struct routing_state *rstate, goto malformed; } + /* If we know the blockheight, and it's in the future, reject + * out-of-hand. Remember, it should be 6 deep before they tell us + * anyway. */ + if (current_blockheight != 0 + && short_channel_id_blocknum(&pending->short_channel_id) > current_blockheight) { + status_debug("Ignoring future channel_announcment for %s" + " (current block %u)", + type_to_string(tmpctx, struct short_channel_id, + &pending->short_channel_id), + current_blockheight); + goto ignored; + } + /* If a prior txout lookup failed there is little point it trying * again. Just drop the announcement and walk away whistling. Any non-0 * result means this failed before. */ diff --git a/gossipd/routing.h b/gossipd/routing.h index 6f69233f9..180363a5c 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -346,6 +346,7 @@ struct chan *new_chan(struct routing_state *rstate, */ u8 *handle_channel_announcement(struct routing_state *rstate, const u8 *announce TAKES, + u32 current_blockheight, const struct short_channel_id **scid); /** diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 50ba85211..157a3e68d 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -177,6 +177,7 @@ const char *got_pong(const u8 *pong UNNEEDED, size_t *num_pings_outstanding UNNE /* Generated stub for handle_channel_announcement */ u8 *handle_channel_announcement(struct routing_state *rstate UNNEEDED, const u8 *announce TAKES UNNEEDED, + u32 current_blockheight UNNEEDED, const struct short_channel_id **scid UNNEEDED) { fprintf(stderr, "handle_channel_announcement called!\n"); abort(); } /* Generated stub for handle_channel_update */ diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index 9fc703fee..0fa27c471 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -184,6 +184,7 @@ const char *got_pong(const u8 *pong UNNEEDED, size_t *num_pings_outstanding UNNE /* Generated stub for handle_channel_announcement */ u8 *handle_channel_announcement(struct routing_state *rstate UNNEEDED, const u8 *announce TAKES UNNEEDED, + u32 current_blockheight UNNEEDED, const struct short_channel_id **scid UNNEEDED) { fprintf(stderr, "handle_channel_announcement called!\n"); abort(); } /* Generated stub for handle_channel_update */