gossipd: put gossip_store pointer inside gossmap_manage.

It's actually the only one that uses it.  We also tweak the way
gossip_store handles failure: gossmap_manage now tells it when to
reset the corrupted store.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2025-02-10 14:55:31 +10:30 committed by Alex Myers
parent e440799b5e
commit 4f2a7039c6
9 changed files with 115 additions and 74 deletions

View file

@ -191,7 +191,7 @@ static bool upgrade_field(u8 oldversion,
* validity, but this code is written as simply and robustly as * validity, but this code is written as simply and robustly as
* possible! * possible!
* *
* Returns fd of new store. * Returns fd of new store, or -1 if it was grossly invalid.
*/ */
static int gossip_store_compact(struct daemon *daemon, static int gossip_store_compact(struct daemon *daemon,
u64 *total_len, u64 *total_len,
@ -398,19 +398,18 @@ rename_new:
return new_fd; return new_fd;
badmsg: badmsg:
/* We truncate */ /* Caller will presumably try gossip_store_reset. */
status_broken("gossip_store: %s (offset %"PRIu64"). Moving to %s.corrupt and truncating", status_broken("gossip_store: %s (offset %"PRIu64").", bad, cur_off);
bad, cur_off, GOSSIP_STORE_FILENAME); close(old_fd);
close(new_fd);
return -1;
}
void gossip_store_corrupt(void)
{
status_broken("gossip_store: Moving to %s.corrupt",
GOSSIP_STORE_FILENAME);
rename(GOSSIP_STORE_FILENAME, GOSSIP_STORE_FILENAME ".corrupt"); rename(GOSSIP_STORE_FILENAME, GOSSIP_STORE_FILENAME ".corrupt");
if (lseek(new_fd, 0, SEEK_SET) != 0
|| !write_all(new_fd, &version, sizeof(version))) {
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Overwriting new gossip_store file: %s",
strerror(errno));
}
*total_len = sizeof(version);
goto rename_new;
} }
struct gossip_store *gossip_store_new(const tal_t *ctx, struct gossip_store *gossip_store_new(const tal_t *ctx,
@ -423,6 +422,8 @@ struct gossip_store *gossip_store_new(const tal_t *ctx,
gs->daemon = daemon; gs->daemon = daemon;
*dying = tal_arr(ctx, struct chan_dying, 0); *dying = tal_arr(ctx, struct chan_dying, 0);
gs->fd = gossip_store_compact(daemon, &gs->len, populated, dying); gs->fd = gossip_store_compact(daemon, &gs->len, populated, dying);
if (gs->fd < 0)
return tal_free(gs);
tal_add_destructor(gs, gossip_store_destroy); tal_add_destructor(gs, gossip_store_destroy);
return gs; return gs;
} }

View file

@ -31,6 +31,8 @@ struct chan_dying {
* @daemon: the daemon context * @daemon: the daemon context
* @populated: set to false if store is empty/obviously partial. * @populated: set to false if store is empty/obviously partial.
* @dying: an array of channels we found dying markers for. * @dying: an array of channels we found dying markers for.
*
* Returns NULL on error.
*/ */
struct gossip_store *gossip_store_new(const tal_t *ctx, struct gossip_store *gossip_store_new(const tal_t *ctx,
struct daemon *daemon, struct daemon *daemon,
@ -38,10 +40,9 @@ struct gossip_store *gossip_store_new(const tal_t *ctx,
struct chan_dying **dying); struct chan_dying **dying);
/** /**
* Get the (refreshed!) gossmap from the gossip_store. * Move the old gossip store out the way. Log a broken message about it.
* @gs: gossip store
*/ */
struct gossmap *gossip_store_gossmap(struct gossip_store *gs); void gossip_store_corrupt(void);
/** /**
* Append a gossip message to the gossip_store * Append a gossip message to the gossip_store
@ -109,4 +110,5 @@ void gossip_store_set_timestamp(struct gossip_store *gs, u64 offset, u32 timesta
* For debugging. * For debugging.
*/ */
u64 gossip_store_len_written(const struct gossip_store *gs); u64 gossip_store_len_written(const struct gossip_store *gs);
#endif /* LIGHTNING_GOSSIPD_GOSSIP_STORE_H */ #endif /* LIGHTNING_GOSSIPD_GOSSIP_STORE_H */

View file

@ -282,12 +282,8 @@ handled_msg_errmsg:
err = NULL; err = NULL;
handled_msg: handled_msg:
if (err) { if (err)
queue_peer_msg(daemon, &source, take(err)); queue_peer_msg(daemon, &source, take(err));
} else {
/* Some peer gave us gossip, so we're not at zero. */
peer->daemon->gossip_store_populated = true;
}
} }
/*~ connectd's input handler is very simple. */ /*~ connectd's input handler is very simple. */
@ -401,7 +397,6 @@ bool timestamp_reasonable(const struct daemon *daemon, u32 timestamp)
static void gossip_init(struct daemon *daemon, const u8 *msg) static void gossip_init(struct daemon *daemon, const u8 *msg)
{ {
u32 *dev_gossip_time; u32 *dev_gossip_time;
struct chan_dying *dying;
if (!fromwire_gossipd_init(daemon, msg, if (!fromwire_gossipd_init(daemon, msg,
&chainparams, &chainparams,
@ -422,13 +417,8 @@ static void gossip_init(struct daemon *daemon, const u8 *msg)
tal_free(dev_gossip_time); tal_free(dev_gossip_time);
} }
daemon->gs = gossip_store_new(daemon,
daemon,
&daemon->gossip_store_populated,
&dying);
/* Gossmap manager starts up */ /* Gossmap manager starts up */
daemon->gm = gossmap_manage_new(daemon, daemon, take(dying)); daemon->gm = gossmap_manage_new(daemon, daemon);
/* Fire up the seeker! */ /* Fire up the seeker! */
daemon->seeker = new_seeker(daemon); daemon->seeker = new_seeker(daemon);

View file

@ -65,12 +65,6 @@ struct daemon {
/* Features lightningd told us to set. */ /* Features lightningd told us to set. */
struct feature_set *our_features; struct feature_set *our_features;
/* Gossip store */
struct gossip_store *gs;
/* Was there anything in the gossip store at startup? */
bool gossip_store_populated;
/* Override local time for gossip messages */ /* Override local time for gossip messages */
struct timeabs *dev_gossip_time; struct timeabs *dev_gossip_time;

View file

@ -66,6 +66,9 @@ struct gossmap_manage {
/* gossip map itself (access via gossmap_manage_get_gossmap, so it's fresh!) */ /* gossip map itself (access via gossmap_manage_get_gossmap, so it's fresh!) */
struct gossmap *raw_gossmap; struct gossmap *raw_gossmap;
/* The gossip_store, which writes to the gossip_store file */
struct gossip_store *gs;
/* Announcements we're checking, indexed by scid */ /* Announcements we're checking, indexed by scid */
struct cannounce_map pending_ann_map; struct cannounce_map pending_ann_map;
@ -87,6 +90,9 @@ struct gossmap_manage {
/* Occasional check for dead channels */ /* Occasional check for dead channels */
struct oneshot *prune_timer; struct oneshot *prune_timer;
/* Are we populated yet? */
bool gossip_store_populated;
}; };
/* Timer recursion */ /* Timer recursion */
@ -257,15 +263,15 @@ static void remove_channel(struct gossmap_manage *gm,
tal_free(map_del(&gm->early_ann_map, scid)); tal_free(map_del(&gm->early_ann_map, scid));
/* Put in tombstone marker. */ /* Put in tombstone marker. */
gossip_store_add(gm->daemon->gs, gossip_store_add(gm->gs,
towire_gossip_store_delete_chan(tmpctx, scid), towire_gossip_store_delete_chan(tmpctx, scid),
0); 0);
/* Delete from store */ /* Delete from store */
gossip_store_del(gm->daemon->gs, chan->cann_off, WIRE_CHANNEL_ANNOUNCEMENT); gossip_store_del(gm->gs, chan->cann_off, WIRE_CHANNEL_ANNOUNCEMENT);
for (int dir = 0; dir < 2; dir++) { for (int dir = 0; dir < 2; dir++) {
if (gossmap_chan_set(chan, dir)) if (gossmap_chan_set(chan, dir))
gossip_store_del(gm->daemon->gs, chan->cupdate_off[dir], WIRE_CHANNEL_UPDATE); gossip_store_del(gm->gs, chan->cupdate_off[dir], WIRE_CHANNEL_UPDATE);
} }
/* Check for node_announcements which should no longer be there */ /* Check for node_announcements which should no longer be there */
@ -285,7 +291,7 @@ static void remove_channel(struct gossmap_manage *gm,
/* Last channel? Delete node announce */ /* Last channel? Delete node announce */
if (node->num_chans == 1) { if (node->num_chans == 1) {
gossip_store_del(gm->daemon->gs, node->nann_off, WIRE_NODE_ANNOUNCEMENT); gossip_store_del(gm->gs, node->nann_off, WIRE_NODE_ANNOUNCEMENT);
continue; continue;
} }
@ -297,10 +303,10 @@ static void remove_channel(struct gossmap_manage *gm,
/* To maintain order, delete and re-add node_announcement */ /* To maintain order, delete and re-add node_announcement */
nannounce = gossmap_node_get_announce(tmpctx, gossmap, node); nannounce = gossmap_node_get_announce(tmpctx, gossmap, node);
timestamp = gossip_store_get_timestamp(gm->daemon->gs, node->nann_off); timestamp = gossip_store_get_timestamp(gm->gs, node->nann_off);
gossip_store_del(gm->daemon->gs, node->nann_off, WIRE_NODE_ANNOUNCEMENT); gossip_store_del(gm->gs, node->nann_off, WIRE_NODE_ANNOUNCEMENT);
offset = gossip_store_add(gm->daemon->gs, nannounce, timestamp); offset = gossip_store_add(gm->gs, nannounce, timestamp);
} else { } else {
/* Are all remaining channels dying but we weren't? /* Are all remaining channels dying but we weren't?
* Can happen if we removed this channel immediately * Can happen if we removed this channel immediately
@ -314,7 +320,7 @@ static void remove_channel(struct gossmap_manage *gm,
/* Be sure to set DYING flag when we move (ignore current /* Be sure to set DYING flag when we move (ignore current
* channel, we haven't reloaded gossmap yet!) */ * channel, we haven't reloaded gossmap yet!) */
if (all_node_channels_dying(gossmap, node, chan)) if (all_node_channels_dying(gossmap, node, chan))
gossip_store_set_flag(gm->daemon->gs, offset, gossip_store_set_flag(gm->gs, offset,
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_NODE_ANNOUNCEMENT); WIRE_NODE_ANNOUNCEMENT);
} }
@ -419,14 +425,43 @@ static void gossmap_logcb(struct daemon *daemon,
va_end(ap); va_end(ap);
} }
static bool setup_gossmap(struct gossmap_manage *gm,
struct daemon *daemon,
struct chan_dying **dying)
{
*dying = NULL;
/* This compacts, and creates if necessary */
gm->gs = gossip_store_new(gm,
daemon,
&gm->gossip_store_populated,
dying);
if (!gm->gs)
return false;
/* This actually loads it into memory */
gm->raw_gossmap = gossmap_load(gm, GOSSIP_STORE_FILENAME,
gossmap_logcb, daemon);
if (!gm->raw_gossmap) {
gm->gs = tal_free(gm->gs);
return false;
}
return true;
}
struct gossmap_manage *gossmap_manage_new(const tal_t *ctx, struct gossmap_manage *gossmap_manage_new(const tal_t *ctx,
struct daemon *daemon, struct daemon *daemon)
struct chan_dying *dying_channels TAKES)
{ {
struct gossmap_manage *gm = tal(ctx, struct gossmap_manage); struct gossmap_manage *gm = tal(ctx, struct gossmap_manage);
gm->raw_gossmap = gossmap_load(gm, GOSSIP_STORE_FILENAME, if (!setup_gossmap(gm, daemon, &gm->dying_channels)) {
gossmap_logcb, daemon); tal_free(gm->dying_channels);
gossip_store_corrupt();
if (!setup_gossmap(gm, daemon, &gm->dying_channels))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could not re-initialize %s", GOSSIP_STORE_FILENAME);
}
assert(gm->gs);
assert(gm->raw_gossmap); assert(gm->raw_gossmap);
gm->daemon = daemon; gm->daemon = daemon;
@ -436,7 +471,6 @@ struct gossmap_manage *gossmap_manage_new(const tal_t *ctx,
gm->early_cupdates = tal_arr(gm, struct pending_cupdate *, 0); gm->early_cupdates = tal_arr(gm, struct pending_cupdate *, 0);
gm->pending_nannounces = tal_arr(gm, struct pending_nannounce *, 0); gm->pending_nannounces = tal_arr(gm, struct pending_nannounce *, 0);
gm->txf = txout_failures_new(gm, daemon); gm->txf = txout_failures_new(gm, daemon);
gm->dying_channels = tal_dup_talarr(gm, struct chan_dying, dying_channels);
start_prune_timer(gm); start_prune_timer(gm);
return gm; return gm;
@ -477,9 +511,9 @@ static void node_announcements_not_dying(struct gossmap_manage *gm,
struct gossmap_node *n = gossmap_find_node(gossmap, &pca->node_id[i]); struct gossmap_node *n = gossmap_find_node(gossmap, &pca->node_id[i]);
if (!n || !gossmap_node_announced(n)) if (!n || !gossmap_node_announced(n))
continue; continue;
if (gossip_store_get_flags(gm->daemon->gs, n->nann_off, WIRE_NODE_ANNOUNCEMENT) if (gossip_store_get_flags(gm->gs, n->nann_off, WIRE_NODE_ANNOUNCEMENT)
& GOSSIP_STORE_DYING_BIT) { & GOSSIP_STORE_DYING_BIT) {
gossip_store_clear_flag(gm->daemon->gs, n->nann_off, gossip_store_clear_flag(gm->gs, n->nann_off,
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_NODE_ANNOUNCEMENT); WIRE_NODE_ANNOUNCEMENT);
} }
@ -555,8 +589,8 @@ const char *gossmap_manage_channel_announcement(const tal_t *ctx,
&& !map_get(&gm->pending_ann_map, scid) && !map_get(&gm->pending_ann_map, scid)
&& !map_get(&gm->early_ann_map, scid)) { && !map_get(&gm->early_ann_map, scid)) {
/* Set with timestamp 0 (we will update once we have a channel_update) */ /* Set with timestamp 0 (we will update once we have a channel_update) */
gossip_store_add(gm->daemon->gs, announce, 0); gossip_store_add(gm->gs, announce, 0);
gossip_store_add(gm->daemon->gs, gossip_store_add(gm->gs,
towire_gossip_store_channel_amount(tmpctx, *known_amount), 0); towire_gossip_store_channel_amount(tmpctx, *known_amount), 0);
node_announcements_not_dying(gm, gossmap, pca); node_announcements_not_dying(gm, gossmap, pca);
@ -662,7 +696,7 @@ void gossmap_manage_handle_get_txout_reply(struct gossmap_manage *gm, const u8 *
status_broken("Redundant channel_announce for scid %s at off %"PRIu64" (gossmap %"PRIu64"/%"PRIu64", store %"PRIu64")", status_broken("Redundant channel_announce for scid %s at off %"PRIu64" (gossmap %"PRIu64"/%"PRIu64", store %"PRIu64")",
fmt_short_channel_id(tmpctx, scid), chan->cann_off, fmt_short_channel_id(tmpctx, scid), chan->cann_off,
before_length_processed, before_total_length, before_length_processed, before_total_length,
gossip_store_len_written(gm->daemon->gs)); gossip_store_len_written(gm->gs));
goto out; goto out;
} else { } else {
u64 after_length_processed, after_total_length; u64 after_length_processed, after_total_length;
@ -675,14 +709,14 @@ void gossmap_manage_handle_get_txout_reply(struct gossmap_manage *gm, const u8 *
fmt_short_channel_id(tmpctx, scid), chan->cann_off, fmt_short_channel_id(tmpctx, scid), chan->cann_off,
before_length_processed, before_total_length, before_length_processed, before_total_length,
after_length_processed, after_total_length, after_length_processed, after_total_length,
gossip_store_len_written(gm->daemon->gs)); gossip_store_len_written(gm->gs));
goto out; goto out;
} }
} }
/* Set with timestamp 0 (we will update once we have a channel_update) */ /* Set with timestamp 0 (we will update once we have a channel_update) */
gossip_store_add(gm->daemon->gs, pca->channel_announcement, 0); gossip_store_add(gm->gs, pca->channel_announcement, 0);
gossip_store_add(gm->daemon->gs, gossip_store_add(gm->gs,
towire_gossip_store_channel_amount(tmpctx, sat), 0); towire_gossip_store_channel_amount(tmpctx, sat), 0);
/* If we looking specifically for this, we no longer are. */ /* If we looking specifically for this, we no longer are. */
@ -768,7 +802,7 @@ static const char *process_channel_update(const tal_t *ctx,
/* Do we have same or earlier update? */ /* Do we have same or earlier update? */
if (gossmap_chan_set(chan, dir)) { if (gossmap_chan_set(chan, dir)) {
u32 prev_timestamp u32 prev_timestamp
= gossip_store_get_timestamp(gm->daemon->gs, chan->cupdate_off[dir]); = gossip_store_get_timestamp(gm->gs, chan->cupdate_off[dir]);
if (prev_timestamp >= timestamp) { if (prev_timestamp >= timestamp) {
status_debug("Too-old update for %s", status_debug("Too-old update for %s",
fmt_short_channel_id(tmpctx, scid)); fmt_short_channel_id(tmpctx, scid));
@ -779,15 +813,15 @@ static const char *process_channel_update(const tal_t *ctx,
/* Is this the first update in either direction? If so, /* Is this the first update in either direction? If so,
* rewrite channel_announcement so timestamp is correct. */ * rewrite channel_announcement so timestamp is correct. */
if (!gossmap_chan_set(chan, !dir)) if (!gossmap_chan_set(chan, !dir))
gossip_store_set_timestamp(gm->daemon->gs, chan->cann_off, timestamp); gossip_store_set_timestamp(gm->gs, chan->cann_off, timestamp);
} }
/* OK, apply the new one */ /* OK, apply the new one */
offset = gossip_store_add(gm->daemon->gs, update, timestamp); offset = gossip_store_add(gm->gs, update, timestamp);
/* If channel is dying, make sure update is also marked dying! */ /* If channel is dying, make sure update is also marked dying! */
if (gossmap_chan_is_dying(gossmap, chan)) { if (gossmap_chan_is_dying(gossmap, chan)) {
gossip_store_set_flag(gm->daemon->gs, gossip_store_set_flag(gm->gs,
offset, offset,
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_CHANNEL_UPDATE); WIRE_CHANNEL_UPDATE);
@ -795,7 +829,7 @@ static const char *process_channel_update(const tal_t *ctx,
/* Now delete old */ /* Now delete old */
if (gossmap_chan_set(chan, dir)) if (gossmap_chan_set(chan, dir))
gossip_store_del(gm->daemon->gs, chan->cupdate_off[dir], WIRE_CHANNEL_UPDATE); gossip_store_del(gm->gs, chan->cupdate_off[dir], WIRE_CHANNEL_UPDATE);
/* Is this an update for an incoming channel? If so, keep lightningd updated */ /* Is this an update for an incoming channel? If so, keep lightningd updated */
gossmap_node_get_id(gossmap, gossmap_node_get_id(gossmap,
@ -818,6 +852,9 @@ static const char *process_channel_update(const tal_t *ctx,
dir, dir,
channel_flags & ROUTING_FLAGS_DISABLED ? "DISABLED" : "ACTIVE"); channel_flags & ROUTING_FLAGS_DISABLED ? "DISABLED" : "ACTIVE");
/* We're off zero, at least! */
gm->gossip_store_populated = true;
return NULL; return NULL;
} }
@ -936,7 +973,7 @@ static void process_node_announcement(struct gossmap_manage *gm,
/* Do we have a later one? If so, ignore */ /* Do we have a later one? If so, ignore */
if (gossmap_node_announced(node)) { if (gossmap_node_announced(node)) {
u32 prev_timestamp u32 prev_timestamp
= gossip_store_get_timestamp(gm->daemon->gs, node->nann_off); = gossip_store_get_timestamp(gm->gs, node->nann_off);
if (prev_timestamp >= timestamp) { if (prev_timestamp >= timestamp) {
/* Too old, ignore */ /* Too old, ignore */
return; return;
@ -944,17 +981,17 @@ static void process_node_announcement(struct gossmap_manage *gm,
} }
/* OK, apply the new one */ /* OK, apply the new one */
offset = gossip_store_add(gm->daemon->gs, nannounce, timestamp); offset = gossip_store_add(gm->gs, nannounce, timestamp);
/* If all channels are dying, make sure this is marked too. */ /* If all channels are dying, make sure this is marked too. */
if (all_node_channels_dying(gossmap, node, NULL)) { if (all_node_channels_dying(gossmap, node, NULL)) {
gossip_store_set_flag(gm->daemon->gs, offset, gossip_store_set_flag(gm->gs, offset,
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_NODE_ANNOUNCEMENT); WIRE_NODE_ANNOUNCEMENT);
} }
/* Now delete old */ /* Now delete old */
if (gossmap_node_announced(node)) if (gossmap_node_announced(node))
gossip_store_del(gm->daemon->gs, node->nann_off, WIRE_NODE_ANNOUNCEMENT); gossip_store_del(gm->gs, node->nann_off, WIRE_NODE_ANNOUNCEMENT);
/* Used to evaluate gossip peers' performance */ /* Used to evaluate gossip peers' performance */
peer_supplied_good_gossip(gm->daemon, source_peer, 1); peer_supplied_good_gossip(gm->daemon, source_peer, 1);
@ -1231,7 +1268,7 @@ void gossmap_manage_new_block(struct gossmap_manage *gm, u32 new_blockheight)
* in particular, we might move a node_announcement twice! */ * in particular, we might move a node_announcement twice! */
gossmap = gossmap_manage_get_gossmap(gm); gossmap = gossmap_manage_get_gossmap(gm);
kill_spent_channel(gm, gossmap, gm->dying_channels[i].scid); kill_spent_channel(gm, gossmap, gm->dying_channels[i].scid);
gossip_store_del(gm->daemon->gs, gossip_store_del(gm->gs,
gm->dying_channels[i].gossmap_offset, gm->dying_channels[i].gossmap_offset,
WIRE_GOSSIP_STORE_CHAN_DYING); WIRE_GOSSIP_STORE_CHAN_DYING);
tal_arr_remove(&gm->dying_channels, i); tal_arr_remove(&gm->dying_channels, i);
@ -1280,11 +1317,11 @@ void gossmap_manage_channel_spent(struct gossmap_manage *gm,
/* Save to gossip_store in case we restart */ /* Save to gossip_store in case we restart */
msg = towire_gossip_store_chan_dying(tmpctx, cd.scid, cd.deadline); msg = towire_gossip_store_chan_dying(tmpctx, cd.scid, cd.deadline);
cd.gossmap_offset = gossip_store_add(gm->daemon->gs, msg, 0); cd.gossmap_offset = gossip_store_add(gm->gs, msg, 0);
tal_arr_expand(&gm->dying_channels, cd); tal_arr_expand(&gm->dying_channels, cd);
/* Mark it dying, so we don't gossip it */ /* Mark it dying, so we don't gossip it */
gossip_store_set_flag(gm->daemon->gs, chan->cann_off, gossip_store_set_flag(gm->gs, chan->cann_off,
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_CHANNEL_ANNOUNCEMENT); WIRE_CHANNEL_ANNOUNCEMENT);
/* Channel updates too! */ /* Channel updates too! */
@ -1292,7 +1329,7 @@ void gossmap_manage_channel_spent(struct gossmap_manage *gm,
if (!gossmap_chan_set(chan, dir)) if (!gossmap_chan_set(chan, dir))
continue; continue;
gossip_store_set_flag(gm->daemon->gs, gossip_store_set_flag(gm->gs,
chan->cupdate_off[dir], chan->cupdate_off[dir],
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_CHANNEL_UPDATE); WIRE_CHANNEL_UPDATE);
@ -1312,7 +1349,7 @@ void gossmap_manage_channel_spent(struct gossmap_manage *gm,
/* Are all (other) channels dying? */ /* Are all (other) channels dying? */
if (all_node_channels_dying(gossmap, n, chan)) { if (all_node_channels_dying(gossmap, n, chan)) {
gossip_store_set_flag(gm->daemon->gs, gossip_store_set_flag(gm->gs,
n->nann_off, n->nann_off,
GOSSIP_STORE_DYING_BIT, GOSSIP_STORE_DYING_BIT,
WIRE_NODE_ANNOUNCEMENT); WIRE_NODE_ANNOUNCEMENT);
@ -1384,3 +1421,8 @@ void gossmap_manage_tell_lightningd_locals(struct daemon *daemon,
take(towire_gossipd_init_nannounce(NULL, take(towire_gossipd_init_nannounce(NULL,
nannounce))); nannounce)));
} }
bool gossmap_manage_populated(const struct gossmap_manage *gm)
{
return gm->gossip_store_populated;
}

View file

@ -7,8 +7,7 @@ struct gossmap_manage;
struct chan_dying; struct chan_dying;
struct gossmap_manage *gossmap_manage_new(const tal_t *ctx, struct gossmap_manage *gossmap_manage_new(const tal_t *ctx,
struct daemon *daemon, struct daemon *daemon);
struct chan_dying *dying_channels TAKES);
/** /**
* gossmap_manage_channel_announcement: process an incoming channel_announcement * gossmap_manage_channel_announcement: process an incoming channel_announcement
@ -103,4 +102,13 @@ struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm);
*/ */
void gossmap_manage_tell_lightningd_locals(struct daemon *daemon, void gossmap_manage_tell_lightningd_locals(struct daemon *daemon,
struct gossmap_manage *gm); struct gossmap_manage *gm);
/**
* gossmap_manage_populated - do we have some gossip?
* @gm: the gossmap_manage context.
*
*
* The seeker uses this if we're at startup and want complete gossip.
*/
bool gossmap_manage_populated(const struct gossmap_manage *gm);
#endif /* LIGHTNING_GOSSIPD_GOSSMAP_MANAGE_H */ #endif /* LIGHTNING_GOSSIPD_GOSSMAP_MANAGE_H */

View file

@ -236,7 +236,7 @@ static void enable_gossip_stream(struct seeker *seeker, struct peer *peer,
u8 *msg; u8 *msg;
/* If we have no gossip, always ask for everything */ /* If we have no gossip, always ask for everything */
if (!peer->daemon->gossip_store_populated) if (!gossmap_manage_populated(peer->daemon->gm))
ask_for_all = true; ask_for_all = true;
/* Modern timestamp_filter is a trinary: 0 = all, FFFFFFFF = none, /* Modern timestamp_filter is a trinary: 0 = all, FFFFFFFF = none,

View file

@ -68,6 +68,9 @@ struct gossmap_node *gossmap_first_node(const struct gossmap *map UNNEEDED)
/* Generated stub for gossmap_manage_get_gossmap */ /* Generated stub for gossmap_manage_get_gossmap */
struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm UNNEEDED) struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm UNNEEDED)
{ fprintf(stderr, "gossmap_manage_get_gossmap called!\n"); abort(); } { fprintf(stderr, "gossmap_manage_get_gossmap called!\n"); abort(); }
/* Generated stub for gossmap_manage_populated */
bool gossmap_manage_populated(const struct gossmap_manage *gm UNNEEDED)
{ fprintf(stderr, "gossmap_manage_populated called!\n"); abort(); }
/* Generated stub for gossmap_max_node_idx */ /* Generated stub for gossmap_max_node_idx */
u32 gossmap_max_node_idx(const struct gossmap *map UNNEEDED) u32 gossmap_max_node_idx(const struct gossmap *map UNNEEDED)
{ fprintf(stderr, "gossmap_max_node_idx called!\n"); abort(); } { fprintf(stderr, "gossmap_max_node_idx called!\n"); abort(); }

View file

@ -1283,7 +1283,7 @@ def test_gossip_store_load_announce_before_update(node_factory):
def test_gossip_store_load_amount_truncated(node_factory): def test_gossip_store_load_amount_truncated(node_factory):
"""Make sure we can read canned gossip store with truncated amount""" """Make sure we can read canned gossip store with truncated amount"""
l1 = node_factory.get_node(start=False, broken_log=r'gossip_store: channel_announcement without amount \(offset 1\). Moving to gossip_store.corrupt and truncating|plugin-cln-renepay:.*unable to fetch channel capacity') l1 = node_factory.get_node(start=False, broken_log=r'gossip_store: channel_announcement without amount \(offset 1\)|Moving to gossip_store.corrupt|plugin-cln-renepay:.*unable to fetch channel capacity')
with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), 'wb') as f: with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), 'wb') as f:
f.write(bytearray.fromhex("0c" # GOSSIP_STORE_VERSION f.write(bytearray.fromhex("0c" # GOSSIP_STORE_VERSION
"000001b0" # len "000001b0" # len
@ -1294,8 +1294,9 @@ def test_gossip_store_load_amount_truncated(node_factory):
l1.start() l1.start()
# May preceed the Started msg waited for in 'start'. # May preceed the Started msg waited for in 'start'.
wait_for(lambda: l1.daemon.is_in_log(r'\*\*BROKEN\*\* gossipd: gossip_store: channel_announcement without amount \(offset 1\). Moving to gossip_store.corrupt and truncating')) wait_for(lambda: l1.daemon.is_in_log(r'\*\*BROKEN\*\* gossipd: gossip_store: channel_announcement without amount \(offset 1\)\.'))
wait_for(lambda: l1.daemon.is_in_log(r'gossip_store: Read 0/0/0/0 cannounce/cupdate/nannounce/delete from store in 467 bytes, now 1 bytes \(populated=false\)')) wait_for(lambda: l1.daemon.is_in_log(r'\*\*BROKEN\*\* gossipd: gossip_store: Moving to gossip_store.corrupt'))
wait_for(lambda: l1.daemon.is_in_log(r'gossip_store: Read 0/0/0/0 cannounce/cupdate/nannounce/delete from store in 0 bytes, now 1 bytes \(populated=false\)'))
assert os.path.exists(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store.corrupt')) assert os.path.exists(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store.corrupt'))