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

@@ -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