gossipd: handle case where block closes multiple channels requiring node_announcement moves more than once.

If we delete it the first time a channel before it is closed, we will
crash when we try to move it again:

```
$ lightning_gossipd: gossip_store: get delete entry offset 47411992/51608943 (version v23.11-378-gac2a386-modded)
0x1002544b send_backtrace
        common/daemon.c:33
0x1003415f status_failed
        common/status.c:221
0x10016ef3 gossip_store_get_with_hdr
        gossipd/gossip_store.c:466
0x10016faf check_msg_type
        gossipd/gossip_store.c:491
0x1001722b gossip_store_set_flag
        gossipd/gossip_store.c:509
0x1001752b gossip_store_del
        gossipd/gossip_store.c:561
0x10017f5b remove_channel
        gossipd/gossmap_manage.c:299
0x100181cf kill_spent_channel
        gossipd/gossmap_manage.c:1144
0x1001a7df gossmap_manage_new_block
        gossipd/gossmap_manage.c:1183
0x10014673 new_blockheight
        gossipd/gossipd.c:483
0x10014d73 recv_req
        gossipd/gossipd.c:594
```

Reported-by: @microsatosi on Discord
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-02-14 16:47:56 +10:30 committed by Christian Decker
parent 8d7a99b589
commit 1018b5449b

View file

@ -1150,7 +1150,6 @@ static void kill_spent_channel(struct gossmap_manage *gm,
void gossmap_manage_new_block(struct gossmap_manage *gm, u32 new_blockheight)
{
u64 idx;
struct gossmap *gossmap = gossmap_manage_get_gossmap(gm);
for (struct pending_cannounce *pca = uintmap_first(&gm->early_ann_map.map, &idx);
pca != NULL;
@ -1180,9 +1179,14 @@ void gossmap_manage_new_block(struct gossmap_manage *gm, u32 new_blockheight)
}
for (size_t i = 0; i < tal_count(gm->dying_channels); i++) {
struct gossmap *gossmap;
if (gm->dying_channels[i].deadline > new_blockheight)
continue;
/* Refresh gossmap each time in case we move things in the loop:
* in particular, we might move a node_announcement twice! */
gossmap = gossmap_manage_get_gossmap(gm);
kill_spent_channel(gm, gossmap, gm->dying_channels[i].scid);
gossip_store_del(gm->daemon->gs,
gm->dying_channels[i].gossmap_offset,