diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index 2c03719d5..fbd954783 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -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); diff --git a/gossipd/gossip_store.h b/gossipd/gossip_store.h index b318842f1..4f86a5b60 100644 --- a/gossipd/gossip_store.h +++ b/gossipd/gossip_store.h @@ -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); diff --git a/plugins/topology.c b/plugins/topology.c index 6cb12c308..f43688e71 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -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. */