From d1f121cbc6fc78c0f7838ff6e0a7de46d190a330 Mon Sep 17 00:00:00 2001 From: carla Date: Tue, 16 Feb 2021 13:31:50 +0200 Subject: [PATCH] liquidity: move swap suggestions behind interface --- liquidity/interface.go | 47 ++++++++++++++++++++++++++++++++++++++++ liquidity/liquidity.go | 49 ++++++++++++++++++++++++++++++------------ 2 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 liquidity/interface.go diff --git a/liquidity/interface.go b/liquidity/interface.go new file mode 100644 index 0000000..a2386ed --- /dev/null +++ b/liquidity/interface.go @@ -0,0 +1,47 @@ +package liquidity + +import ( + "github.com/btcsuite/btcutil" + "github.com/lightninglabs/loop" + "github.com/lightningnetwork/lnd/lnwire" +) + +// swapSuggestion is an interface implemented by suggested swaps for our +// different swap types. This interface is used to allow us to handle different +// swap types with the same autoloop logic. +type swapSuggestion interface { + // fees returns the highest possible fee amount we could pay for a swap + // in satoshis. + fees() btcutil.Amount + + // amount returns the swap amount in satoshis. + amount() btcutil.Amount + + // channels returns the set of channels involved in the swap. + channels() []lnwire.ShortChannelID +} + +type loopOutSwapSuggestion struct { + loop.OutRequest +} + +func (l *loopOutSwapSuggestion) amount() btcutil.Amount { + return l.Amount +} + +func (l *loopOutSwapSuggestion) fees() btcutil.Amount { + return worstCaseOutFees( + l.MaxPrepayRoutingFee, l.MaxSwapRoutingFee, l.MaxSwapFee, + l.MaxMinerFee, l.MaxPrepayAmount, + ) +} + +func (l *loopOutSwapSuggestion) channels() []lnwire.ShortChannelID { + channels := make([]lnwire.ShortChannelID, len(l.OutgoingChanSet)) + + for i, id := range l.OutgoingChanSet { + channels[i] = lnwire.NewShortChanIDFromInt(id) + } + + return channels +} diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index bf65014..c0007e7 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -574,6 +574,17 @@ func newSuggestions() *Suggestions { } } +func (s *Suggestions) addSwap(swap swapSuggestion) error { + out, ok := swap.(*loopOutSwapSuggestion) + if !ok { + return fmt.Errorf("unexpected swap type: %T", swap) + } + + s.OutSwaps = append(s.OutSwaps, out.OutRequest) + + return nil +} + // singleReasonSuggestion is a helper function which returns a set of // suggestions where all of our rules are disqualified due to a reason that // applies to all of them (such as being out of budget). @@ -693,7 +704,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( traffic := m.currentSwapTraffic(loopOut, loopIn) var ( - suggestions []loop.OutRequest + suggestions []swapSuggestion disqualified = make(map[lnwire.ShortChannelID]Reason) ) @@ -719,7 +730,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( return nil, err } - suggestions = append(suggestions, *suggestion) + suggestions = append(suggestions, suggestion) } // Finally, run through all possible swaps, excluding swaps that are @@ -736,7 +747,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( // Sort suggestions by amount in descending order. sort.SliceStable(suggestions, func(i, j int) bool { - return suggestions[i].Amount > suggestions[j].Amount + return suggestions[i].amount() > suggestions[j].amount() }) // Run through our suggested swaps in descending order of amount and @@ -745,11 +756,14 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( // setReason is a helper that adds a swap's channels to our disqualified // list with the reason provided. - setReason := func(reason Reason, swap loop.OutRequest) { - for _, id := range swap.OutgoingChanSet { - chanID := lnwire.NewShortChanIDFromInt(id) + setReason := func(reason Reason, swap swapSuggestion) { + for _, channel := range swap.channels() { + _, ok := m.params.ChannelRules[channel] + if !ok { + continue + } - resp.DisqualifiedChans[chanID] = reason + resp.DisqualifiedChans[channel] = reason } } @@ -773,17 +787,17 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( continue } - fees := worstCaseOutFees( - swap.MaxPrepayRoutingFee, swap.MaxSwapRoutingFee, - swap.MaxSwapFee, swap.MaxMinerFee, swap.MaxPrepayAmount, - ) + fees := swap.fees() // If the maximum fee we expect our swap to use is less than the // amount we have available, we add it to our set of swaps that // fall within the budget and decrement our available amount. if fees <= available { available -= fees - resp.OutSwaps = append(resp.OutSwaps, swap) + + if err := resp.addSwap(swap); err != nil { + return nil, err + } } else { setReason(ReasonBudgetInsufficient, swap) } @@ -796,7 +810,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) ( // swap request for the rule provided. func (m *Manager) suggestSwap(ctx context.Context, traffic *swapTraffic, balance *balances, rule *ThresholdRule, restrictions *Restrictions, - autoloop bool) (*loop.OutRequest, error) { + autoloop bool) (swapSuggestion, error) { // Check whether we can perform a swap. err := traffic.maySwap(balance.pubkey, balance.channelID) @@ -811,7 +825,14 @@ func (m *Manager) suggestSwap(ctx context.Context, traffic *swapTraffic, return nil, newReasonError(ReasonLiquidityOk) } - return m.loopOutSwap(ctx, amount, balance, autoloop) + swap, err := m.loopOutSwap(ctx, amount, balance, autoloop) + if err != nil { + return nil, err + } + + return &loopOutSwapSuggestion{ + OutRequest: *swap, + }, nil } // loopOutSwap creates a loop out swap with the amount provided for the balance