mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
gossipd: remove zombie handling.
We never enabled it, because we seemed to be eliminating valid channels. We discard zombie-marked records on loading. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
af64d30407
commit
e7ceffd565
@ -39,11 +39,6 @@ struct gossip_rcvd_filter;
|
||||
*/
|
||||
#define GOSSIP_STORE_RATELIMIT_BIT 0x2000U
|
||||
|
||||
/**
|
||||
* Bit of flags used to mark a channel announcement as inactive (needs channel updates.)
|
||||
*/
|
||||
#define GOSSIP_STORE_ZOMBIE_BIT 0x1000U
|
||||
|
||||
/**
|
||||
* Bit of flags used to mark a channel announcement closed (not deleted for 12 blocks)
|
||||
*/
|
||||
|
@ -651,9 +651,6 @@ static bool map_catchup(struct gossmap *map, bool *changed)
|
||||
if (flags & GOSSIP_STORE_DELETED_BIT)
|
||||
continue;
|
||||
|
||||
if (flags & GOSSIP_STORE_ZOMBIE_BIT)
|
||||
continue;
|
||||
|
||||
/* Partial write, this can happen. */
|
||||
if (map->map_end + reclen > map->map_size)
|
||||
break;
|
||||
|
@ -17,7 +17,6 @@ GOSSIP_STORE_MAJOR_VERSION_MASK = 0xE0
|
||||
GOSSIP_STORE_LEN_DELETED_BIT = 0x8000
|
||||
GOSSIP_STORE_LEN_PUSH_BIT = 0x4000
|
||||
GOSSIP_STORE_LEN_RATELIMIT_BIT = 0x2000
|
||||
GOSSIP_STORE_ZOMBIE_BIT = 0x1000
|
||||
|
||||
# These duplicate constants in lightning/gossipd/gossip_store_wiregen.h
|
||||
WIRE_GOSSIP_STORE_PRIVATE_CHANNEL = 4104
|
||||
@ -92,7 +91,6 @@ class GossipStoreMsgHeader(object):
|
||||
self.off = off
|
||||
self.deleted = (self.flags & GOSSIP_STORE_LEN_DELETED_BIT) != 0
|
||||
self.ratelimit = (self.flags & GOSSIP_STORE_LEN_RATELIMIT_BIT) != 0
|
||||
self.zombie = (self.flags & GOSSIP_STORE_ZOMBIE_BIT) != 0
|
||||
|
||||
|
||||
class GossmapHalfchannel(object):
|
||||
@ -624,8 +622,6 @@ class Gossmap(object):
|
||||
break
|
||||
if hdr.deleted: # Skip deleted records
|
||||
continue
|
||||
if hdr.zombie:
|
||||
continue
|
||||
|
||||
rectype, = struct.unpack(">H", rec[:2])
|
||||
if rectype == channel_announcement.number:
|
||||
|
@ -68,13 +68,12 @@ int main(int argc, char *argv[])
|
||||
u16 flags = be16_to_cpu(hdr.flags);
|
||||
u16 msglen = be16_to_cpu(hdr.len);
|
||||
u8 *msg, *inner;
|
||||
bool deleted, push, ratelimit, zombie, dying;
|
||||
bool deleted, push, ratelimit, dying;
|
||||
u32 blockheight;
|
||||
|
||||
deleted = (flags & GOSSIP_STORE_DELETED_BIT);
|
||||
push = (flags & GOSSIP_STORE_PUSH_BIT);
|
||||
ratelimit = (flags & GOSSIP_STORE_RATELIMIT_BIT);
|
||||
zombie = (flags & GOSSIP_STORE_ZOMBIE_BIT);
|
||||
dying = (flags & GOSSIP_STORE_DYING_BIT);
|
||||
|
||||
msg = tal_arr(NULL, u8, msglen);
|
||||
@ -85,11 +84,10 @@ int main(int argc, char *argv[])
|
||||
!= crc32c(be32_to_cpu(hdr.timestamp), msg, msglen))
|
||||
warnx("Checksum verification failed");
|
||||
|
||||
printf("%zu: %s%s%s%s%s", off,
|
||||
printf("%zu: %s%s%s%s", off,
|
||||
deleted ? "DELETED " : "",
|
||||
push ? "PUSH " : "",
|
||||
ratelimit ? "RATE-LIMITED " : "",
|
||||
zombie ? "ZOMBIE " : "",
|
||||
dying ? "DYING " : "");
|
||||
if (print_timestamp)
|
||||
printf("T=%u ", be32_to_cpu(hdr.timestamp));
|
||||
|
@ -15,9 +15,12 @@
|
||||
#include <unistd.h>
|
||||
#include <wire/peer_wire.h>
|
||||
|
||||
/* Obsolete ZOMBIE bit */
|
||||
#define GOSSIP_STORE_ZOMBIE_BIT_V13 0x1000U
|
||||
|
||||
#define GOSSIP_STORE_TEMP_FILENAME "gossip_store.tmp"
|
||||
/* We write it as major version 0, minor version 13 */
|
||||
#define GOSSIP_STORE_VER ((0 << 5) | 13)
|
||||
/* We write it as major version 0, minor version 14 */
|
||||
#define GOSSIP_STORE_VER ((0 << 5) | 14)
|
||||
|
||||
struct gossip_store {
|
||||
/* Back pointer. */
|
||||
@ -59,7 +62,7 @@ static ssize_t gossip_pwritev(int fd, const struct iovec *iov, int iovcnt,
|
||||
#endif /* !HAVE_PWRITEV */
|
||||
|
||||
static bool append_msg(int fd, const u8 *msg, u32 timestamp,
|
||||
bool zombie, bool spam, bool dying, u64 *len)
|
||||
bool spam, bool dying, u64 *len)
|
||||
{
|
||||
struct gossip_hdr hdr;
|
||||
u32 msglen;
|
||||
@ -73,8 +76,6 @@ static bool append_msg(int fd, const u8 *msg, u32 timestamp,
|
||||
hdr.flags = 0;
|
||||
if (spam)
|
||||
hdr.flags |= CPU_TO_BE16(GOSSIP_STORE_RATELIMIT_BIT);
|
||||
if (zombie)
|
||||
hdr.flags |= CPU_TO_BE16(GOSSIP_STORE_ZOMBIE_BIT);
|
||||
if (dying)
|
||||
hdr.flags |= CPU_TO_BE16(GOSSIP_STORE_DYING_BIT);
|
||||
hdr.crc = cpu_to_be32(crc32c(timestamp, msg, msglen));
|
||||
@ -97,10 +98,11 @@ static bool append_msg(int fd, const u8 *msg, u32 timestamp,
|
||||
* v11 mandated channel_updates use the htlc_maximum_msat field
|
||||
* v12 added the zombie flag for expired channel updates
|
||||
* v13 removed private gossip entries
|
||||
* v14 removed zombie flags
|
||||
*/
|
||||
static bool can_upgrade(u8 oldversion)
|
||||
{
|
||||
return oldversion >= 9 && oldversion <= 12;
|
||||
return oldversion >= 9 && oldversion <= 13;
|
||||
}
|
||||
|
||||
/* On upgrade, do best effort on private channels: hand them to
|
||||
@ -154,6 +156,7 @@ static void give_lightningd_canned_private_update(struct daemon *daemon,
|
||||
|
||||
static bool upgrade_field(u8 oldversion,
|
||||
struct daemon *daemon,
|
||||
u16 hdr_flags,
|
||||
u8 **msg)
|
||||
{
|
||||
int type = fromwire_peektype(*msg);
|
||||
@ -175,6 +178,12 @@ static bool upgrade_field(u8 oldversion,
|
||||
*msg = tal_free(*msg);
|
||||
}
|
||||
}
|
||||
if (oldversion <= 13) {
|
||||
/* Discard any zombies */
|
||||
if (hdr_flags & GOSSIP_STORE_ZOMBIE_BIT_V13) {
|
||||
*msg = tal_free(*msg);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -250,7 +259,8 @@ static u32 gossip_store_compact_offline(struct daemon *daemon)
|
||||
}
|
||||
|
||||
if (oldversion != version) {
|
||||
if (!upgrade_field(oldversion, daemon, &msg)) {
|
||||
if (!upgrade_field(oldversion, daemon,
|
||||
be16_to_cpu(hdr.flags), &msg)) {
|
||||
tal_free(msg);
|
||||
goto close_and_delete;
|
||||
}
|
||||
@ -299,7 +309,7 @@ static u32 gossip_store_compact_offline(struct daemon *daemon)
|
||||
oldlen = lseek(old_fd, SEEK_END, 0);
|
||||
newlen = lseek(new_fd, SEEK_END, 0);
|
||||
append_msg(old_fd, towire_gossip_store_ended(tmpctx, newlen),
|
||||
0, false, false, false, &oldlen);
|
||||
0, false, false, &oldlen);
|
||||
close(old_fd);
|
||||
status_debug("gossip_store_compact_offline: %zu deleted, %zu copied",
|
||||
deleted, count);
|
||||
@ -357,7 +367,7 @@ struct gossip_store *gossip_store_new(struct daemon *daemon)
|
||||
}
|
||||
|
||||
u64 gossip_store_add(struct gossip_store *gs, const u8 *gossip_msg,
|
||||
u32 timestamp, bool zombie,
|
||||
u32 timestamp,
|
||||
bool spam, bool dying, const u8 *addendum)
|
||||
{
|
||||
u64 off = gs->len;
|
||||
@ -365,12 +375,12 @@ u64 gossip_store_add(struct gossip_store *gs, const u8 *gossip_msg,
|
||||
/* Should never get here during loading! */
|
||||
assert(gs->writable);
|
||||
|
||||
if (!append_msg(gs->fd, gossip_msg, timestamp, zombie, spam, dying, &gs->len)) {
|
||||
if (!append_msg(gs->fd, gossip_msg, timestamp, spam, dying, &gs->len)) {
|
||||
status_broken("Failed writing to gossip store: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (addendum && !append_msg(gs->fd, addendum, 0, false, false, false, &gs->len)) {
|
||||
if (addendum && !append_msg(gs->fd, addendum, 0, false, false, &gs->len)) {
|
||||
status_broken("Failed writing addendum to gossip store: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
@ -504,53 +514,7 @@ void gossip_store_mark_channel_deleted(struct gossip_store *gs,
|
||||
const struct short_channel_id *scid)
|
||||
{
|
||||
gossip_store_add(gs, towire_gossip_store_delete_chan(tmpctx, scid),
|
||||
0, false, false, false, NULL);
|
||||
}
|
||||
|
||||
static void mark_zombie(struct gossip_store *gs,
|
||||
const struct broadcastable *bcast,
|
||||
enum peer_wire expected_type)
|
||||
{
|
||||
beint16_t beflags;
|
||||
u32 index = bcast->index;
|
||||
|
||||
/* We assume flags is the first field! */
|
||||
BUILD_ASSERT(offsetof(struct gossip_hdr, flags) == 0);
|
||||
|
||||
/* Should never get here during loading! */
|
||||
assert(gs->writable);
|
||||
assert(index);
|
||||
|
||||
const u8 *msg = gossip_store_get(tmpctx, gs, index);
|
||||
assert(fromwire_peektype(msg) == expected_type);
|
||||
|
||||
if (pread(gs->fd, &beflags, sizeof(beflags), index) != sizeof(beflags))
|
||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"Failed reading flags to zombie %s @%u: %s",
|
||||
peer_wire_name(expected_type),
|
||||
index, strerror(errno));
|
||||
|
||||
assert((be16_to_cpu(beflags) & GOSSIP_STORE_DELETED_BIT) == 0);
|
||||
beflags |= cpu_to_be16(GOSSIP_STORE_ZOMBIE_BIT);
|
||||
if (pwrite(gs->fd, &beflags, sizeof(beflags), index) != sizeof(beflags))
|
||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"Failed writing flags to zombie %s @%u: %s",
|
||||
peer_wire_name(expected_type),
|
||||
index, strerror(errno));
|
||||
}
|
||||
|
||||
/* Marks the length field of a channel_announcement with the zombie flag bit */
|
||||
void gossip_store_mark_channel_zombie(struct gossip_store *gs,
|
||||
struct broadcastable *bcast)
|
||||
{
|
||||
mark_zombie(gs, bcast, WIRE_CHANNEL_ANNOUNCEMENT);
|
||||
}
|
||||
|
||||
/* Marks the length field of a channel_update with the zombie flag bit */
|
||||
void gossip_store_mark_cupdate_zombie(struct gossip_store *gs,
|
||||
struct broadcastable *bcast)
|
||||
{
|
||||
mark_zombie(gs, bcast, WIRE_CHANNEL_UPDATE);
|
||||
0, false, false, NULL);
|
||||
}
|
||||
|
||||
u32 gossip_store_get_timestamp(struct gossip_store *gs, u64 offset)
|
||||
@ -737,7 +701,7 @@ u32 gossip_store_load(struct gossip_store *gs)
|
||||
if (!routing_add_channel_update(gs->daemon->rstate,
|
||||
take(msg), gs->len,
|
||||
NULL, false,
|
||||
spam, false)) {
|
||||
spam)) {
|
||||
bad = "Bad channel_update";
|
||||
goto badmsg;
|
||||
}
|
||||
|
@ -32,14 +32,13 @@ u32 gossip_store_load(struct gossip_store *gs);
|
||||
* @gs: gossip store
|
||||
* @gossip_msg: the gossip message to insert.
|
||||
* @timestamp: the timestamp for filtering of this messsage.
|
||||
* @zombie: true if this channel is missing a current channel_update.
|
||||
* @spam: true if this message is rate-limited and squelched to peers.
|
||||
* @dying: true if this message is for a dying channel.
|
||||
* @addendum: another message to append immediately after this
|
||||
* (for appending amounts to channel_announcements for internal use).
|
||||
*/
|
||||
u64 gossip_store_add(struct gossip_store *gs, const u8 *gossip_msg,
|
||||
u32 timestamp, bool zombie, bool spam, bool dying,
|
||||
u32 timestamp, bool spam, bool dying,
|
||||
const u8 *addendum);
|
||||
|
||||
|
||||
@ -80,17 +79,6 @@ void gossip_store_flag(struct gossip_store *gs,
|
||||
void gossip_store_mark_channel_deleted(struct gossip_store *gs,
|
||||
const struct short_channel_id *scid);
|
||||
|
||||
/*
|
||||
* Marks the length field of a channel announcement with a zombie flag bit.
|
||||
* This allows the channel_announcement to be retained in the store while
|
||||
* waiting for channel updates to reactivate it.
|
||||
*/
|
||||
void gossip_store_mark_channel_zombie(struct gossip_store *gs,
|
||||
struct broadcastable *bcast);
|
||||
|
||||
void gossip_store_mark_cupdate_zombie(struct gossip_store *gs,
|
||||
struct broadcastable *bcast);
|
||||
|
||||
/**
|
||||
* Mark this channel_announcement/channel_update as dying.
|
||||
*
|
||||
|
@ -312,25 +312,6 @@ static struct node *new_node(struct routing_state *rstate,
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool is_chan_zombie(struct chan *chan)
|
||||
{
|
||||
if (chan->half[0].zombie || chan->half[1].zombie)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_node_zombie(struct node* node)
|
||||
{
|
||||
struct chan_map_iter i;
|
||||
struct chan *c;
|
||||
|
||||
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
||||
if (!is_chan_zombie(c))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We can *send* a channel_announce for a channel attached to this node:
|
||||
* we only send once we have a channel_update. */
|
||||
bool node_has_broadcastable_channels(const struct node *node)
|
||||
@ -339,8 +320,6 @@ bool node_has_broadcastable_channels(const struct node *node)
|
||||
struct chan *c;
|
||||
|
||||
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
||||
if (is_chan_zombie(c))
|
||||
continue;
|
||||
if (is_halfchan_defined(&c->half[0])
|
||||
|| is_halfchan_defined(&c->half[1]))
|
||||
return true;
|
||||
@ -354,10 +333,6 @@ static bool node_announce_predates_channels(const struct node *node)
|
||||
struct chan *c;
|
||||
|
||||
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
||||
/* Zombies don't count! */
|
||||
if (is_chan_zombie(c))
|
||||
continue;
|
||||
|
||||
if (c->bcast.index < node->bcast.index)
|
||||
return false;
|
||||
}
|
||||
@ -381,7 +356,6 @@ static void force_node_announce_rexmit(struct routing_state *rstate,
|
||||
node->bcast.timestamp,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
NULL);
|
||||
if (node->rgraph.index == initial_bcast_index){
|
||||
node->rgraph.index = node->bcast.index;
|
||||
@ -393,7 +367,6 @@ static void force_node_announce_rexmit(struct routing_state *rstate,
|
||||
node->rgraph.index = gossip_store_add(rstate->daemon->gs,
|
||||
announce,
|
||||
node->rgraph.timestamp,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
NULL);
|
||||
@ -490,7 +463,6 @@ static void init_half_chan(struct routing_state *rstate,
|
||||
broadcastable_init(&c->bcast);
|
||||
broadcastable_init(&c->rgraph);
|
||||
c->tokens = TOKEN_MAX;
|
||||
c->zombie = false;
|
||||
}
|
||||
|
||||
static void bad_gossip_order(const u8 *msg,
|
||||
@ -677,7 +649,6 @@ static void add_channel_announce_to_broadcast(struct routing_state *rstate,
|
||||
chan->bcast.timestamp,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
addendum);
|
||||
}
|
||||
|
||||
@ -702,9 +673,8 @@ static void delete_chan_messages_from_store(struct routing_state *rstate,
|
||||
static void remove_channel_from_store(struct routing_state *rstate,
|
||||
struct chan *chan)
|
||||
{
|
||||
/* Put in tombstone marker. Zombie channels will have one already. */
|
||||
if (!is_chan_zombie(chan))
|
||||
gossip_store_mark_channel_deleted(rstate->daemon->gs, &chan->scid);
|
||||
/* Put in tombstone marker. */
|
||||
gossip_store_mark_channel_deleted(rstate->daemon->gs, &chan->scid);
|
||||
|
||||
/* Now delete old entries. */
|
||||
delete_chan_messages_from_store(rstate, chan);
|
||||
@ -1115,8 +1085,7 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
/* NULL if it's us */
|
||||
const struct node_id *source_peer,
|
||||
bool ignore_timestamp,
|
||||
bool force_spam_flag,
|
||||
bool force_zombie_flag)
|
||||
bool force_spam_flag)
|
||||
{
|
||||
secp256k1_ecdsa_signature signature;
|
||||
struct short_channel_id short_channel_id;
|
||||
@ -1133,7 +1102,6 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
u8 direction;
|
||||
struct amount_sat sat;
|
||||
bool spam;
|
||||
bool zombie;
|
||||
bool dying;
|
||||
|
||||
/* Make sure we own msg, even if we don't save it. */
|
||||
@ -1155,7 +1123,6 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
if (chan) {
|
||||
uc = NULL;
|
||||
sat = chan->sat;
|
||||
zombie = is_chan_zombie(chan);
|
||||
dying = is_chan_dying(rstate, &short_channel_id);
|
||||
} else {
|
||||
/* Maybe announcement was waiting for this update? */
|
||||
@ -1172,8 +1139,6 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
return false;
|
||||
}
|
||||
sat = uc->sat;
|
||||
/* When loading zombies from the store. */
|
||||
zombie = force_zombie_flag;
|
||||
dying = false;
|
||||
}
|
||||
|
||||
@ -1197,9 +1162,6 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
assert(!chan);
|
||||
chan = new_chan(rstate, &short_channel_id,
|
||||
&uc->id[0], &uc->id[1], sat);
|
||||
/* Assign zombie flag if loading zombie from store */
|
||||
if (force_zombie_flag)
|
||||
chan->half[direction].zombie = true;
|
||||
}
|
||||
|
||||
/* Discard older updates */
|
||||
@ -1302,68 +1264,6 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
uc->index);
|
||||
}
|
||||
|
||||
/* Handle resurrection of zombie channels if the other side of the
|
||||
* zombie channel has a recent timestamp. */
|
||||
if (zombie && timestamp_reasonable(rstate->daemon,
|
||||
chan->half[!direction].bcast.timestamp) &&
|
||||
chan->half[!direction].bcast.index && !index) {
|
||||
status_peer_debug(source_peer,
|
||||
"Resurrecting zombie channel %s.",
|
||||
type_to_string(tmpctx,
|
||||
struct short_channel_id,
|
||||
&chan->scid));
|
||||
const u8 *zombie_announcement = NULL;
|
||||
const u8 *zombie_addendum = NULL;
|
||||
const u8 *zombie_update[2] = {NULL, NULL};
|
||||
/* Resurrection is a careful process. First delete the zombie-
|
||||
* flagged channel_announcement which has already been
|
||||
* tombstoned, and re-add to the store without zombie flag. */
|
||||
zombie_announcement = gossip_store_get(tmpctx, rstate->daemon->gs,
|
||||
chan->bcast.index);
|
||||
u32 offset = tal_count(zombie_announcement) +
|
||||
sizeof(struct gossip_hdr);
|
||||
/* The channel_announcement addendum reminds us of its size. */
|
||||
zombie_addendum = gossip_store_get(tmpctx, rstate->daemon->gs,
|
||||
chan->bcast.index + offset);
|
||||
gossip_store_delete(rstate->daemon->gs, &chan->bcast,
|
||||
WIRE_CHANNEL_ANNOUNCEMENT);
|
||||
chan->bcast.index =
|
||||
gossip_store_add(rstate->daemon->gs, zombie_announcement,
|
||||
chan->bcast.timestamp,
|
||||
false, false, false, zombie_addendum);
|
||||
/* Deletion of the old addendum is optional. */
|
||||
/* This opposing channel_update has been stashed away. Now that
|
||||
* there are two valid updates, this one gets restored. */
|
||||
/* FIXME: Handle spam case probably needs a helper f'n */
|
||||
zombie_update[0] = gossip_store_get(tmpctx, rstate->daemon->gs,
|
||||
chan->half[!direction].bcast.index);
|
||||
if (chan->half[!direction].bcast.index != chan->half[!direction].rgraph.index) {
|
||||
/* Don't forget the spam channel_update */
|
||||
zombie_update[1] = gossip_store_get(tmpctx, rstate->daemon->gs,
|
||||
chan->half[!direction].rgraph.index);
|
||||
gossip_store_delete(rstate->daemon->gs, &chan->half[!direction].rgraph,
|
||||
WIRE_CHANNEL_UPDATE);
|
||||
}
|
||||
gossip_store_delete(rstate->daemon->gs, &chan->half[!direction].bcast,
|
||||
WIRE_CHANNEL_UPDATE);
|
||||
chan->half[!direction].bcast.index =
|
||||
gossip_store_add(rstate->daemon->gs, zombie_update[0],
|
||||
chan->half[!direction].bcast.timestamp,
|
||||
false, false, false, NULL);
|
||||
if (zombie_update[1])
|
||||
chan->half[!direction].rgraph.index =
|
||||
gossip_store_add(rstate->daemon->gs, zombie_update[1],
|
||||
chan->half[!direction].rgraph.timestamp,
|
||||
false, true, false, NULL);
|
||||
else
|
||||
chan->half[!direction].rgraph.index = chan->half[!direction].bcast.index;
|
||||
|
||||
/* It's a miracle! */
|
||||
chan->half[0].zombie = false;
|
||||
chan->half[1].zombie = false;
|
||||
zombie = false;
|
||||
}
|
||||
|
||||
/* If we're loading from store, this means we don't re-add to store. */
|
||||
if (index) {
|
||||
if (!spam)
|
||||
@ -1372,7 +1272,7 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
} else {
|
||||
hc->rgraph.index
|
||||
= gossip_store_add(rstate->daemon->gs, update, timestamp,
|
||||
zombie, spam, dying, NULL);
|
||||
spam, dying, NULL);
|
||||
if (!spam)
|
||||
hc->bcast.index = hc->rgraph.index;
|
||||
|
||||
@ -1540,7 +1440,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES,
|
||||
}
|
||||
|
||||
routing_add_channel_update(rstate, take(serialized), 0, source_peer, force,
|
||||
false, false);
|
||||
false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1674,8 +1574,7 @@ bool routing_add_node_announcement(struct routing_state *rstate,
|
||||
if (!pna) {
|
||||
if (was_unknown)
|
||||
*was_unknown = true;
|
||||
/* Don't complain if it's a zombie node! */
|
||||
if (!node || !is_node_zombie(node)) {
|
||||
if (!node) {
|
||||
bad_gossip_order(msg, source_peer,
|
||||
type_to_string(tmpctx, struct node_id,
|
||||
&node_id));
|
||||
@ -1788,7 +1687,7 @@ bool routing_add_node_announcement(struct routing_state *rstate,
|
||||
} else {
|
||||
node->rgraph.index
|
||||
= gossip_store_add(rstate->daemon->gs, msg, timestamp,
|
||||
false, spam, false, NULL);
|
||||
spam, false, NULL);
|
||||
if (!spam)
|
||||
node->bcast.index = node->rgraph.index;
|
||||
|
||||
@ -1882,10 +1781,6 @@ void route_prune(struct routing_state *rstate)
|
||||
for (struct chan *chan = uintmap_first(&rstate->chanmap, &idx);
|
||||
chan;
|
||||
chan = uintmap_after(&rstate->chanmap, &idx)) {
|
||||
/* These have been pruned already */
|
||||
if (is_chan_zombie(chan))
|
||||
continue;
|
||||
|
||||
/* BOLT #7:
|
||||
* - if the `timestamp` of the latest `channel_update` in
|
||||
* either direction is older than two weeks (1209600 seconds):
|
||||
@ -2061,7 +1956,7 @@ void routing_channel_spent(struct routing_state *rstate,
|
||||
|
||||
/* Save to gossip_store in case we restart */
|
||||
msg = towire_gossip_store_chan_dying(tmpctx, &chan->scid, deadline);
|
||||
index = gossip_store_add(rstate->daemon->gs, msg, 0, false, false, false, NULL);
|
||||
index = gossip_store_add(rstate->daemon->gs, msg, 0, false, false, NULL);
|
||||
|
||||
/* Mark it dying, so we don't gossip it */
|
||||
gossip_store_mark_dying(rstate->daemon->gs, &chan->bcast,
|
||||
|
@ -30,9 +30,6 @@ struct half_chan {
|
||||
|
||||
/* Token bucket */
|
||||
u8 tokens;
|
||||
|
||||
/* Disabled channel waiting for a channel_update from both sides. */
|
||||
bool zombie;
|
||||
};
|
||||
|
||||
struct chan {
|
||||
@ -319,8 +316,7 @@ bool routing_add_channel_update(struct routing_state *rstate,
|
||||
u32 index,
|
||||
const struct node_id *source_peer TAKES,
|
||||
bool ignore_timestamp,
|
||||
bool force_spam_flag,
|
||||
bool force_zombie_flag);
|
||||
bool force_spam_flag);
|
||||
/**
|
||||
* Add a node_announcement to the network view without checking it
|
||||
*
|
||||
@ -364,7 +360,7 @@ bool would_ratelimit_cupdate(struct routing_state *rstate,
|
||||
const struct half_chan *hc,
|
||||
u32 timestamp);
|
||||
|
||||
/* Does this node have public, non-zombie channels? */
|
||||
/* Does this node have public channels? */
|
||||
bool node_has_broadcastable_channels(const struct node *node);
|
||||
|
||||
/* Returns an error string if there are unfinalized entries after load */
|
||||
|
@ -1616,7 +1616,7 @@ def test_gossip_store_load_no_channel_update(node_factory):
|
||||
|
||||
# This should actually result in an empty store.
|
||||
with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), "rb") as f:
|
||||
assert bytearray(f.read()) == bytearray.fromhex("0d")
|
||||
assert bytearray(f.read()) == bytearray.fromhex("0e")
|
||||
|
||||
|
||||
def test_gossip_store_compact_on_load(node_factory, bitcoind):
|
||||
@ -2094,74 +2094,6 @@ def test_gossip_not_dying(node_factory, bitcoind):
|
||||
assert len(get_gossip(l1)) == 2
|
||||
|
||||
|
||||
@pytest.mark.skip("Zombie research had unexpected side effects")
|
||||
def test_channel_resurrection(node_factory, bitcoind):
|
||||
"""When a node goes offline long enough to prune a channel, the
|
||||
channel_announcement should be retained in case the node comes back online.
|
||||
"""
|
||||
opts = {'dev-fast-gossip-prune': None,
|
||||
'may_reconnect': True}
|
||||
l1, l2 = node_factory.get_nodes(2, opts=opts)
|
||||
opts.update({'log-level': 'debug'})
|
||||
l3, = node_factory.get_nodes(1, opts=opts)
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
l3.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
scid, _ = l1.fundchannel(l2, 10**6, True, True)
|
||||
bitcoind.generate_block(6)
|
||||
sync_blockheight(bitcoind, [l1, l2, l3])
|
||||
l3.wait_channel_active(scid)
|
||||
start_time = int(time.time())
|
||||
# Channel_update should now be refreshed.
|
||||
refresh_due = start_time + 44
|
||||
prune_due = start_time + 61
|
||||
l2.rpc.call('dev-gossip-set-time', [refresh_due])
|
||||
l3.rpc.call('dev-gossip-set-time', [refresh_due])
|
||||
# Automatic reconnect is too fast, so shutdown l1 instead of disconnecting
|
||||
l1.stop()
|
||||
l2.daemon.wait_for_log('Sending keepalive channel_update')
|
||||
l3.daemon.wait_for_log('Received channel_update for channel 103x1')
|
||||
# Wait for the next pruning cycle
|
||||
l2.rpc.call('dev-gossip-set-time', [prune_due])
|
||||
l3.rpc.call('dev-gossip-set-time', [prune_due])
|
||||
# Make sure l1 is recognized as disconnected
|
||||
wait_for(lambda: only_one(l2.rpc.listpeers(l1.info['id'])['peers'])['connected'] is False)
|
||||
# Wait for the channel to be pruned.
|
||||
l3.daemon.wait_for_log("Pruning channel")
|
||||
assert l3.rpc.listchannels()['channels'] == []
|
||||
l1.start()
|
||||
time.sleep(1)
|
||||
l1.rpc.call('dev-gossip-set-time', [prune_due])
|
||||
time.sleep(1)
|
||||
l1.rpc.call('dev-gossip-set-time', [prune_due])
|
||||
wait_for(lambda: [c['active'] for c in l2.rpc.listchannels()['channels']] == [True, True])
|
||||
l1.rpc.call('dev-gossip-set-time', [prune_due + 30])
|
||||
l2.rpc.call('dev-gossip-set-time', [prune_due + 30])
|
||||
l3.rpc.call('dev-gossip-set-time', [prune_due + 30])
|
||||
# l2 should recognize its own channel as announceable
|
||||
wait_for(lambda: [[c['public'], c['active']] for c in l2.rpc.listchannels()['channels']] == [[True, True], [True, True]], timeout=30)
|
||||
# l3 should be able to recover the zombie channel
|
||||
wait_for(lambda: [c['active'] for c in l3.rpc.listchannels()['channels']] == [True, True], timeout=30)
|
||||
|
||||
# Now test spending the outpoint and removing a zombie channel from the store.
|
||||
l2.stop()
|
||||
prune_again = prune_due + 91
|
||||
l1.rpc.call('dev-gossip-set-time', [prune_again])
|
||||
l3.rpc.call('dev-gossip-set-time', [prune_again])
|
||||
l3.daemon.wait_for_log("Pruning channel")
|
||||
txid = l1.rpc.close(l2.info['id'], 1)['txid']
|
||||
bitcoind.generate_block(13, txid)
|
||||
l3.daemon.wait_for_log(f"Deleting channel {scid} due to the funding "
|
||||
"outpoint being spent", 30)
|
||||
# gossip_store is cleaned of zombie channels once outpoint is spent.
|
||||
gs_path = os.path.join(l3.daemon.lightning_dir, TEST_NETWORK, 'gossip_store')
|
||||
gs = subprocess.run(['devtools/dump-gossipstore', '--print-deleted', gs_path],
|
||||
check=True, timeout=TIMEOUT, stdout=subprocess.PIPE)
|
||||
print(gs.stdout.decode())
|
||||
for l in gs.stdout.decode().splitlines():
|
||||
if "ZOMBIE" in l:
|
||||
assert ("DELETED" in l)
|
||||
|
||||
|
||||
def test_dump_own_gossip(node_factory):
|
||||
"""We *should* send all self-related gossip unsolicited, if we have any"""
|
||||
l1, l2 = node_factory.line_graph(2, wait_for_announce=True)
|
||||
|
Loading…
Reference in New Issue
Block a user