diff --git a/gossipd/gossip.c b/gossipd/gossip.c index d157b122e..6ab24a7ef 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -694,6 +694,105 @@ static u8 *handle_gossip_msg(struct daemon *daemon, const u8 *msg, return NULL; } +/* BOLT #7: + * + * the first byte indicates the encoding, the rest contains the data. + * + * Encoding types: + * * `0`: uncompressed array of `short_channel_id` types, in ascending order. + */ +static struct short_channel_id *decode_short_ids(const tal_t *ctx, + const u8 *encoded) +{ + struct short_channel_id *scids; + size_t max = tal_len(encoded), n; + u8 type; + + /* BOLT #7: + * + * The receiver: + * - if the first byte of `encoded_short_ids` is not zero: + * - MAY fail the connection + * - if `encoded_short_ids` does not decode into a whole number of + * `short_channel_id`: + * - MAY fail the connection + */ + type = fromwire_u8(&encoded, &max); + if (type != 0) + return NULL; + + n = 0; + scids = tal_arr(ctx, struct short_channel_id, n); + while (max) { + tal_resize(&scids, n+1); + fromwire_short_channel_id(&encoded, &max, &scids[n++]); + } + + /* encoded is set to NULL if we ran over */ + if (!encoded) + return tal_free(scids); + return scids; +} + +static void handle_query_short_channel_ids(struct peer *peer, u8 *msg) +{ + struct routing_state *rstate =peer->daemon->rstate; + struct bitcoin_blkid chain; + u8 *encoded; + struct short_channel_id *scids; + + if (!fromwire_query_short_channel_ids(tmpctx, msg, &chain, &encoded)) { + peer_error(peer, "Bad query_short_channel_ids %s", + tal_hex(tmpctx, msg)); + return; + } + + if (!structeq(&rstate->chain_hash, &chain)) { + status_trace("%s sent query_short_channel_ids chainhash %s", + type_to_string(tmpctx, struct pubkey, &peer->id), + type_to_string(tmpctx, struct bitcoin_blkid, &chain)); + return; + } + + /* BOLT #7: + * + * - if it has not sent `reply_short_channel_ids_end` to a + * previously received `query_short_channel_ids` from this + * sender: + * - MAY fail the connection. + */ + if (peer->scid_queries || peer->scid_query_nodes) { + peer_error(peer, "Bad second query_short_channel_ids"); + return; + } + + scids = decode_short_ids(tmpctx, encoded); + if (!scids) { + peer_error(peer, "Bad query_short_channel_ids encoding %s", + tal_hex(tmpctx, encoded)); + return; + } + + /* BOLT #7: + * + * - SHOULD respond to each known `short_channel_id` with a + * `channel_announce` and the latest `channel_update`s for each end + * - SHOULD NOT wait for the next outgoing announcement flush to send + * these. + */ + peer->scid_queries = tal_steal(peer, scids); + peer->scid_query_idx = 0; + peer->scid_query_nodes = tal_arr(peer, struct pubkey, 0); + + /* Wake writer. */ + if (peer->local) + /* Notify the peer-write loop */ + msg_wake(&peer->local->peer_out); + else + /* Notify the daemon_conn-write loop */ + msg_wake(&peer->remote->out); +} + static void handle_ping(struct peer *peer, u8 *ping) { u8 *pong; @@ -800,6 +899,10 @@ static struct io_plan *peer_msgin(struct io_conn *conn, handle_pong(peer, msg); return peer_next_in(conn, peer); + case WIRE_QUERY_SHORT_CHANNEL_IDS: + handle_query_short_channel_ids(peer, msg); + return peer_next_in(conn, peer); + case WIRE_OPEN_CHANNEL: case WIRE_CHANNEL_REESTABLISH: case WIRE_ACCEPT_CHANNEL: @@ -824,7 +927,6 @@ static struct io_plan *peer_msgin(struct io_conn *conn, /* This will wait. */ return peer_next_in(conn, peer); - case WIRE_QUERY_SHORT_CHANNEL_IDS: case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_QUERY_CHANNEL_RANGE: case WIRE_REPLY_CHANNEL_RANGE: @@ -1232,7 +1334,8 @@ static struct io_plan *owner_msg_in(struct io_conn *conn, err = handle_gossip_msg(peer->daemon, dc->msg_in, "subdaemon"); if (err) queue_peer_msg(peer, take(err)); - + } else if (type == WIRE_QUERY_SHORT_CHANNEL_IDS) { + handle_query_short_channel_ids(peer, dc->msg_in); } else if (type == WIRE_GOSSIP_GET_UPDATE) { handle_get_update(peer, dc->msg_in); } else if (type == WIRE_GOSSIP_LOCAL_ADD_CHANNEL) {