mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 15:00:34 +01:00
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:
parent
e440799b5e
commit
4f2a7039c6
9 changed files with 115 additions and 74 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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'))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue