gossipd: new routines to support gossmap compatibility.

gossip_store_del - takes a gossmap-style offset-of-msg not offset-of-hdr.
gossip_store_flag: set an arbitrary flag on a gossip_store hdr.
gossip_store_get_timestamp/gossip_store_set_timestamp: access gossip_store hdr.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-01-31 14:49:33 +10:30
parent 37ccca5d69
commit 870c996628
3 changed files with 130 additions and 27 deletions

View file

@ -667,7 +667,7 @@ void gossip_store_mark_dying(struct gossip_store *gs,
}
/* Returns index of following entry. */
static u32 delete_by_index(struct gossip_store *gs, u32 index, int type)
static u32 flag_by_index(struct gossip_store *gs, u32 index, int flag, int type)
{
struct {
beint16_t beflags;
@ -682,28 +682,28 @@ static u32 delete_by_index(struct gossip_store *gs, u32 index, int type)
/* FIXME: debugging a gs->len overrun issue reported in #6270 */
if (pread(gs->fd, &hdr, sizeof(hdr), index) != sizeof(hdr)) {
status_broken("gossip_store overrun during delete @%u type: %i"
" gs->len: %"PRIu64, index, type, gs->len);
status_broken("gossip_store pread fail during flag %u @%u type: %i"
" gs->len: %"PRIu64, flag, index, type, gs->len);
return index;
}
if (index + sizeof(struct gossip_hdr) +
be16_to_cpu(hdr.belen) > gs->len) {
status_broken("gossip_store overrun during delete @%u type: %i"
" gs->len: %"PRIu64, index, type, gs->len);
status_broken("gossip_store overrun during flag-%u @%u type: %i"
" gs->len: %"PRIu64, flag, index, type, gs->len);
return index;
}
const u8 *msg = gossip_store_get(tmpctx, gs, index);
if(fromwire_peektype(msg) != type) {
status_broken("asked to delete type %i @%u but store contains "
status_broken("asked to flag-%u type %i @%u but store contains "
"%i (gs->len=%"PRIu64"): %s",
type, index, fromwire_peektype(msg),
flag, type, index, fromwire_peektype(msg),
gs->len, tal_hex(tmpctx, msg));
return index;
}
assert((be16_to_cpu(hdr.beflags) & GOSSIP_STORE_DELETED_BIT) == 0);
hdr.beflags |= cpu_to_be16(GOSSIP_STORE_DELETED_BIT);
assert((be16_to_cpu(hdr.beflags) & flag) == 0);
hdr.beflags |= cpu_to_be16(flag);
if (pwrite(gs->fd, &hdr.beflags, sizeof(hdr.beflags), index) != sizeof(hdr.beflags))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed writing flags to delete @%u: %s",
@ -713,24 +713,45 @@ static u32 delete_by_index(struct gossip_store *gs, u32 index, int type)
return index + sizeof(struct gossip_hdr) + be16_to_cpu(hdr.belen);
}
void gossip_store_del(struct gossip_store *gs,
u64 offset,
int type)
{
u32 next_index;
assert(offset > sizeof(struct gossip_hdr));
next_index = flag_by_index(gs, offset - sizeof(struct gossip_hdr),
GOSSIP_STORE_DELETED_BIT,
type);
/* For a channel_announcement, we need to delete amount too */
if (type == WIRE_CHANNEL_ANNOUNCEMENT)
flag_by_index(gs, next_index,
GOSSIP_STORE_DELETED_BIT,
WIRE_GOSSIP_STORE_CHANNEL_AMOUNT);
}
void gossip_store_flag(struct gossip_store *gs,
u64 offset,
u16 flag,
int type)
{
assert(offset > sizeof(struct gossip_hdr));
flag_by_index(gs, offset - sizeof(struct gossip_hdr), flag, type);
}
void gossip_store_delete(struct gossip_store *gs,
struct broadcastable *bcast,
int type)
{
u32 next_index;
if (!bcast->index)
return;
next_index = delete_by_index(gs, bcast->index, type);
gossip_store_del(gs, bcast->index + sizeof(struct gossip_hdr), type);
/* Reset index. */
bcast->index = 0;
/* For a channel_announcement, we need to delete amount too */
if (type == WIRE_CHANNEL_ANNOUNCEMENT)
delete_by_index(gs, next_index,
WIRE_GOSSIP_STORE_CHANNEL_AMOUNT);
}
void gossip_store_mark_channel_deleted(struct gossip_store *gs,
@ -786,11 +807,26 @@ void gossip_store_mark_cupdate_zombie(struct gossip_store *gs,
mark_zombie(gs, bcast, WIRE_CHANNEL_UPDATE);
}
const u8 *gossip_store_get(const tal_t *ctx,
struct gossip_store *gs,
u64 offset)
u32 gossip_store_get_timestamp(struct gossip_store *gs, u64 offset)
{
struct gossip_hdr hdr;
assert(offset > sizeof(struct gossip_hdr));
if (pread(gs->fd, &hdr, sizeof(hdr), offset - sizeof(hdr)) != sizeof(hdr)) {
status_broken("gossip_store overrun during get_timestamp @%"PRIu64
" gs->len: %"PRIu64, offset, gs->len);
return 0;
}
return be32_to_cpu(hdr.timestamp);
}
static const u8 *gossip_store_get_with_hdr(const tal_t *ctx,
struct gossip_store *gs,
u64 offset,
struct gossip_hdr *hdr)
{
u32 msglen, checksum;
u8 *msg;
@ -798,28 +834,28 @@ const u8 *gossip_store_get(const tal_t *ctx,
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: can't access offset %"PRIu64,
offset);
if (pread(gs->fd, &hdr, sizeof(hdr), offset) != sizeof(hdr)) {
if (pread(gs->fd, hdr, sizeof(*hdr), offset) != sizeof(*hdr)) {
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: can't read hdr offset %"PRIu64
"/%"PRIu64": %s",
offset, gs->len, strerror(errno));
}
if (be16_to_cpu(hdr.flags) & GOSSIP_STORE_DELETED_BIT)
if (be16_to_cpu(hdr->flags) & GOSSIP_STORE_DELETED_BIT)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: get delete entry offset %"PRIu64
"/%"PRIu64"",
offset, gs->len);
msglen = be16_to_cpu(hdr.len);
checksum = be32_to_cpu(hdr.crc);
msglen = be16_to_cpu(hdr->len);
checksum = be32_to_cpu(hdr->crc);
msg = tal_arr(ctx, u8, msglen);
if (pread(gs->fd, msg, msglen, offset + sizeof(hdr)) != msglen)
if (pread(gs->fd, msg, msglen, offset + sizeof(*hdr)) != msglen)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: can't read len %u offset %"PRIu64
"/%"PRIu64, msglen, offset, gs->len);
if (checksum != crc32c(be32_to_cpu(hdr.timestamp), msg, msglen))
if (checksum != crc32c(be32_to_cpu(hdr->timestamp), msg, msglen))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: bad checksum offset %"PRIu64": %s",
offset, tal_hex(tmpctx, msg));
@ -827,6 +863,38 @@ const u8 *gossip_store_get(const tal_t *ctx,
return msg;
}
void gossip_store_set_timestamp(struct gossip_store *gs, u64 offset, u32 timestamp)
{
struct gossip_hdr hdr;
const u8 *msg;
assert(offset > sizeof(struct gossip_hdr));
msg = gossip_store_get_with_hdr(tmpctx, gs, offset - sizeof(hdr), &hdr);
if (pread(gs->fd, &hdr, sizeof(hdr), offset - sizeof(hdr)) != sizeof(hdr)) {
status_broken("gossip_store overrun during set_timestamp @%"PRIu64
" gs->len: %"PRIu64, offset, gs->len);
return;
}
/* Change timestamp and crc */
hdr.timestamp = cpu_to_be32(timestamp);
hdr.crc = cpu_to_be32(crc32c(timestamp, msg, tal_bytelen(msg)));
if (pwrite(gs->fd, &hdr, sizeof(hdr), offset - sizeof(hdr)) != sizeof(hdr))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed writing header to re-timestamp @%"PRIu64": %s",
offset, strerror(errno));
}
const u8 *gossip_store_get(const tal_t *ctx,
struct gossip_store *gs,
u64 offset)
{
struct gossip_hdr hdr;
return gossip_store_get_with_hdr(ctx, gs, offset, &hdr);
}
int gossip_store_readonly_fd(struct gossip_store *gs)
{
int fd = open(GOSSIP_STORE_FILENAME, O_RDONLY);

View file

@ -53,6 +53,27 @@ void gossip_store_delete(struct gossip_store *gs,
struct broadcastable *bcast,
int type);
/**
* Delete the record at this offset (offset is that of
* record, not header, unlike bcast->index!).
*
* In developer mode, checks that type is correct.
*/
void gossip_store_del(struct gossip_store *gs,
u64 offset,
int type);
/**
* Add a flag the record at this offset (offset is that of
* record, not header, unlike bcast->index!).
*
* In developer mode, checks that type is correct.
*/
void gossip_store_flag(struct gossip_store *gs,
u64 offset,
u16 flag,
int type);
/**
* Mark that the channel is about to be deleted, for convenience of
* others mapping the gossip_store.
@ -91,6 +112,20 @@ const u8 *gossip_store_get(const tal_t *ctx,
struct gossip_store *gs,
u64 offset);
/**
* Direct store accessor: get timestamp header for a record.
*
* Offset is *after* the header.
*/
u32 gossip_store_get_timestamp(struct gossip_store *gs, u64 offset);
/**
* Direct store accessor: set timestamp header for a record.
*
* Offset is *after* the header.
*/
void gossip_store_set_timestamp(struct gossip_store *gs, u64 offset, u32 timestamp);
/* Exposed for dev-compact-gossip-store to force compaction. */
bool gossip_store_compact(struct gossip_store *gs);

View file

@ -266,7 +266,7 @@ static void json_add_halfchan(struct json_stream *response,
json_add_num(response, "direction", dir);
json_add_bool(response, "public", !gossmap_chan_is_localmod(gossmap, c));
if (c->private) {
if (gossmap_chan_is_localmod(gossmap, c)) {
/* Local additions don't have a channel_update
* in gossmap. This is deprecated anyway, but
* fill in values from entry we added. */