mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-12-09 12:22:38 +01:00
Merge pull request #3197 from breez/optimize_prune_zombie_channels
Optimize prune zombie channels
This commit is contained in:
@@ -760,22 +760,31 @@ func (r *ChannelRouter) syncGraphWithChain() error {
|
||||
// usually signals that a channel has been closed on-chain. We do this
|
||||
// periodically to keep a healthy, lively routing table.
|
||||
func (r *ChannelRouter) pruneZombieChans() error {
|
||||
var chansToPrune []uint64
|
||||
chansToPrune := make(map[uint64]struct{})
|
||||
chanExpiry := r.cfg.ChannelPruneExpiry
|
||||
|
||||
log.Infof("Examining channel graph for zombie channels")
|
||||
|
||||
// A helper method to detect if the channel belongs to this node
|
||||
isSelfChannelEdge := func(info *channeldb.ChannelEdgeInfo) bool {
|
||||
return info.NodeKey1Bytes == r.selfNode.PubKeyBytes ||
|
||||
info.NodeKey2Bytes == r.selfNode.PubKeyBytes
|
||||
}
|
||||
|
||||
// First, we'll collect all the channels which are eligible for garbage
|
||||
// collection due to being zombies.
|
||||
filterPruneChans := func(info *channeldb.ChannelEdgeInfo,
|
||||
e1, e2 *channeldb.ChannelEdgePolicy) error {
|
||||
|
||||
// Exit early in case this channel is already marked to be pruned
|
||||
if _, markedToPrune := chansToPrune[info.ChannelID]; markedToPrune {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We'll ensure that we don't attempt to prune our *own*
|
||||
// channels from the graph, as in any case this should be
|
||||
// re-advertised by the sub-system above us.
|
||||
if info.NodeKey1Bytes == r.selfNode.PubKeyBytes ||
|
||||
info.NodeKey2Bytes == r.selfNode.PubKeyBytes {
|
||||
|
||||
if isSelfChannelEdge(info) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -800,34 +809,9 @@ func (r *ChannelRouter) pruneZombieChans() error {
|
||||
}
|
||||
}
|
||||
|
||||
isZombieChan := e1Zombie && e2Zombie
|
||||
|
||||
// If AssumeChannelValid is present and we've determined the
|
||||
// channel is not a zombie, we'll look at the disabled bit for
|
||||
// both edges. If they're both disabled, then we can interpret
|
||||
// this as the channel being closed and can prune it from our
|
||||
// graph.
|
||||
if r.cfg.AssumeChannelValid && !isZombieChan {
|
||||
var e1Disabled, e2Disabled bool
|
||||
if e1 != nil {
|
||||
e1Disabled = e1.IsDisabled()
|
||||
log.Tracef("Edge #1 of ChannelID(%v) "+
|
||||
"disabled=%v", info.ChannelID,
|
||||
e1Disabled)
|
||||
}
|
||||
if e2 != nil {
|
||||
e2Disabled = e2.IsDisabled()
|
||||
log.Tracef("Edge #2 of ChannelID(%v) "+
|
||||
"disabled=%v", info.ChannelID,
|
||||
e2Disabled)
|
||||
}
|
||||
|
||||
isZombieChan = e1Disabled && e2Disabled
|
||||
}
|
||||
|
||||
// If the channel is not considered zombie, we can move on to
|
||||
// the next.
|
||||
if !isZombieChan {
|
||||
if !e1Zombie || !e2Zombie {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -835,25 +819,57 @@ func (r *ChannelRouter) pruneZombieChans() error {
|
||||
info.ChannelID)
|
||||
|
||||
// TODO(roasbeef): add ability to delete single directional edge
|
||||
chansToPrune = append(chansToPrune, info.ChannelID)
|
||||
chansToPrune[info.ChannelID] = struct{}{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err := r.cfg.Graph.ForEachChannel(filterPruneChans)
|
||||
// If AssumeChannelValid is present we'll look at the disabled bit for both
|
||||
// edges. If they're both disabled, then we can interpret this as the
|
||||
// channel being closed and can prune it from our graph.
|
||||
if r.cfg.AssumeChannelValid {
|
||||
disabledChanIDs, err := r.cfg.Graph.DisabledChannelIDs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get disabled channels ids "+
|
||||
"chans: %v", err)
|
||||
}
|
||||
|
||||
disabledEdges, err := r.cfg.Graph.FetchChanInfos(disabledChanIDs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch disabled channels edges "+
|
||||
"chans: %v", err)
|
||||
}
|
||||
|
||||
// Ensuring we won't prune our own channel from the graph.
|
||||
for _, disabledEdge := range disabledEdges {
|
||||
if !isSelfChannelEdge(disabledEdge.Info) {
|
||||
chansToPrune[disabledEdge.Info.ChannelID] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startTime := time.Unix(0, 0)
|
||||
endTime := time.Now().Add(-1 * chanExpiry)
|
||||
oldEdges, err := r.cfg.Graph.ChanUpdatesInHorizon(startTime, endTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to filter local zombie channels: "+
|
||||
"%v", err)
|
||||
return fmt.Errorf("unable to fetch expired channel updates "+
|
||||
"chans: %v", err)
|
||||
}
|
||||
|
||||
for _, u := range oldEdges {
|
||||
filterPruneChans(u.Info, u.Policy1, u.Policy2)
|
||||
}
|
||||
|
||||
log.Infof("Pruning %v zombie channels", len(chansToPrune))
|
||||
|
||||
// With the set of zombie-like channels obtained, we'll do another pass
|
||||
// to delete them from the channel graph.
|
||||
for _, chanID := range chansToPrune {
|
||||
toPrune := make([]uint64, 0, len(chansToPrune))
|
||||
for chanID := range chansToPrune {
|
||||
toPrune = append(toPrune, chanID)
|
||||
log.Tracef("Pruning zombie channel with ChannelID(%v)", chanID)
|
||||
}
|
||||
if err := r.cfg.Graph.DeleteChannelEdges(chansToPrune...); err != nil {
|
||||
if err := r.cfg.Graph.DeleteChannelEdges(toPrune...); err != nil {
|
||||
return fmt.Errorf("unable to delete zombie channels: %v", err)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user