gossmap: add callback for gossipd to see dying messages.

gossmap doesn't care, so gossipd currently has to iterate through the
store to find them at startup.  Create a callback for gossipd to use
instead.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2026-02-12 09:18:10 +10:30
parent e8fd235d4e
commit 1ad8ca9603
7 changed files with 98 additions and 15 deletions

View File

@@ -641,8 +641,47 @@ static void node_announcement(struct gossmap *map, u64 nann_off)
n->nann_off = nann_off;
}
static bool report_dying_cb(struct gossmap *map,
u64 dying_off,
u16 msglen,
void (*dyingcb)(struct short_channel_id scid,
u32 blockheight,
u64 offset,
void *cb_arg),
void *cb_arg)
{
struct short_channel_id scid;
u32 blockheight;
u8 *msg;
msg = tal_arr(NULL, u8, msglen);
map_copy(map, dying_off, msg, msglen);
if (!fromwire_gossip_store_chan_dying(msg, &scid, &blockheight)) {
map->logcb(map->cbarg,
LOG_BROKEN,
"Invalid chan_dying message @%"PRIu64
"/%"PRIu64": %s",
dying_off, map->map_size, msglen,
tal_hex(tmpctx, msg));
tal_free(msg);
return false;
}
tal_free(msg);
dyingcb(scid, blockheight, dying_off, cb_arg);
return true;
}
/* Mutual recursion */
static bool map_catchup(struct gossmap *map, bool must_be_clean, bool *changed);
static bool map_catchup(struct gossmap *map,
void (*dyingcb)(struct short_channel_id scid,
u32 blockheight,
u64 offset,
void *cb_arg),
void *cb_arg,
bool must_be_clean,
bool *changed);
static void init_map_structs(struct gossmap *map)
{
@@ -724,7 +763,7 @@ static bool reopen_store(struct gossmap *map, u64 ended_off)
map->generation++;
/* Now do reload. */
map_catchup(map, false, &changed);
map_catchup(map, NULL, NULL, false, &changed);
return changed;
}
@@ -744,7 +783,14 @@ static bool csum_matches(const struct gossmap *map,
}
/* Returns false only if must_be_clean is true. */
static bool map_catchup(struct gossmap *map, bool must_be_clean, bool *changed)
static bool map_catchup(struct gossmap *map,
void (*dyingcb)(struct short_channel_id scid,
u32 blockheight,
u64 offset,
void *cb_arg),
void *cb_arg,
bool must_be_clean,
bool *changed)
{
size_t reclen, num_bad_cupdates = 0;
@@ -830,6 +876,8 @@ static bool map_catchup(struct gossmap *map, bool must_be_clean, bool *changed)
/* We absorbed this in add_channel; ignore */
continue;
} else if (type == WIRE_GOSSIP_STORE_CHAN_DYING) {
if (dyingcb && !report_dying_cb(map, off, msglen, dyingcb, cb_arg))
return false;
/* We don't really care until it's deleted */
continue;
} else if (type == WIRE_GOSSIP_STORE_UUID) {
@@ -856,7 +904,13 @@ static bool map_catchup(struct gossmap *map, bool must_be_clean, bool *changed)
return true;
}
static bool load_gossip_store(struct gossmap *map, bool must_be_clean)
static bool load_gossip_store(struct gossmap *map,
void (*dyingcb)(struct short_channel_id scid,
u32 blockheight,
u64 offset,
void *cb_arg),
void *cb_arg,
bool must_be_clean)
{
bool updated;
@@ -880,7 +934,7 @@ static bool load_gossip_store(struct gossmap *map, bool must_be_clean)
init_map_structs(map);
map->map_end = 1;
return map_catchup(map, must_be_clean, &updated);
return map_catchup(map, dyingcb, cb_arg, must_be_clean, &updated);
}
static void destroy_map(struct gossmap *map)
@@ -1292,7 +1346,7 @@ bool gossmap_refresh(struct gossmap *map)
}
}
map_catchup(map, false, &changed);
map_catchup(map, NULL, NULL, false, &changed);
return changed;
}
@@ -1319,7 +1373,11 @@ struct gossmap *gossmap_load_(const tal_t *ctx,
enum log_level level,
const char *fmt,
...),
void *cbarg)
void (*dyingcb)(struct short_channel_id scid,
u32 blockheight,
u64 offset,
void *cb_arg),
void *cb_arg)
{
map = tal(ctx, struct gossmap);
map->generation = 0;
@@ -1331,15 +1389,15 @@ struct gossmap *gossmap_load_(const tal_t *ctx,
map->logcb = logcb;
else
map->logcb = log_stderr;
map->cbarg = cbarg;
map->cbarg = cb_arg;
tal_add_destructor(map, destroy_map);
if (!load_gossip_store(map, expected_len != 0))
if (!load_gossip_store(map, dyingcb, cb_arg, expected_len != 0))
return tal_free(map);
if (expected_len != 0
&& (map->map_size != map->map_end
|| map->map_size != expected_len)) {
logcb(cbarg, LOG_BROKEN,
logcb(cb_arg, LOG_BROKEN,
"gossip_store only processed %"PRIu64
" bytes of %"PRIu64" (expected %"PRIu64")",
map->map_end, map->map_size, expected_len);

View File

@@ -46,17 +46,21 @@ struct gossmap_chan {
enum log_level, \
const char *fmt, \
...), \
(cbarg))
NULL, (cbarg))
/* If we're the author of the gossmap, it should have no redundant records, corruption, etc.
* So this fails if that's not the case. */
#define gossmap_load_initial(ctx, filename, expected_len, logcb, cbarg) \
#define gossmap_load_initial(ctx, filename, expected_len, logcb, dyingcb, cb_arg) \
gossmap_load_((ctx), (filename), (expected_len), \
typesafe_cb_postargs(void, void *, (logcb), (cbarg), \
typesafe_cb_postargs(void, void *, (logcb), (cb_arg), \
enum log_level, \
const char *fmt, \
...), \
(cbarg))
typesafe_cb_preargs(void, void *, (dyingcb), (cb_arg), \
struct short_channel_id, \
u32, \
u64), \
(cb_arg))
struct gossmap *gossmap_load_(const tal_t *ctx,
const char *filename,
@@ -65,6 +69,10 @@ struct gossmap *gossmap_load_(const tal_t *ctx,
enum log_level level,
const char *fmt,
...),
void (*dyingcb)(struct short_channel_id scid,
u32 blockheight,
u64 offset,
void *cb_arg),
void *cb_arg);
/* Disable mmap. Noop if already disabled. */
@@ -305,4 +313,5 @@ u64 gossmap_lengths(const struct gossmap *map, u64 *total);
/* Debugging: connectd wants to enumerate fds */
int gossmap_fd(const struct gossmap *map);
#endif /* LIGHTNING_COMMON_GOSSMAP_H */

View File

@@ -19,6 +19,9 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct channel_id *channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_channel_id called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_chan_dying */
bool fromwire_gossip_store_chan_dying(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED, u32 *blockheight UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_chan_dying called!\n"); abort(); }
/* Generated stub for sciddir_or_pubkey_from_node_id */
bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED,
const struct node_id *node_id UNNEEDED)

View File

@@ -19,6 +19,9 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct channel_id *channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_channel_id called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_chan_dying */
bool fromwire_gossip_store_chan_dying(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED, u32 *blockheight UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_chan_dying called!\n"); abort(); }
/* Generated stub for sciddir_or_pubkey_from_node_id */
bool sciddir_or_pubkey_from_node_id(struct sciddir_or_pubkey *sciddpk UNNEEDED,
const struct node_id *node_id UNNEEDED)

View File

@@ -10,12 +10,16 @@ int unused_main(int argc, char *argv[]);
#include <common/memleak.h>
#include <common/onionreply.h>
#include <common/setup.h>
#include <common/gossip_store_wiregen.h>
#include <stdio.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire_connectd_dev_set_max_scids_encode_size */
bool fromwire_connectd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED)
{ fprintf(stderr, "fromwire_connectd_dev_set_max_scids_encode_size called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_chan_dying */
bool fromwire_gossip_store_chan_dying(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED, u32 *blockheight UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_chan_dying called!\n"); abort(); }
/* Generated stub for get_gossmap */
struct gossmap *get_gossmap(struct daemon *daemon UNNEEDED)
{ fprintf(stderr, "get_gossmap called!\n"); abort(); }

View File

@@ -464,7 +464,9 @@ static bool setup_gossmap(struct gossmap_manage *gm,
/* This actually loads it into memory, with strict checks. */
gm->raw_gossmap = gossmap_load_initial(gm, GOSSIP_STORE_FILENAME,
expected_len,
gossmap_logcb, daemon);
gossmap_logcb,
NULL,
daemon);
if (!gm->raw_gossmap) {
gm->gs = tal_free(gm->gs);
return false;

View File

@@ -9,6 +9,7 @@
#include <common/sciddir_or_pubkey.h>
#include <common/setup.h>
#include <common/wireaddr.h>
#include <common/gossip_store_wiregen.h>
#include <stdio.h>
/* AUTOGENERATED MOCKS START */
@@ -19,6 +20,9 @@ struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id
struct peer *first_random_peer(struct daemon *daemon UNNEEDED,
struct peer_node_id_map_iter *it UNNEEDED)
{ fprintf(stderr, "first_random_peer called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_chan_dying */
bool fromwire_gossip_store_chan_dying(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED, u32 *blockheight UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_chan_dying called!\n"); abort(); }
/* Generated stub for gossmap_manage_get_gossmap */
struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm UNNEEDED)
{ fprintf(stderr, "gossmap_manage_get_gossmap called!\n"); abort(); }