From 4d8b29089b047d2014776ce8a4f03114c916b4a1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 4 Jun 2018 13:52:25 +0930 Subject: [PATCH] gossipd: wire up infrastructure to generate query_short_channel_ids msg. Signed-off-by: Rusty Russell --- gossipd/gossip.c | 143 ++++++++++++++++++++++++++++++++++-- gossipd/gossip_wire.csv | 11 +++ lightningd/gossip_control.c | 2 + 3 files changed, 151 insertions(+), 5 deletions(-) diff --git a/gossipd/gossip.c b/gossipd/gossip.c index 6ab24a7ef..31b9e5f94 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -228,6 +228,9 @@ struct peer { /* Is it time to continue the staggered broadcast? */ bool gossip_sync; + /* How many query responses are we expecting? */ + size_t num_scid_queries_outstanding; + /* Only one of these is set: */ struct local_peer_state *local; struct daemon_conn *remote; @@ -348,6 +351,7 @@ static struct peer *new_peer(const tal_t *ctx, peer->scid_query_idx = 0; peer->scid_query_nodes = NULL; peer->scid_query_nodes_idx = 0; + peer->num_scid_queries_outstanding = 0; return peer; } @@ -403,6 +407,30 @@ static void reached_peer(struct peer *peer, struct io_conn *conn) tal_free(r); } +static u8 *encode_short_channel_ids_start(const tal_t *ctx) +{ + /* BOLT #7: + * + * Encoding types: + * * `0`: uncompressed array of `short_channel_id` types, in ascending + * order. + */ + u8 *encoded = tal_arr(tmpctx, u8, 0); + towire_u8(&encoded, 0); + return encoded; +} + +static void encode_add_short_channel_id(u8 **encoded, + const struct short_channel_id *scid) +{ + towire_short_channel_id(encoded, scid); +} + +static bool encode_short_channel_ids_end(u8 **encoded, size_t max_bytes) +{ + return tal_len(*encoded) <= max_bytes; +} + static void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) { if (peer->local) { @@ -820,6 +848,34 @@ static void handle_pong(struct peer *peer, const u8 *pong) tal_len(pong)))); } +static void handle_reply_short_channel_ids_end(struct peer *peer, u8 *msg) +{ + struct bitcoin_blkid chain; + u8 complete; + + if (!fromwire_reply_short_channel_ids_end(msg, &chain, &complete)) { + peer_error(peer, "Bad reply_short_channel_ids_end %s", + tal_hex(tmpctx, msg)); + return; + } + + if (!structeq(&peer->daemon->rstate->chain_hash, &chain)) { + peer_error(peer, "reply_short_channel_ids_end for bad chain: %s", + tal_hex(tmpctx, msg)); + return; + } + + if (peer->num_scid_queries_outstanding == 0) { + peer_error(peer, "unexpected reply_short_channel_ids_end: %s", + tal_hex(tmpctx, msg)); + return; + } + + peer->num_scid_queries_outstanding--; + msg = towire_gossip_scids_reply(msg, true, complete); + daemon_conn_send(&peer->daemon->master, take(msg)); +} + /* If master asks us to release peer, we attach this destructor in case it * dies while we're waiting for it to finish IO */ static void fail_release(struct peer *peer) @@ -903,6 +959,10 @@ static struct io_plan *peer_msgin(struct io_conn *conn, handle_query_short_channel_ids(peer, msg); return peer_next_in(conn, peer); + case WIRE_REPLY_SHORT_CHANNEL_IDS_END: + handle_reply_short_channel_ids_end(peer, msg); + return peer_next_in(conn, peer); + case WIRE_OPEN_CHANNEL: case WIRE_CHANNEL_REESTABLISH: case WIRE_ACCEPT_CHANNEL: @@ -927,7 +987,6 @@ static struct io_plan *peer_msgin(struct io_conn *conn, /* This will wait. */ return peer_next_in(conn, peer); - case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_QUERY_CHANNEL_RANGE: case WIRE_REPLY_CHANNEL_RANGE: case WIRE_GOSSIP_TIMESTAMP_FILTER: @@ -1037,7 +1096,7 @@ static bool create_next_scid_reply(struct peer *peer) struct chan *chan; chan = get_channel(rstate, &peer->scid_queries[i]); - if (!chan || is_chan_public(chan)) + if (!chan || !is_chan_public(chan)) continue; queue_peer_msg(peer, chan->channel_announce); @@ -1336,6 +1395,8 @@ static struct io_plan *owner_msg_in(struct io_conn *conn, 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_REPLY_SHORT_CHANNEL_IDS_END) { + handle_reply_short_channel_ids_end(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) { @@ -1751,6 +1812,7 @@ static struct io_plan *getnodes(struct io_conn *conn, struct daemon *daemon, return daemon_conn_read_next(conn, &daemon->master); } +#if DEVELOPER static struct io_plan *ping_req(struct io_conn *conn, struct daemon *daemon, const u8 *msg) { @@ -1793,6 +1855,67 @@ out: return daemon_conn_read_next(conn, &daemon->master); } +static struct io_plan *query_scids_req(struct io_conn *conn, + struct daemon *daemon, + const u8 *msg) +{ + struct pubkey id; + struct short_channel_id *scids; + struct peer *peer; + u8 *encoded; + /* BOLT #7: + * + * 1. type: 261 (`query_short_channel_ids`) (`gossip_queries`) + * 2. data: + * * [`32`:`chain_hash`] + * * [`2`:`len`] + * * [`len`:`encoded_short_ids`] + */ + const size_t reply_overhead = 32 + 2; + const size_t max_encoded_bytes = 65535 - 2 - reply_overhead; + + if (!fromwire_gossip_query_scids(msg, msg, &id, &scids)) + master_badmsg(WIRE_GOSSIP_QUERY_SCIDS, msg); + + peer = find_peer(daemon, &id); + if (!peer) { + status_broken("query_scids: unknown peer %s", + type_to_string(tmpctx, struct pubkey, &id)); + goto fail; + } + + if (!feature_offered(peer->lfeatures, LOCAL_GOSSIP_QUERIES)) { + status_broken("query_scids: no gossip_query support in peer %s", + type_to_string(tmpctx, struct pubkey, &id)); + goto fail; + } + + encoded = encode_short_channel_ids_start(tmpctx); + for (size_t i = 0; i < tal_count(scids); i++) + encode_add_short_channel_id(&encoded, &scids[i]); + + if (!encode_short_channel_ids_end(&encoded, max_encoded_bytes)) { + status_broken("query_short_channel_ids: %zu is too many", + tal_count(scids)); + goto fail; + } + + msg = towire_query_short_channel_ids(NULL, &daemon->rstate->chain_hash, + encoded); + queue_peer_msg(peer, take(msg)); + peer->num_scid_queries_outstanding++; + + status_trace("sending query for %zu scids", tal_count(scids)); +out: + return daemon_conn_read_next(conn, &daemon->master); + +fail: + daemon_conn_send(&daemon->master, + take(towire_gossip_scids_reply(NULL, false, false))); + goto out; +} +#endif /* DEVELOPER */ + static int make_listen_fd(int domain, void *addr, socklen_t len, bool mayfail) { int fd = socket(domain, SOCK_STREAM, 0); @@ -2966,9 +3089,6 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIP_GETCHANNELS_REQUEST: return getchannels_req(conn, daemon, daemon->master.msg_in); - case WIRE_GOSSIP_PING: - return ping_req(conn, daemon, daemon->master.msg_in); - case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST: return resolve_channel_req(conn, daemon, daemon->master.msg_in); @@ -3008,6 +3128,18 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIP_LOCAL_CHANNEL_CLOSE: return handle_local_channel_close(conn, daemon, master->msg_in); +#if DEVELOPER + case WIRE_GOSSIP_PING: + return ping_req(conn, daemon, daemon->master.msg_in); + + case WIRE_GOSSIP_QUERY_SCIDS: + return query_scids_req(conn, daemon, daemon->master.msg_in); +#else + case WIRE_GOSSIP_PING: + case WIRE_GOSSIP_QUERY_SCIDS: + break; +#endif /* !DEVELOPER */ + /* We send these, we don't receive them */ case WIRE_GOSSIPCTL_ACTIVATE_REPLY: case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: @@ -3017,6 +3149,7 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIP_GETCHANNELS_REPLY: case WIRE_GOSSIP_GETPEERS_REPLY: case WIRE_GOSSIP_PING_REPLY: + case WIRE_GOSSIP_SCIDS_REPLY: case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY: case WIRE_GOSSIP_PEER_CONNECTED: case WIRE_GOSSIPCTL_CONNECT_TO_PEER_RESULT: diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index 53acd72df..c5805067b 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -155,6 +155,17 @@ gossip_ping_reply,,sent,bool # 0 == no pong expected gossip_ping_reply,,totlen,u16 +# Test of query_short_channel_ids. Master->gossipd +gossip_query_scids,3031 +gossip_query_scids,,id,struct pubkey +gossip_query_scids,,num_ids,u16 +gossip_query_scids,,ids,num_ids*struct short_channel_id + +# Gossipd -> master +gossip_scids_reply,3131 +gossip_scids_reply,,ok,bool +gossip_scids_reply,,complete,bool + # Given a short_channel_id, return the endpoints gossip_resolve_channel_request,3009 gossip_resolve_channel_request,,channel_id,struct short_channel_id diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 39e553bd4..1cecba96f 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -136,6 +136,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIP_OUTPOINT_SPENT: case WIRE_GOSSIP_ROUTING_FAILURE: case WIRE_GOSSIP_MARK_CHANNEL_UNROUTABLE: + case WIRE_GOSSIP_QUERY_SCIDS: case WIRE_GOSSIPCTL_PEER_DISCONNECT: case WIRE_GOSSIPCTL_PEER_IMPORTANT: case WIRE_GOSSIPCTL_PEER_DISCONNECTED: @@ -147,6 +148,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIP_GETCHANNELS_REPLY: case WIRE_GOSSIP_GETPEERS_REPLY: case WIRE_GOSSIP_PING_REPLY: + case WIRE_GOSSIP_SCIDS_REPLY: case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY: case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIPCTL_RELEASE_PEER_REPLYFAIL: