From 75720ad0e1690052c108fbf457ded807bf09d6c1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 15 Jun 2021 06:37:39 +0930 Subject: [PATCH] lightningd: wait for gossipd to finish initalizing before starting plugins. This mainly helps our CI under valgrind, which starts a fresh instance and immediately calls the invoice command. This can cause the topology plugin to try to access the gossmap file before it's created. We can also move the gossmap reading in topology to init time. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 4 ++++ gossipd/gossipd_wire.csv | 2 ++ gossipd/gossipd_wiregen.c | 23 ++++++++++++++++++++++- gossipd/gossipd_wiregen.h | 7 ++++++- lightningd/gossip_control.c | 20 ++++++++++++++++++-- plugins/topology.c | 21 +++++++++------------ 6 files changed, 61 insertions(+), 16 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index eea5fd3d6..d13ba5e46 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1135,6 +1135,9 @@ static struct io_plan *gossip_init(struct io_conn *conn, daemon->connectd = daemon_conn_new(daemon, CONNECTD_FD, connectd_req, NULL, daemon); + /* OK, we are ready. */ + daemon_conn_send(daemon->master, + take(towire_gossipd_init_reply(NULL))); return daemon_conn_read_next(conn, daemon->master); } @@ -1507,6 +1510,7 @@ static struct io_plan *recv_req(struct io_conn *conn, return onionmsg_req(conn, daemon, msg); /* We send these, we don't receive them */ case WIRE_GOSSIPD_PING_REPLY: + case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: case WIRE_GOSSIPD_GET_TXOUT: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index bb51590e2..2dbd2b224 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -16,6 +16,8 @@ msgdata,gossipd_init,dev_gossip_time,?u32, msgdata,gossipd_init,dev_fast_gossip,bool, msgdata,gossipd_init,dev_fast_gossip_prune,bool, +msgtype,gossipd_init_reply,3100 + # In developer mode, we can mess with time. msgtype,gossipd_dev_set_time,3001 msgdata,gossipd_dev_set_time,dev_gossip_time,u32, diff --git a/gossipd/gossipd_wiregen.c b/gossipd/gossipd_wiregen.c index e779e9601..b5f6a2b32 100644 --- a/gossipd/gossipd_wiregen.c +++ b/gossipd/gossipd_wiregen.c @@ -21,6 +21,7 @@ const char *gossipd_wire_name(int e) switch ((enum gossipd_wire)e) { case WIRE_GOSSIPD_INIT: return "WIRE_GOSSIPD_INIT"; + case WIRE_GOSSIPD_INIT_REPLY: return "WIRE_GOSSIPD_INIT_REPLY"; case WIRE_GOSSIPD_DEV_SET_TIME: return "WIRE_GOSSIPD_DEV_SET_TIME"; case WIRE_GOSSIPD_PING: return "WIRE_GOSSIPD_PING"; case WIRE_GOSSIPD_PING_REPLY: return "WIRE_GOSSIPD_PING_REPLY"; @@ -52,6 +53,7 @@ bool gossipd_wire_is_defined(u16 type) { switch ((enum gossipd_wire)type) { case WIRE_GOSSIPD_INIT:; + case WIRE_GOSSIPD_INIT_REPLY:; case WIRE_GOSSIPD_DEV_SET_TIME:; case WIRE_GOSSIPD_PING:; case WIRE_GOSSIPD_PING_REPLY:; @@ -139,6 +141,25 @@ bool fromwire_gossipd_init(const tal_t *ctx, const void *p, const struct chainpa return cursor != NULL; } +/* WIRE: GOSSIPD_INIT_REPLY */ +u8 *towire_gossipd_init_reply(const tal_t *ctx) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_GOSSIPD_INIT_REPLY); + + return memcheck(p, tal_count(p)); +} +bool fromwire_gossipd_init_reply(const void *p) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_INIT_REPLY) + return false; + return cursor != NULL; +} + /* WIRE: GOSSIPD_DEV_SET_TIME */ /* In developer mode */ u8 *towire_gossipd_dev_set_time(const tal_t *ctx, u32 dev_gossip_time) @@ -732,4 +753,4 @@ bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestrin *err = fromwire_wirestring(ctx, &cursor, &plen); return cursor != NULL; } -// SHA256STAMP:bc9045727cefbbe29118c8eae928972fe009a4d9d8c9e903f8b35f006973f462 +// SHA256STAMP:6f6810a7e9c5e3e7dc1dd716b6a8de019516f6e82e3664bdf760647b5a987883 diff --git a/gossipd/gossipd_wiregen.h b/gossipd/gossipd_wiregen.h index 5059fb559..5e2c5f4a3 100644 --- a/gossipd/gossipd_wiregen.h +++ b/gossipd/gossipd_wiregen.h @@ -15,6 +15,7 @@ enum gossipd_wire { /* Initialize the gossip daemon. */ WIRE_GOSSIPD_INIT = 3000, + WIRE_GOSSIPD_INIT_REPLY = 3100, /* In developer mode */ WIRE_GOSSIPD_DEV_SET_TIME = 3001, /* Ping/pong test. Waits for a reply if it expects one. */ @@ -72,6 +73,10 @@ bool gossipd_wire_is_defined(u16 type); u8 *towire_gossipd_init(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_features, const struct node_id *id, const u8 rgb[3], const u8 alias[32], const struct wireaddr *announcable, u32 *dev_gossip_time, bool dev_fast_gossip, bool dev_fast_gossip_prune); bool fromwire_gossipd_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_features, struct node_id *id, u8 rgb[3], u8 alias[32], struct wireaddr **announcable, u32 **dev_gossip_time, bool *dev_fast_gossip, bool *dev_fast_gossip_prune); +/* WIRE: GOSSIPD_INIT_REPLY */ +u8 *towire_gossipd_init_reply(const tal_t *ctx); +bool fromwire_gossipd_init_reply(const void *p); + /* WIRE: GOSSIPD_DEV_SET_TIME */ /* In developer mode */ u8 *towire_gossipd_dev_set_time(const tal_t *ctx, u32 dev_gossip_time); @@ -175,4 +180,4 @@ bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestrin #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ -// SHA256STAMP:bc9045727cefbbe29118c8eae928972fe009a4d9d8c9e903f8b35f006973f462 +// SHA256STAMP:6f6810a7e9c5e3e7dc1dd716b6a8de019516f6e82e3664bdf760647b5a987883 diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 4063679e8..1b2fd6a70 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -148,6 +148,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_SEND_ONIONMSG: case WIRE_GOSSIPD_ADDGOSSIP: /* This is a reply, so never gets through to here. */ + case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: @@ -187,6 +188,16 @@ static void gossip_topology_synced(struct chain_topology *topo, void *unused) gossip_notify_new_block(topo->ld, get_block_height(topo)); } +/* We make sure gossipd is started before plugins (which may want gossip_map) */ +static void gossipd_init_done(struct subd *gossipd, + const u8 *msg, + const int *fds, + void *unused) +{ + /* Break out of loop, so we can begin */ + io_break(gossipd); +} + /* Create the `gossipd` subdaemon and send the initialization * message */ void gossip_init(struct lightningd *ld, int connectd_fd) @@ -207,7 +218,7 @@ void gossip_init(struct lightningd *ld, int connectd_fd) gossip_topology_synced, NULL); msg = towire_gossipd_init( - tmpctx, + NULL, chainparams, ld->our_features, &ld->id, @@ -217,7 +228,12 @@ void gossip_init(struct lightningd *ld, int connectd_fd) IFDEV(ld->dev_gossip_time ? &ld->dev_gossip_time: NULL, NULL), IFDEV(ld->dev_fast_gossip, false), IFDEV(ld->dev_fast_gossip_prune, false)); - subd_send_msg(ld->gossip, msg); + + subd_req(ld->gossip, ld->gossip, take(msg), -1, 0, + gossipd_init_done, NULL); + + /* Wait for gossipd_init_reply */ + io_loop(NULL, NULL); } void gossipd_notify_spend(struct lightningd *ld, diff --git a/plugins/topology.c b/plugins/topology.c index 47490f754..2fbe1db76 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -20,24 +20,15 @@ #include /* Access via get_gossmap() */ +static struct gossmap *global_gossmap; static struct node_id local_id; static struct plugin *plugin; /* We load this on demand, since we can start before gossipd. */ static struct gossmap *get_gossmap(void) { - static struct gossmap *gossmap; - - if (gossmap) - gossmap_refresh(gossmap); - else { - gossmap = notleak_with_children(gossmap_load(NULL, - GOSSIP_STORE_FILENAME)); - if (!gossmap) - plugin_err(plugin, "Could not load gossmap %s: %s", - GOSSIP_STORE_FILENAME, strerror(errno)); - } - return gossmap; + gossmap_refresh(global_gossmap); + return global_gossmap; } /* Convenience global since route_score_fuzz doesn't take args. 0 to 1. */ @@ -677,6 +668,12 @@ static const char *init(struct plugin *p, take(json_out_obj(NULL, NULL, NULL)), "{id:%}", JSON_SCAN(json_to_node_id, &local_id)); + global_gossmap = notleak_with_children(gossmap_load(NULL, + GOSSIP_STORE_FILENAME)); + if (!global_gossmap) + plugin_err(plugin, "Could not load gossmap %s: %s", + GOSSIP_STORE_FILENAME, strerror(errno)); + return NULL; }