gossipd: erase old entries from the store, don't just append.

We use the high bit of the length field: this way we can still check
that the checksums are valid on deleted fields.

Once this is done, serially reading the gossip_store file will result
in a complete, ordered, minimal gossip broadcast.  Also, the horrible
corner case where we might try to delete things from the store during
load time is completely gone: we only load non-deleted things.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2019-06-04 03:39:25 +09:30
parent 696dc6b597
commit df00f20e4a
14 changed files with 126 additions and 93 deletions

View File

@ -2,6 +2,7 @@
#include <ccan/endian/endian.h>
#include <common/gossip_store.h>
#include <common/status.h>
#include <common/utils.h>
#include <errno.h>
#include <inttypes.h>
#include <unistd.h>
@ -23,7 +24,8 @@ u8 *gossip_store_read(const tal_t *ctx, int gossip_store_fd, u64 offset)
offset, strerror(errno));
}
msglen = be32_to_cpu(hdr[0]);
/* FIXME: We should skip over these deleted entries! */
msglen = be32_to_cpu(hdr[0]) & ~GOSSIP_STORE_LEN_DELETED_BIT;
checksum = be32_to_cpu(hdr[1]);
msg = tal_arr(ctx, u8, msglen);
if (pread(gossip_store_fd, msg, msglen, offset + sizeof(hdr)) != msglen)
@ -33,8 +35,8 @@ u8 *gossip_store_read(const tal_t *ctx, int gossip_store_fd, u64 offset)
if (checksum != crc32c(0, msg, msglen))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: bad checksum offset %"PRIu64,
offset);
"gossip_store: bad checksum offset %"PRIu64": %s",
offset, tal_hex(tmpctx, msg));
return msg;
}

View File

@ -7,7 +7,12 @@
/**
* gossip_store -- On-disk storage related information
*/
#define GOSSIP_STORE_VERSION 4
#define GOSSIP_STORE_VERSION 5
/**
* Bit of length we use to mark a deleted record.
*/
#define GOSSIP_STORE_LEN_DELETED_BIT 0x80000000U
/**
* Direct store accessor: loads gossip msg from store.

View File

@ -45,17 +45,21 @@ int main(int argc, char *argv[])
while (read(fd, &belen, sizeof(belen)) == sizeof(belen) &&
read(fd, &becsum, sizeof(becsum)) == sizeof(becsum)) {
struct amount_sat sat;
struct short_channel_id scid;
u32 msglen = be32_to_cpu(belen);
u8 *msg = tal_arr(NULL, u8, msglen), *inner;
u8 *msg, *inner;
bool deleted = (msglen & GOSSIP_STORE_LEN_DELETED_BIT);
msglen &= ~GOSSIP_STORE_LEN_DELETED_BIT;
msg = tal_arr(NULL, u8, msglen);
if (read(fd, msg, msglen) != msglen)
errx(1, "%zu: Truncated file?", off);
if (be32_to_cpu(becsum) != crc32c(0, msg, msglen))
warnx("Checksum verification failed");
if (fromwire_gossip_store_channel_amount(msg, &sat)) {
if (deleted) {
printf("%zu: DELETED\n", off);
} else if (fromwire_gossip_store_channel_amount(msg, &sat)) {
printf("%zu: channel_amount: %s\n", off,
type_to_string(tmpctx, struct amount_sat, &sat));
} else if (fromwire_peektype(msg) == WIRE_CHANNEL_ANNOUNCEMENT) {
@ -70,11 +74,6 @@ int main(int argc, char *argv[])
} else if (fromwire_peektype(msg) == WIRE_GOSSIPD_LOCAL_ADD_CHANNEL) {
printf("%zu: local_add_channel: %s\n",
off, tal_hex(msg, msg));
} else if (fromwire_gossip_store_channel_delete(msg, &scid)) {
printf("%zu: channel_delete: %s\n",
off,
type_to_string(msg, struct short_channel_id,
&scid));
} else if (fromwire_gossip_store_private_update(msg, msg,
&inner)) {
printf("%zu: private channel_update: %s\n",

View File

@ -206,6 +206,12 @@ static size_t transfer_store_msg(int from_fd, size_t from_off, int to_fd,
}
msglen = be32_to_cpu(hdr[0]);
if (msglen & GOSSIP_STORE_LEN_DELETED_BIT) {
status_broken("Can't transfer deleted msg from gossip store @%zu",
from_off);
return 0;
}
/* FIXME: Reuse buffer? */
msg = tal_arr(tmpctx, u8, sizeof(hdr) + msglen);
memcpy(msg, hdr, sizeof(hdr));
@ -396,19 +402,46 @@ u64 gossip_store_add_private_update(struct gossip_store *gs, const u8 *update)
return gossip_store_add(gs, pupdate, NULL);
}
void gossip_store_add_channel_delete(struct gossip_store *gs,
const struct short_channel_id *scid)
void gossip_store_delete(struct gossip_store *gs,
struct broadcastable *bcast,
int type)
{
u8 *msg = towire_gossip_store_channel_delete(NULL, scid);
beint32_t belen;
int flags;
if (!bcast->index)
return;
/* Should never get here during loading! */
assert(gs->writable);
if (!append_msg(gs->fd, msg, &gs->len))
#if DEVELOPER
u8 *msg = gossip_store_read(tmpctx, gs->fd, bcast->index);
assert(fromwire_peektype(msg) == type);
#endif
if (pread(gs->fd, &belen, sizeof(belen), bcast->index) != sizeof(belen))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed writing channel_delete to gossip store: %s",
strerror(errno));
tal_free(msg);
"Failed reading len to delete @%u: %s",
bcast->index, strerror(errno));
assert((be32_to_cpu(belen) & GOSSIP_STORE_LEN_DELETED_BIT) == 0);
belen |= cpu_to_be32(GOSSIP_STORE_LEN_DELETED_BIT);
/* From man pwrite(2):
*
* BUGS
* POSIX requires that opening a file with the O_APPEND flag should
* have no effect on the location at which pwrite() writes data.
* However, on Linux, if a file is opened with O_APPEND, pwrite()
* appends data to the end of the file, regardless of the value of
* offset.
*/
flags = fcntl(gs->fd, F_GETFL);
fcntl(gs->fd, F_SETFL, flags & ~O_APPEND);
if (pwrite(gs->fd, &belen, sizeof(belen), bcast->index) != sizeof(belen))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed writing len to delete @%u: %s",
bcast->index, strerror(errno));
fcntl(gs->fd, F_SETFL, flags);
}
const u8 *gossip_store_get(const tal_t *ctx,
@ -443,7 +476,6 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
u32 msglen, checksum;
u8 *msg;
struct amount_sat satoshis;
struct short_channel_id scid;
const char *bad;
size_t stats[] = {0, 0, 0, 0};
struct timeabs start = time_now();
@ -452,7 +484,7 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
gs->writable = false;
while (pread(gs->fd, hdr, sizeof(hdr), gs->len) == sizeof(hdr)) {
msglen = be32_to_cpu(hdr[0]);
msglen = be32_to_cpu(hdr[0]) & ~GOSSIP_STORE_LEN_DELETED_BIT;
checksum = be32_to_cpu(hdr[1]);
msg = tal_arr(tmpctx, u8, msglen);
@ -466,6 +498,10 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
goto truncate;
}
/* Skip deleted entries */
if (be32_to_cpu(hdr[0]) & GOSSIP_STORE_LEN_DELETED_BIT)
goto next;
switch (fromwire_peektype(msg)) {
case WIRE_GOSSIP_STORE_CHANNEL_AMOUNT:
if (!fromwire_gossip_store_channel_amount(msg,
@ -473,12 +509,9 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
bad = "Bad gossip_store_channel_amount";
goto truncate;
}
/* Should follow channel_announcement */
if (!chan_ann) {
bad = "gossip_store_channel_amount without"
" channel_announcement";
goto truncate;
}
/* Previous channel_announcement may have been deleted */
if (!chan_ann)
break;
if (!routing_add_channel_announcement(rstate,
take(chan_ann),
satoshis,
@ -520,19 +553,6 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
}
stats[2]++;
break;
case WIRE_GOSSIP_STORE_CHANNEL_DELETE:
if (!fromwire_gossip_store_channel_delete(msg, &scid)) {
bad = "Bad channel_delete";
goto truncate;
}
struct chan *c = get_channel(rstate, &scid);
if (!c) {
bad = "Bad channel_delete scid";
goto truncate;
}
free_chan(rstate, c);
stats[3]++;
break;
case WIRE_GOSSIPD_LOCAL_ADD_CHANNEL:
if (!handle_local_add_channel(rstate, msg, gs->len)) {
bad = "Bad local_add_channel";
@ -543,10 +563,11 @@ void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)
bad = "Unknown message";
goto truncate;
}
gs->len += sizeof(hdr) + msglen;
if (fromwire_peektype(msg) != WIRE_GOSSIP_STORE_CHANNEL_AMOUNT)
gs->count++;
next:
gs->len += sizeof(hdr) + msglen;
clean_tmpctx();
}
goto out;
@ -570,9 +591,3 @@ out:
gs->len);
gs->writable = true;
}
/* FIXME: Remove */
bool gossip_store_loading(const struct gossip_store *gs)
{
return !gs->writable;
}

View File

@ -6,9 +6,6 @@
gossip_store_channel_amount,4101
gossip_store_channel_amount,,satoshis,struct amount_sat
gossip_store_channel_delete,4099
gossip_store_channel_delete,,short_channel_id,struct short_channel_id
gossip_store_private_update,4102
gossip_store_private_update,,len,u16
gossip_store_private_update,,update,len*u8

1 # gossip_store messages: messages persisted in the gossip_store
6 gossip_store_channel_amount,,satoshis,struct amount_sat
7 gossip_store_channel_delete,4099 gossip_store_private_update,4102
8 gossip_store_channel_delete,,short_channel_id,struct short_channel_id gossip_store_private_update,,len,u16
gossip_store_private_update,4102
gossip_store_private_update,,len,u16
gossip_store_private_update,,update,len*u8
9 gossip_store_private_update,,update,len*u8
10
11

View File

@ -39,10 +39,13 @@ u64 gossip_store_add(struct gossip_store *gs, const u8 *gossip_msg,
/**
* Remember that we deleted a channel as a result of its outpoint being spent
* Delete the broadcast associated with this (if any).
*
* In developer mode, checks that type is correct.
*/
void gossip_store_add_channel_delete(struct gossip_store *gs,
const struct short_channel_id *scid);
void gossip_store_delete(struct gossip_store *gs,
struct broadcastable *bcast,
int type);
/**
* Direct store accessor: loads gossip msg back from store.
@ -88,7 +91,4 @@ bool gossip_store_compact(struct gossip_store *gs,
*/
int gossip_store_readonly_fd(struct gossip_store *gs);
/* FIXME: Remove */
bool gossip_store_loading(const struct gossip_store *gs);
#endif /* LIGHTNING_GOSSIPD_GOSSIP_STORE_H */

View File

@ -2802,13 +2802,11 @@ static struct io_plan *handle_outpoint_spent(struct io_conn *conn,
"Deleting channel %s due to the funding outpoint being "
"spent",
type_to_string(msg, struct short_channel_id, &scid));
remove_channel_from_store(rstate, chan);
/* Freeing is sufficient since everything else is allocated off
* of the channel and this takes care of unregistering
* the channel */
free_chan(rstate, chan);
/* We put a tombstone marker in the channel store, so we don't
* have to replay blockchain spends on restart. */
gossip_store_add_channel_delete(rstate->broadcasts->gs, &scid);
}
return daemon_conn_read_next(conn, daemon->master);

View File

@ -330,6 +330,9 @@ static void remove_chan_from_node(struct routing_state *rstate,
/* Last channel? Simply delete node (and associated announce) */
if (num_chans == 0) {
gossip_store_delete(rstate->broadcasts->gs,
&node->bcast,
WIRE_NODE_ANNOUNCEMENT);
tal_free(node);
return;
}
@ -337,14 +340,11 @@ static void remove_chan_from_node(struct routing_state *rstate,
if (!node->bcast.index)
return;
/* FIXME: Remove when we get rid of WIRE_GOSSIP_STORE_CHANNEL_DELETE.
* For the moment, it can cause us to try to write to the store. */
(void)WIRE_GOSSIP_STORE_CHANNEL_DELETE;
if (gossip_store_loading(rstate->broadcasts->gs))
return;
/* Removed only public channel? Remove node announcement. */
if (!node_has_broadcastable_channels(node)) {
gossip_store_delete(rstate->broadcasts->gs,
&node->bcast,
WIRE_NODE_ANNOUNCEMENT);
broadcast_del(rstate->broadcasts, &node->bcast);
} else if (node_announce_predates_channels(node)) {
const u8 *announce;
@ -356,6 +356,9 @@ static void remove_chan_from_node(struct routing_state *rstate,
* Move to end (we could, in theory, move to just past next
* channel_announce, but we don't care that much about spurious
* retransmissions in this corner case */
gossip_store_delete(rstate->broadcasts->gs,
&node->bcast,
WIRE_NODE_ANNOUNCEMENT);
broadcast_del(rstate->broadcasts, &node->bcast);
insert_broadcast(&rstate->broadcasts, announce, NULL,
&node->bcast);
@ -1416,8 +1419,10 @@ bool routing_add_channel_announcement(struct routing_state *rstate,
}
/* Pretend it didn't exist, for the moment. */
if (chan)
if (chan) {
remove_channel_from_store(rstate, chan);
free_chan(rstate, chan);
}
uc = tal(rstate, struct unupdated_channel);
uc->channel_announce = tal_dup_arr(uc, u8, msg, tal_count(msg), 0);
@ -1836,7 +1841,13 @@ bool routing_add_channel_update(struct routing_state *rstate,
message_flags, channel_flags,
timestamp, htlc_minimum, htlc_maximum);
/* Safe even if was never added */
/* Safe even if was never added, but if it's a private channel it
* would be a WIRE_GOSSIP_STORE_PRIVATE_UPDATE. */
gossip_store_delete(rstate->broadcasts->gs,
&chan->half[direction].bcast,
is_chan_public(chan)
? WIRE_CHANNEL_UPDATE
: WIRE_GOSSIP_STORE_PRIVATE_UPDATE);
broadcast_del(rstate->broadcasts, &chan->half[direction].bcast);
/* BOLT #7:
@ -1899,6 +1910,28 @@ static const struct node_id *get_channel_owner(struct routing_state *rstate,
return NULL;
}
void remove_channel_from_store(struct routing_state *rstate,
struct chan *chan)
{
int update_type, announcment_type;
if (is_chan_public(chan)) {
update_type = WIRE_CHANNEL_UPDATE;
announcment_type = WIRE_CHANNEL_ANNOUNCEMENT;
} else {
update_type = WIRE_GOSSIP_STORE_PRIVATE_UPDATE;
announcment_type = WIRE_GOSSIPD_LOCAL_ADD_CHANNEL;
}
/* If these aren't in the store, these are noops. */
gossip_store_delete(rstate->broadcasts->gs,
&chan->bcast, announcment_type);
gossip_store_delete(rstate->broadcasts->gs,
&chan->half[0].bcast, update_type);
gossip_store_delete(rstate->broadcasts->gs,
&chan->half[1].bcast, update_type);
}
u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES,
const char *source)
{
@ -2108,6 +2141,9 @@ bool routing_add_node_announcement(struct routing_state *rstate,
}
/* Harmless if it was never added */
gossip_store_delete(rstate->broadcasts->gs,
&node->bcast,
WIRE_NODE_ANNOUNCEMENT);
broadcast_del(rstate->broadcasts, &node->bcast);
node->bcast.timestamp = timestamp;
@ -2428,8 +2464,10 @@ void route_prune(struct routing_state *rstate)
}
/* Now free all the chans and maybe even nodes. */
for (size_t i = 0; i < tal_count(pruned); i++)
for (size_t i = 0; i < tal_count(pruned); i++) {
remove_channel_from_store(rstate, pruned[i]);
free_chan(rstate, pruned[i]);
}
}
#if DEVELOPER

View File

@ -426,4 +426,7 @@ static inline void local_enable_chan(struct routing_state *rstate,
/* Helper to convert on-wire addresses format to wireaddrs array */
struct wireaddr *read_addresses(const tal_t *ctx, const u8 *ser);
/* Remove channel from store: announcement and any updates. */
void remove_channel_from_store(struct routing_state *rstate,
struct chan *chan);
#endif /* LIGHTNING_GOSSIPD_ROUTING_H */

View File

@ -42,9 +42,6 @@ bool fromwire_gossipd_local_add_channel(const void *p UNNEEDED, struct short_cha
/* Generated stub for fromwire_gossip_store_channel_amount */
bool fromwire_gossip_store_channel_amount(const void *p UNNEEDED, struct amount_sat *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_channel_delete */
bool fromwire_gossip_store_channel_delete(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_private_update */
bool fromwire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **update UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_private_update called!\n"); abort(); }
@ -85,9 +82,6 @@ u8 *towire_gossipd_local_add_channel(const tal_t *ctx UNNEEDED, const struct sho
/* Generated stub for towire_gossip_store_channel_amount */
u8 *towire_gossip_store_channel_amount(const tal_t *ctx UNNEEDED, struct amount_sat satoshis UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for towire_gossip_store_channel_delete */
u8 *towire_gossip_store_channel_delete(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for towire_gossip_store_private_update */
u8 *towire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_private_update called!\n"); abort(); }

View File

@ -31,9 +31,6 @@ bool fromwire_gossipd_local_add_channel(const void *p UNNEEDED, struct short_cha
/* Generated stub for fromwire_gossip_store_channel_amount */
bool fromwire_gossip_store_channel_amount(const void *p UNNEEDED, struct amount_sat *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_channel_delete */
bool fromwire_gossip_store_channel_delete(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_private_update */
bool fromwire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **update UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_private_update called!\n"); abort(); }
@ -74,9 +71,6 @@ u8 *towire_gossipd_local_add_channel(const tal_t *ctx UNNEEDED, const struct sho
/* Generated stub for towire_gossip_store_channel_amount */
u8 *towire_gossip_store_channel_amount(const tal_t *ctx UNNEEDED, struct amount_sat satoshis UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for towire_gossip_store_channel_delete */
u8 *towire_gossip_store_channel_delete(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for towire_gossip_store_private_update */
u8 *towire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_private_update called!\n"); abort(); }

View File

@ -29,9 +29,6 @@ bool fromwire_gossipd_local_add_channel(const void *p UNNEEDED, struct short_cha
/* Generated stub for fromwire_gossip_store_channel_amount */
bool fromwire_gossip_store_channel_amount(const void *p UNNEEDED, struct amount_sat *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_channel_delete */
bool fromwire_gossip_store_channel_delete(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_private_update */
bool fromwire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **update UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_private_update called!\n"); abort(); }
@ -72,9 +69,6 @@ u8 *towire_gossipd_local_add_channel(const tal_t *ctx UNNEEDED, const struct sho
/* Generated stub for towire_gossip_store_channel_amount */
u8 *towire_gossip_store_channel_amount(const tal_t *ctx UNNEEDED, struct amount_sat satoshis UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for towire_gossip_store_channel_delete */
u8 *towire_gossip_store_channel_delete(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for towire_gossip_store_private_update */
u8 *towire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_private_update called!\n"); abort(); }

View File

@ -29,9 +29,6 @@ bool fromwire_gossipd_local_add_channel(const void *p UNNEEDED, struct short_cha
/* Generated stub for fromwire_gossip_store_channel_amount */
bool fromwire_gossip_store_channel_amount(const void *p UNNEEDED, struct amount_sat *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_channel_delete */
bool fromwire_gossip_store_channel_delete(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for fromwire_gossip_store_private_update */
bool fromwire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **update UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_store_private_update called!\n"); abort(); }
@ -72,9 +69,6 @@ u8 *towire_gossipd_local_add_channel(const tal_t *ctx UNNEEDED, const struct sho
/* Generated stub for towire_gossip_store_channel_amount */
u8 *towire_gossip_store_channel_amount(const tal_t *ctx UNNEEDED, struct amount_sat satoshis UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_amount called!\n"); abort(); }
/* Generated stub for towire_gossip_store_channel_delete */
u8 *towire_gossip_store_channel_delete(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_channel_delete called!\n"); abort(); }
/* Generated stub for towire_gossip_store_private_update */
u8 *towire_gossip_store_private_update(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_private_update called!\n"); abort(); }

View File

@ -861,7 +861,7 @@ def test_gossip_store_load(node_factory):
"""Make sure we can read canned gossip store"""
l1 = node_factory.get_node(start=False)
with open(os.path.join(l1.daemon.lightning_dir, 'gossip_store'), 'wb') as f:
f.write(bytearray.fromhex("04" # GOSSIP_STORE_VERSION
f.write(bytearray.fromhex("05" # GOSSIP_STORE_VERSION
"000001b0" # len
"697dac9f" # csum
"0100" # WIRE_CHANNEL_ANNOUNCEMENT