diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index b9a8f9c..481fe5c 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -652,25 +652,32 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( return nil, nil } - eligible, err := m.getEligibleChannels(ctx, loopOut, loopIn) + channels, err := m.cfg.Lnd.Client.ListChannels(ctx) if err != nil { return nil, err } + // Get a summary of the channels and peers that are not eligible due + // to ongoing swaps. + traffic := m.currentSwapTraffic(loopOut, loopIn) + var suggestions []loop.OutRequest - for _, channel := range eligible { - channelID := lnwire.NewShortChanIDFromInt(channel.ChannelID) - rule, ok := m.params.ChannelRules[channelID] + + for _, channel := range channels { + balance := newBalances(channel) + + rule, ok := m.params.ChannelRules[balance.channelID] if !ok { continue } - balance := newBalances(channel) - - suggestion := rule.suggestSwap(balance, restrictions) + if !traffic.maySwap(channel.PubKeyBytes, balance.channelID) { + continue + } // We can have nil suggestions in the case where no action is // required, so we skip over them. + suggestion := rule.suggestSwap(balance, restrictions) if suggestion == nil { continue } @@ -928,17 +935,13 @@ func (m *Manager) checkExistingAutoLoops(ctx context.Context, return &summary, nil } -// getEligibleChannels takes lists of our existing loop out and in swaps, and -// gets a list of channels that are not currently being utilized for a swap. -func (m *Manager) getEligibleChannels(ctx context.Context, - loopOut []*loopdb.LoopOut, loopIn []*loopdb.LoopIn) ( - []lndclient.ChannelInfo, error) { +// currentSwapTraffic examines our existing swaps and returns a summary of the +// current activity which can be used to determine whether we should perform +// any swaps. +func (m *Manager) currentSwapTraffic(loopOut []*loopdb.LoopOut, + loopIn []*loopdb.LoopIn) *swapTraffic { - var ( - existingOut = make(map[lnwire.ShortChannelID]bool) - existingIn = make(map[route.Vertex]bool) - failedOut = make(map[lnwire.ShortChannelID]time.Time) - ) + traffic := newSwapTraffic() // Failure cutoff is the most recent failure timestamp we will still // consider a channel eligible. Any channels involved in swaps that have @@ -971,7 +974,7 @@ func (m *Manager) getEligibleChannels(ctx context.Context, id, ) - failedOut[chanID] = failedAt + traffic.failedLoopOut[chanID] = failedAt } } } @@ -988,7 +991,7 @@ func (m *Manager) getEligibleChannels(ctx context.Context, for _, id := range chanSet { chanID := lnwire.NewShortChanIDFromInt(id) - existingOut[chanID] = true + traffic.ongoingLoopOut[chanID] = true } } @@ -1003,51 +1006,55 @@ func (m *Manager) getEligibleChannels(ctx context.Context, continue } - existingIn[*in.Contract.LastHop] = true + traffic.ongoingLoopIn[*in.Contract.LastHop] = true } - channels, err := m.cfg.Lnd.Client.ListChannels(ctx) - if err != nil { - return nil, err - } + return traffic +} - // Run through our set of channels and skip over any channels that - // are currently being utilized by a restricted swap (where restricted - // means that a loop out limited channels, or a loop in limited last - // hop). - var eligible []lndclient.ChannelInfo - for _, channel := range channels { - shortID := lnwire.NewShortChanIDFromInt(channel.ChannelID) +// swapTraffic contains a summary of our current and previously failed swaps. +type swapTraffic struct { + ongoingLoopOut map[lnwire.ShortChannelID]bool + ongoingLoopIn map[route.Vertex]bool + failedLoopOut map[lnwire.ShortChannelID]time.Time +} - lastFail, recentFail := failedOut[shortID] - if recentFail { - log.Debugf("Channel: %v not eligible for "+ - "suggestions, was part of a failed swap at: %v", - channel.ChannelID, lastFail) +func newSwapTraffic() *swapTraffic { + return &swapTraffic{ + ongoingLoopOut: make(map[lnwire.ShortChannelID]bool), + ongoingLoopIn: make(map[route.Vertex]bool), + failedLoopOut: make(map[lnwire.ShortChannelID]time.Time), + } +} - continue - } +// maySwap returns a boolean that indicates whether we may perform a swap for a +// peer and its set of channels. +func (s *swapTraffic) maySwap(peer route.Vertex, + chanID lnwire.ShortChannelID) bool { - if existingOut[shortID] { - log.Debugf("Channel: %v not eligible for "+ - "suggestions, ongoing loop out utilizing "+ - "channel", channel.ChannelID) + lastFail, recentFail := s.failedLoopOut[chanID] + if recentFail { + log.Debugf("Channel: %v not eligible for suggestions, was "+ + "part of a failed swap at: %v", chanID, lastFail) - continue - } + return false + } - if existingIn[channel.PubKeyBytes] { - log.Debugf("Channel: %v not eligible for "+ - "suggestions, ongoing loop in utilizing "+ - "peer", channel.ChannelID) + if s.ongoingLoopOut[chanID] { + log.Debugf("Channel: %v not eligible for suggestions, "+ + "ongoing loop out utilizing channel", chanID) - continue - } + return false + } + + if s.ongoingLoopIn[peer] { + log.Debugf("Peer: %x not eligible for suggestions ongoing "+ + "loop in utilizing peer", peer) - eligible = append(eligible, channel) + return false } - return eligible, nil + return true } // checkFeeLimits takes a set of fees for a swap and checks whether they exceed