diff --git a/channeldb/graph.go b/channeldb/graph.go index f042dcc4..b975bd92 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -1997,12 +1997,54 @@ func delChannelEdge(edges, edgeIndex, chanIndex, zombieIndex, return nil } + nodeKey1, nodeKey2 := makeZombiePubkeys(&edgeInfo, edge1, edge2) + return markEdgeZombie( - zombieIndex, byteOrder.Uint64(chanID), edgeInfo.NodeKey1Bytes, - edgeInfo.NodeKey2Bytes, + zombieIndex, byteOrder.Uint64(chanID), nodeKey1, nodeKey2, ) } +// makeZombiePubkeys derives the node pubkeys to store in the zombie index for a +// particular pair of channel policies. The return values are one of: +// 1. (pubkey1, pubkey2) +// 2. (pubkey1, blank) +// 3. (blank, pubkey2) +// +// A blank pubkey means that corresponding node will be unable to resurrect a +// channel on its own. For example, node1 may continue to publish recent +// updates, but node2 has fallen way behind. After marking an edge as a zombie, +// we don't want another fresh update from node1 to resurrect, as the edge can +// only become live once node2 finally sends something recent. +// +// In the case where we have neither update, we allow either party to resurrect +// the channel. If the channel were to be marked zombie again, it would be +// marked with the correct lagging channel since we received an update from only +// one side. +func makeZombiePubkeys(info *ChannelEdgeInfo, + e1, e2 *ChannelEdgePolicy) ([33]byte, [33]byte) { + + switch { + + // If we don't have either edge policy, we'll return both pubkeys so + // that the channel can be resurrected by either party. + case e1 == nil && e2 == nil: + return info.NodeKey1Bytes, info.NodeKey2Bytes + + // If we're missing edge1, or if both edges are present but edge1 is + // older, we'll return edge1's pubkey and a blank pubkey for edge2. This + // means that only an update from edge1 will be able to resurrect the + // channel. + case e1 == nil || (e2 != nil && e1.LastUpdate.Before(e2.LastUpdate)): + return info.NodeKey1Bytes, [33]byte{} + + // Otherwise, we're missing edge2 or edge2 is the older side, so we + // return a blank pubkey for edge1. In this case, only an update from + // edge2 can resurect the channel. + default: + return [33]byte{}, info.NodeKey2Bytes + } +} + // UpdateEdgePolicy updates the edge routing policy for a single directed edge // within the database for the referenced channel. The `flags` attribute within // the ChannelEdgePolicy determines which of the directed edges are being