diff --git a/common/gossmap.c b/common/gossmap.c index 051f04bc97ad..e9f3b693debf 100644 --- a/common/gossmap.c +++ b/common/gossmap.c @@ -458,7 +458,7 @@ static struct gossmap_chan *add_channel(struct gossmap *map, * * [`u32`:`fee_proportional_millionths`] * * [`u64`:`htlc_maximum_msat`] (option_channel_htlc_max) */ -static void update_channel(struct gossmap *map, size_t cupdate_off) +static bool update_channel(struct gossmap *map, size_t cupdate_off) { /* Note that first two bytes are message type */ const size_t scid_off = cupdate_off + 2 + (64 + 32); @@ -473,6 +473,7 @@ static void update_channel(struct gossmap *map, size_t cupdate_off) struct gossmap_chan *chan; struct half_chan hc; u8 chanflags; + bool dumb_values; scid.u64 = map_be64(map, scid_off); chan = gossmap_find_chan(map, &scid); @@ -502,19 +503,18 @@ static void update_channel(struct gossmap *map, size_t cupdate_off) if (hc.base_fee != map_be32(map, fee_base_off) || hc.proportional_fee != map_be32(map, fee_prop_off) || hc.delay != map_be16(map, cltv_expiry_delta_off)) { - warnx("channel_update %s ignored: fee %u/%u cltv %u too large", - type_to_string(tmpctx, struct short_channel_id, &scid), - map_be32(map, fee_base_off), - map_be32(map, fee_prop_off), - map_be16(map, cltv_expiry_delta_off)); + dumb_values = true; hc.htlc_max = 0; hc.enabled = false; - } + } else + dumb_values = false; /* Preserve this */ hc.nodeidx = chan->half[chanflags & 1].nodeidx; chan->half[chanflags & 1] = hc; chan->cupdate_off[chanflags & 1] = cupdate_off; + + return !dumb_values; } static void remove_channel_by_deletemsg(struct gossmap *map, size_t del_off) @@ -580,13 +580,14 @@ static void reopen_store(struct gossmap *map, size_t ended_off) close(map->fd); map->fd = fd; - gossmap_refresh(map); + gossmap_refresh(map, NULL); } -static bool map_catchup(struct gossmap *map) +static bool map_catchup(struct gossmap *map, size_t *num_rejected) { size_t reclen; bool changed = false; + size_t num_bad = 0; for (; map->map_end + sizeof(struct gossip_hdr) < map->map_size; map->map_end += reclen) { @@ -612,9 +613,9 @@ static bool map_catchup(struct gossmap *map) else if (type == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL) add_channel(map, off + 2 + 8 + 2, true); else if (type == WIRE_CHANNEL_UPDATE) - update_channel(map, off); + num_bad += !update_channel(map, off); else if (type == WIRE_GOSSIP_STORE_PRIVATE_UPDATE) - update_channel(map, off + 2 + 2); + num_bad += !update_channel(map, off + 2 + 2); else if (type == WIRE_GOSSIP_STORE_DELETE_CHAN) remove_channel_by_deletemsg(map, off); else if (type == WIRE_NODE_ANNOUNCEMENT) @@ -627,10 +628,12 @@ static bool map_catchup(struct gossmap *map) changed = true; } + if (num_rejected) + *num_rejected = num_bad; return changed; } -static bool load_gossip_store(struct gossmap *map) +static bool load_gossip_store(struct gossmap *map, size_t *num_rejected) { map->fd = open(map->fname, O_RDONLY); if (map->fd < 0) @@ -665,7 +668,7 @@ static bool load_gossip_store(struct gossmap *map) map->freed_nodes = init_node_arr(map->node_arr, 0); map->map_end = 1; - map_catchup(map); + map_catchup(map, num_rejected); return true; } @@ -910,7 +913,7 @@ void gossmap_remove_localmods(struct gossmap *map, map->local = NULL; } -bool gossmap_refresh(struct gossmap *map) +bool gossmap_refresh(struct gossmap *map, size_t *num_rejected) { off_t len; @@ -928,14 +931,15 @@ bool gossmap_refresh(struct gossmap *map) map->mmap = mmap(NULL, map->map_size, PROT_READ, MAP_SHARED, map->fd, 0); if (map->mmap == MAP_FAILED) map->mmap = NULL; - return map_catchup(map); + return map_catchup(map, num_rejected); } -struct gossmap *gossmap_load(const tal_t *ctx, const char *filename) +struct gossmap *gossmap_load(const tal_t *ctx, const char *filename, + size_t *num_channel_updates_rejected) { map = tal(ctx, struct gossmap); map->fname = tal_strdup(map, filename); - if (load_gossip_store(map)) + if (load_gossip_store(map, num_channel_updates_rejected)) tal_add_destructor(map, destroy_map); else map = tal_free(map); diff --git a/common/gossmap.h b/common/gossmap.h index a75e20a149bd..92880f098472 100644 --- a/common/gossmap.h +++ b/common/gossmap.h @@ -41,11 +41,14 @@ struct gossmap_chan { } half[2]; }; -struct gossmap *gossmap_load(const tal_t *ctx, const char *filename); +/* If num_channel_updates_rejected is not NULL, indicates how many channels we + * marked inactive because their values were too high to be represented. */ +struct gossmap *gossmap_load(const tal_t *ctx, const char *filename, + size_t *num_channel_updates_rejected); /* Call this before using to ensure it's up-to-date. Returns true if something * was updated. Note: this can scramble node and chan indexes! */ -bool gossmap_refresh(struct gossmap *map); +bool gossmap_refresh(struct gossmap *map, size_t *num_channel_updates_rejected); /* Local modifications. */ struct gossmap_localmods *gossmap_localmods_new(const tal_t *ctx); diff --git a/common/test/run-gossmap_local.c b/common/test/run-gossmap_local.c index c624f93d11b2..fecfcbd8041f 100644 --- a/common/test/run-gossmap_local.c +++ b/common/test/run-gossmap_local.c @@ -311,7 +311,7 @@ int main(int argc, char *argv[]) fd = mkstemp(gossfile); assert(write_all(fd, canned_map, sizeof(canned_map))); - map = gossmap_load(tmpctx, gossfile); + map = gossmap_load(tmpctx, gossfile, NULL); assert(map); /* There is a public channel 2<->3 (103x1x0), and private @@ -503,6 +503,6 @@ int main(int argc, char *argv[]) /* Now we can refresh. */ assert(write(fd, "", 1) == 1); - gossmap_refresh(map); + gossmap_refresh(map, NULL); common_shutdown(); } diff --git a/common/test/run-route-specific.c b/common/test/run-route-specific.c index 3690ce5ba023..d2c402388590 100644 --- a/common/test/run-route-specific.c +++ b/common/test/run-route-specific.c @@ -210,7 +210,7 @@ int main(void) assert(write(store_fd, &gossip_version, sizeof(gossip_version)) == sizeof(gossip_version)); - gossmap = gossmap_load(tmpctx, gossipfilename); + gossmap = gossmap_load(tmpctx, gossipfilename, NULL); /* [{'active': True, 'short_id': '6990:2:1/1', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'last_update': 1504064344}, */ add_connection(store_fd, &c, &b, "6990x2x1", @@ -232,7 +232,7 @@ int main(void) AMOUNT_MSAT(0), AMOUNT_MSAT(1000), 0, 10, 5, false); - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); a_node = gossmap_find_node(gossmap, &a); b_node = gossmap_find_node(gossmap, &b); @@ -278,7 +278,7 @@ int main(void) add_connection(store_fd, &a, &d, "6991x2x1", AMOUNT_MSAT(100), AMOUNT_MSAT(499968), /* exact repr in fp16! */ 0, 0, 5); - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); a_node = gossmap_find_node(gossmap, &a); b_node = gossmap_find_node(gossmap, &b); diff --git a/common/test/run-route.c b/common/test/run-route.c index 0c50b798e04b..d2a08700d6d6 100644 --- a/common/test/run-route.c +++ b/common/test/run-route.c @@ -190,18 +190,18 @@ int main(void) store_fd = mkstemp(gossipfilename); assert(write(store_fd, &gossip_version, sizeof(gossip_version)) == sizeof(gossip_version)); - gossmap = gossmap_load(tmpctx, gossipfilename); + gossmap = gossmap_load(tmpctx, gossipfilename, NULL); memset(&tmp, 'a', sizeof(tmp)); node_id_from_privkey(&tmp, &a); memset(&tmp, 'b', sizeof(tmp)); node_id_from_privkey(&tmp, &b); - assert(!gossmap_refresh(gossmap)); + assert(!gossmap_refresh(gossmap, NULL)); /* A<->B */ add_connection(store_fd, &a, &b, 1, 1, 1); - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); a_node = gossmap_find_node(gossmap, &a); b_node = gossmap_find_node(gossmap, &b); @@ -219,7 +219,7 @@ int main(void) memset(&tmp, 'c', sizeof(tmp)); node_id_from_privkey(&tmp, &c); add_connection(store_fd, &b, &c, 1, 1, 1); - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); /* These can theoretically change after refresh! */ a_node = gossmap_find_node(gossmap, &a); @@ -243,7 +243,7 @@ int main(void) add_connection(store_fd, &a, &d, 0, 2, 1); add_connection(store_fd, &d, &c, 0, 2, 1); - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); /* These can theoretically change after refresh! */ a_node = gossmap_find_node(gossmap, &a); @@ -284,7 +284,7 @@ int main(void) /* Make B->C inactive, force it back via D */ update_connection(store_fd, &b, &c, 1, 1, 1, true); - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); /* These can theoretically change after refresh! */ a_node = gossmap_find_node(gossmap, &a); diff --git a/devtools/route.c b/devtools/route.c index 77facf97fd6d..1bd3c627cfd4 100644 --- a/devtools/route.c +++ b/devtools/route.c @@ -71,6 +71,7 @@ int main(int argc, char *argv[]) struct gossmap *map; struct node_id dstid; bool clean_topology = false; + size_t num_channel_updates_rejected; opt_register_noarg("--clean-topology", opt_set_bool, &clean_topology, "Clean up topology before run"); @@ -83,13 +84,14 @@ int main(int argc, char *argv[]) opt_usage_exit_fail("Expect 3 arguments"); tstart = time_mono(); - map = gossmap_load(NULL, argv[1]); + map = gossmap_load(NULL, argv[1], &num_channel_updates_rejected); if (!map) err(1, "Loading gossip store %s", argv[1]); tstop = time_mono(); - printf("# Time to load: %"PRIu64" msec\n", - time_to_msec(timemono_between(tstop, tstart))); + printf("# Time to load: %"PRIu64" msec (%zu ignored)\n", + time_to_msec(timemono_between(tstop, tstart)), + num_channel_updates_rejected); if (clean_topology) clean_topo(map, false); diff --git a/devtools/topology.c b/devtools/topology.c index 37311d3964da..640f822fa82a 100644 --- a/devtools/topology.c +++ b/devtools/topology.c @@ -270,7 +270,7 @@ int main(int argc, char *argv[]) opt_usage_exit_fail("Expect 3 arguments"); tstart = time_mono(); - map = gossmap_load(NULL, argv[1]); + map = gossmap_load(NULL, argv[1], NULL); if (!map) err(1, "Loading gossip store %s", argv[1]); tstop = time_mono(); diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 3bad3e8264cb..b8f4387eaf21 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -462,12 +462,18 @@ static struct command_result *sendonionmsg_done(struct command *cmd, static void init_gossmap(struct plugin *plugin) { + size_t num_cupdates_rejected; global_gossmap = notleak_with_children(gossmap_load(NULL, - GOSSIP_STORE_FILENAME)); + GOSSIP_STORE_FILENAME, + &num_cupdates_rejected)); if (!global_gossmap) plugin_err(plugin, "Could not load gossmap %s: %s", GOSSIP_STORE_FILENAME, strerror(errno)); + if (num_cupdates_rejected) + plugin_log(plugin, LOG_DBG, + "gossmap ignored %zu channel updates", + num_cupdates_rejected); } static struct gossmap *get_gossmap(struct plugin *plugin) @@ -475,7 +481,7 @@ static struct gossmap *get_gossmap(struct plugin *plugin) if (!global_gossmap) init_gossmap(plugin); else - gossmap_refresh(global_gossmap); + gossmap_refresh(global_gossmap, NULL); return global_gossmap; } diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index f044cccf5f89..7ade24b932b1 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -17,12 +17,18 @@ static struct gossmap *global_gossmap; static void init_gossmap(struct plugin *plugin) { + size_t num_channel_updates_rejected; global_gossmap = notleak_with_children(gossmap_load(NULL, - GOSSIP_STORE_FILENAME)); + GOSSIP_STORE_FILENAME, + &num_channel_updates_rejected)); if (!global_gossmap) plugin_err(plugin, "Could not load gossmap %s: %s", GOSSIP_STORE_FILENAME, strerror(errno)); + if (num_channel_updates_rejected) + plugin_log(plugin, LOG_DBG, + "gossmap ignored %zu channel updates", + num_channel_updates_rejected); } struct gossmap *get_gossmap(struct plugin *plugin) @@ -30,7 +36,7 @@ struct gossmap *get_gossmap(struct plugin *plugin) if (!global_gossmap) init_gossmap(plugin); else - gossmap_refresh(global_gossmap); + gossmap_refresh(global_gossmap, NULL); return global_gossmap; } diff --git a/plugins/test/run-route-overlong.c b/plugins/test/run-route-overlong.c index 23c235e2a26d..4398cd90eb92 100644 --- a/plugins/test/run-route-overlong.c +++ b/plugins/test/run-route-overlong.c @@ -345,7 +345,7 @@ int main(void) assert(write(store_fd, &gossip_version, sizeof(gossip_version)) == sizeof(gossip_version)); - gossmap = gossmap_load(tmpctx, gossipfilename); + gossmap = gossmap_load(tmpctx, gossipfilename, NULL); for (size_t i = 0; i < NUM_NODES; i++) { struct privkey tmp; @@ -384,7 +384,7 @@ int main(void) 1 << i); } - assert(gossmap_refresh(gossmap)); + assert(gossmap_refresh(gossmap, NULL)); for (size_t i = ROUTING_MAX_HOPS; i > 2; i--) { struct gossmap_node *dst, *src; struct route_hop *r; diff --git a/plugins/topology.c b/plugins/topology.c index c58dfb219dda..4376e56e1150 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -27,7 +27,7 @@ static struct plugin *plugin; /* We load this on demand, since we can start before gossipd. */ static struct gossmap *get_gossmap(void) { - gossmap_refresh(global_gossmap); + gossmap_refresh(global_gossmap, NULL); return global_gossmap; } @@ -687,17 +687,24 @@ static struct command_result *json_listincoming(struct command *cmd, static const char *init(struct plugin *p, const char *buf UNUSED, const jsmntok_t *config UNUSED) { + size_t num_cupdates_rejected; + plugin = p; rpc_scan(p, "getinfo", 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)); + GOSSIP_STORE_FILENAME, + &num_cupdates_rejected)); if (!global_gossmap) plugin_err(plugin, "Could not load gossmap %s: %s", GOSSIP_STORE_FILENAME, strerror(errno)); + if (num_cupdates_rejected) + plugin_log(plugin, LOG_DBG, + "gossmap ignored %zu channel updates", + num_cupdates_rejected); return NULL; }