mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-11-28 15:13:04 +01:00
routing: prune channels with disabled bit set on both edges
In this commit, we add an additional heuristic when running with AssumeChannelValid. Since AssumeChannelValid being present assumes that we're not able to quickly determine whether channels are valid, we also assume that any channels with the disabled bit set on both sides are considered zombie. This should be relatively safe to do, since the disabled bits are usually set when the channel is closed on-chain. In the case that they aren't, we'll have to wait until both edges haven't had a new update within two weeks to prune them.
This commit is contained in:
@@ -613,13 +613,15 @@ func (r *ChannelRouter) syncGraphWithChain() error {
|
||||
|
||||
// pruneZombieChans is a method that will be called periodically to prune out
|
||||
// any "zombie" channels. We consider channels zombies if *both* edges haven't
|
||||
// been updated since our zombie horizon. We do this periodically to keep a
|
||||
// health, lively routing table.
|
||||
// been updated since our zombie horizon. If AssumeChannelValid is present,
|
||||
// we'll also consider channels zombies if *both* edges are disabled. This
|
||||
// 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 []wire.OutPoint
|
||||
chanExpiry := r.cfg.ChannelPruneExpiry
|
||||
|
||||
log.Infof("Examining Channel Graph for zombie channels")
|
||||
log.Infof("Examining channel graph for zombie channels")
|
||||
|
||||
// First, we'll collect all the channels which are eligible for garbage
|
||||
// collection due to being zombies.
|
||||
@@ -655,20 +657,49 @@ func (r *ChannelRouter) pruneZombieChans() error {
|
||||
info.ChannelPoint, e2.LastUpdate)
|
||||
}
|
||||
}
|
||||
if e1Zombie && e2Zombie {
|
||||
log.Debugf("ChannelPoint(%v) is a zombie, collecting "+
|
||||
"to prune", info.ChannelPoint)
|
||||
|
||||
// TODO(roasbeef): add ability to delete single
|
||||
// directional edge
|
||||
chansToPrune = append(chansToPrune, info.ChannelPoint)
|
||||
isZombieChan := e1Zombie && e2Zombie
|
||||
|
||||
// As we're detecting this as a zombie channel, we'll
|
||||
// add this to the set of recently rejected items so we
|
||||
// don't re-accept it shortly after.
|
||||
r.rejectCache[info.ChannelID] = struct{}{}
|
||||
// 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 {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debugf("ChannelPoint(%v) is a zombie, collecting to prune",
|
||||
info.ChannelPoint)
|
||||
|
||||
// TODO(roasbeef): add ability to delete single directional edge
|
||||
chansToPrune = append(chansToPrune, info.ChannelPoint)
|
||||
|
||||
// As we're detecting this as a zombie channel, we'll add this
|
||||
// to the set of recently rejected items so we don't re-accept
|
||||
// it shortly after.
|
||||
r.rejectCache[info.ChannelID] = struct{}{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -677,21 +708,22 @@ func (r *ChannelRouter) pruneZombieChans() error {
|
||||
|
||||
err := r.cfg.Graph.ForEachChannel(filterPruneChans)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to filter local zombie "+
|
||||
"chans: %v", err)
|
||||
return fmt.Errorf("unable to filter local zombie channels: "+
|
||||
"%v", err)
|
||||
}
|
||||
|
||||
log.Infof("Pruning %v Zombie Channels", len(chansToPrune))
|
||||
log.Infof("Pruning %v zombie channels", len(chansToPrune))
|
||||
|
||||
// With the set zombie-like channels obtained, we'll do another pass to
|
||||
// delete al zombie channels from the channel graph.
|
||||
// With the set of zombie-like channels obtained, we'll do another pass
|
||||
// to delete them from the channel graph.
|
||||
for _, chanToPrune := range chansToPrune {
|
||||
log.Tracef("Pruning zombie chan ChannelPoint(%v)", chanToPrune)
|
||||
log.Tracef("Pruning zombie channel with ChannelPoint(%v)",
|
||||
chanToPrune)
|
||||
|
||||
err := r.cfg.Graph.DeleteChannelEdge(&chanToPrune)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to prune zombie "+
|
||||
"chans: %v", err)
|
||||
return fmt.Errorf("unable to prune zombie with "+
|
||||
"ChannelPoint(%v): %v", chanToPrune, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,7 +938,7 @@ func (r *ChannelRouter) networkHandler() {
|
||||
// for pruning.
|
||||
case <-graphPruneTicker.C:
|
||||
if err := r.pruneZombieChans(); err != nil {
|
||||
log.Errorf("unable to prune zombies: %v", err)
|
||||
log.Errorf("Unable to prune zombies: %v", err)
|
||||
}
|
||||
|
||||
// The router has been signalled to exit, to we exit our main
|
||||
|
||||
Reference in New Issue
Block a user