liquidity: add type to rules

In preparation for adding loop in swaps, we relate liquidity rules
to a specific type of swap that we want to dispatch. This allows us
to use a single rule format for multiple swap types.
pull/433/head
carla 2 years ago
parent 00c2d4e5f0
commit 25b8d20f75
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91

@ -27,7 +27,7 @@ func TestAutoLoopDisabled(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -95,7 +95,7 @@ func TestAutoLoopEnabled(t *testing.T) {
swapFeePPM, routeFeePPM, prepayFeePPM, maxMiner, swapFeePPM, routeFeePPM, prepayFeePPM, maxMiner,
prepayAmount, 20000, prepayAmount, 20000,
), ),
ChannelRules: map[lnwire.ShortChannelID]*ThresholdRule{ ChannelRules: map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
chanID2: chanRule, chanID2: chanRule,
}, },
@ -312,10 +312,10 @@ func TestCompositeRules(t *testing.T) {
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
SweepConfTarget: 10, SweepConfTarget: 10,
ChannelRules: map[lnwire.ShortChannelID]*ThresholdRule{ ChannelRules: map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
}, },
PeerRules: map[route.Vertex]*ThresholdRule{ PeerRules: map[route.Vertex]*SwapRule{
peer2: chanRule, peer2: chanRule,
}, },
} }

@ -97,8 +97,8 @@ var (
defaultParameters = Parameters{ defaultParameters = Parameters{
AutoFeeBudget: defaultBudget, AutoFeeBudget: defaultBudget,
MaxAutoInFlight: defaultMaxInFlight, MaxAutoInFlight: defaultMaxInFlight,
ChannelRules: make(map[lnwire.ShortChannelID]*ThresholdRule), ChannelRules: make(map[lnwire.ShortChannelID]*SwapRule),
PeerRules: make(map[route.Vertex]*ThresholdRule), PeerRules: make(map[route.Vertex]*SwapRule),
FailureBackOff: defaultFailureBackoff, FailureBackOff: defaultFailureBackoff,
SweepConfTarget: defaultConfTarget, SweepConfTarget: defaultConfTarget,
FeeLimit: defaultFeePortion(), FeeLimit: defaultFeePortion(),
@ -216,13 +216,13 @@ type Parameters struct {
// ChannelRules maps a short channel ID to a rule that describes how we // ChannelRules maps a short channel ID to a rule that describes how we
// would like liquidity to be managed. These rules and PeerRules are // would like liquidity to be managed. These rules and PeerRules are
// exclusively set to prevent overlap between peer and channel rules. // exclusively set to prevent overlap between peer and channel rules.
ChannelRules map[lnwire.ShortChannelID]*ThresholdRule ChannelRules map[lnwire.ShortChannelID]*SwapRule
// PeerRules maps a peer's pubkey to a rule that applies to all the // PeerRules maps a peer's pubkey to a rule that applies to all the
// channels that we have with the peer collectively. These rules and // channels that we have with the peer collectively. These rules and
// ChannelRules are exclusively set to prevent overlap between peer // ChannelRules are exclusively set to prevent overlap between peer
// and channel rules map to avoid ambiguity. // and channel rules map to avoid ambiguity.
PeerRules map[route.Vertex]*ThresholdRule PeerRules map[route.Vertex]*SwapRule
} }
// String returns the string representation of our parameters. // String returns the string representation of our parameters.
@ -473,7 +473,7 @@ func (m *Manager) SetParameters(ctx context.Context, params Parameters) error {
func cloneParameters(params Parameters) Parameters { func cloneParameters(params Parameters) Parameters {
paramCopy := params paramCopy := params
paramCopy.ChannelRules = make( paramCopy.ChannelRules = make(
map[lnwire.ShortChannelID]*ThresholdRule, map[lnwire.ShortChannelID]*SwapRule,
len(params.ChannelRules), len(params.ChannelRules),
) )
@ -483,7 +483,7 @@ func cloneParameters(params Parameters) Parameters {
} }
paramCopy.PeerRules = make( paramCopy.PeerRules = make(
map[route.Vertex]*ThresholdRule, map[route.Vertex]*SwapRule,
len(params.PeerRules), len(params.PeerRules),
) )
@ -841,7 +841,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
// suggestSwap checks whether we can currently perform a swap, and creates a // suggestSwap checks whether we can currently perform a swap, and creates a
// swap request for the rule provided. // swap request for the rule provided.
func (m *Manager) suggestSwap(ctx context.Context, traffic *swapTraffic, func (m *Manager) suggestSwap(ctx context.Context, traffic *swapTraffic,
balance *balances, rule *ThresholdRule, restrictions *Restrictions, balance *balances, rule *SwapRule, restrictions *Restrictions,
autoloop bool) (swapSuggestion, error) { autoloop bool) (swapSuggestion, error) {
// First, check whether this peer/channel combination is already in use // First, check whether this peer/channel combination is already in use

@ -47,7 +47,10 @@ var (
} }
// chanRule is a rule that produces chan1Rec. // chanRule is a rule that produces chan1Rec.
chanRule = NewThresholdRule(50, 0) chanRule = &SwapRule{
ThresholdRule: NewThresholdRule(50, 0),
Type: swap.TypeOut,
}
testQuote = &loop.LoopOutQuote{ testQuote = &loop.LoopOutQuote{
SwapFee: btcutil.Amount(5), SwapFee: btcutil.Amount(5),
@ -188,7 +191,10 @@ func TestParameters(t *testing.T) {
require.Equal(t, defaultParameters, startParams) require.Equal(t, defaultParameters, startParams)
// Mutate the parameters returned by our get function. // Mutate the parameters returned by our get function.
startParams.ChannelRules[chanID] = NewThresholdRule(1, 1) startParams.ChannelRules[chanID] = &SwapRule{
ThresholdRule: NewThresholdRule(1, 1),
Type: swap.TypeOut,
}
// Make sure that we have not mutated the liquidity manager's params // Make sure that we have not mutated the liquidity manager's params
// by making this change. // by making this change.
@ -197,9 +203,13 @@ func TestParameters(t *testing.T) {
// Provide a valid set of parameters and validate assert that they are // Provide a valid set of parameters and validate assert that they are
// set. // set.
originalRule := NewThresholdRule(10, 10) originalRule := &SwapRule{
ThresholdRule: NewThresholdRule(10, 10),
Type: swap.TypeOut,
}
expected := defaultParameters expected := defaultParameters
expected.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ expected.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID: originalRule, chanID: originalRule,
} }
@ -208,15 +218,21 @@ func TestParameters(t *testing.T) {
// Check that changing the parameters we just set does not mutate // Check that changing the parameters we just set does not mutate
// our liquidity manager's parameters. // our liquidity manager's parameters.
expected.ChannelRules[chanID] = NewThresholdRule(11, 11) expected.ChannelRules[chanID] = &SwapRule{
ThresholdRule: NewThresholdRule(11, 11),
Type: swap.TypeOut,
}
params = manager.GetParameters() params = manager.GetParameters()
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, originalRule, params.ChannelRules[chanID]) require.Equal(t, originalRule, params.ChannelRules[chanID])
// Set invalid parameters and assert that we fail. // Set invalid parameters and assert that we fail.
expected.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ expected.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
lnwire.NewShortChanIDFromInt(0): NewThresholdRule(1, 2), lnwire.NewShortChanIDFromInt(0): {
ThresholdRule: NewThresholdRule(1, 2),
Type: swap.TypeOut,
},
} }
err = manager.SetParameters(context.Background(), expected) err = manager.SetParameters(context.Background(), expected)
require.Equal(t, ErrZeroChannelID, err) require.Equal(t, ErrZeroChannelID, err)
@ -310,7 +326,7 @@ func TestRestrictedSuggestions(t *testing.T) {
), ),
} }
chanRules = map[lnwire.ShortChannelID]*ThresholdRule{ chanRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
chanID2: chanRule, chanID2: chanRule,
} }
@ -321,8 +337,8 @@ func TestRestrictedSuggestions(t *testing.T) {
channels []lndclient.ChannelInfo channels []lndclient.ChannelInfo
loopOut []*loopdb.LoopOut loopOut []*loopdb.LoopOut
loopIn []*loopdb.LoopIn loopIn []*loopdb.LoopIn
chanRules map[lnwire.ShortChannelID]*ThresholdRule chanRules map[lnwire.ShortChannelID]*SwapRule
peerRules map[route.Vertex]*ThresholdRule peerRules map[route.Vertex]*SwapRule
expected *Suggestions expected *Suggestions
}{ }{
{ {
@ -511,8 +527,11 @@ func TestRestrictedSuggestions(t *testing.T) {
Contract: chan1Out, Contract: chan1Out,
}, },
}, },
peerRules: map[route.Vertex]*ThresholdRule{ peerRules: map[route.Vertex]*SwapRule{
peer1: NewThresholdRule(0, 50), peer1: {
ThresholdRule: NewThresholdRule(0, 50),
Type: swap.TypeOut,
},
}, },
expected: &Suggestions{ expected: &Suggestions{
DisqualifiedChans: noneDisqualified, DisqualifiedChans: noneDisqualified,
@ -629,7 +648,7 @@ func TestSweepFeeLimit(t *testing.T) {
ppmToSat(7500, defaultPrepayRoutingFeePPM) + ppmToSat(7500, defaultPrepayRoutingFeePPM) +
ppmToSat(7500, defaultRoutingFeePPM) ppmToSat(7500, defaultRoutingFeePPM)
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -654,21 +673,21 @@ func TestSuggestSwaps(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
channels []lndclient.ChannelInfo channels []lndclient.ChannelInfo
rules map[lnwire.ShortChannelID]*ThresholdRule rules map[lnwire.ShortChannelID]*SwapRule
peerRules map[route.Vertex]*ThresholdRule peerRules map[route.Vertex]*SwapRule
suggestions *Suggestions suggestions *Suggestions
err error err error
}{ }{
{ {
name: "no rules", name: "no rules",
channels: singleChannel, channels: singleChannel,
rules: map[lnwire.ShortChannelID]*ThresholdRule{}, rules: map[lnwire.ShortChannelID]*SwapRule{},
err: ErrNoRules, err: ErrNoRules,
}, },
{ {
name: "loop out", name: "loop out",
channels: singleChannel, channels: singleChannel,
rules: map[lnwire.ShortChannelID]*ThresholdRule{ rules: map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
}, },
suggestions: &Suggestions{ suggestions: &Suggestions{
@ -682,8 +701,11 @@ func TestSuggestSwaps(t *testing.T) {
{ {
name: "no rule for channel", name: "no rule for channel",
channels: singleChannel, channels: singleChannel,
rules: map[lnwire.ShortChannelID]*ThresholdRule{ rules: map[lnwire.ShortChannelID]*SwapRule{
chanID2: NewThresholdRule(10, 10), chanID2: {
ThresholdRule: NewThresholdRule(10, 10),
Type: swap.TypeOut,
},
}, },
suggestions: &Suggestions{ suggestions: &Suggestions{
DisqualifiedChans: noneDisqualified, DisqualifiedChans: noneDisqualified,
@ -715,9 +737,15 @@ func TestSuggestSwaps(t *testing.T) {
RemoteBalance: 3000, RemoteBalance: 3000,
}, },
}, },
peerRules: map[route.Vertex]*ThresholdRule{ peerRules: map[route.Vertex]*SwapRule{
peer1: NewThresholdRule(80, 0), peer1: {
peer2: NewThresholdRule(40, 50), ThresholdRule: NewThresholdRule(80, 0),
Type: swap.TypeOut,
},
peer2: {
ThresholdRule: NewThresholdRule(40, 50),
Type: swap.TypeOut,
},
}, },
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
@ -869,7 +897,7 @@ func TestFeeLimits(t *testing.T) {
ppmToSat(7500, defaultPrepayRoutingFeePPM) + ppmToSat(7500, defaultPrepayRoutingFeePPM) +
ppmToSat(7500, defaultRoutingFeePPM) ppmToSat(7500, defaultRoutingFeePPM)
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -1061,7 +1089,7 @@ func TestFeeBudget(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
chanID2: chanRule, chanID2: chanRule,
} }
@ -1100,7 +1128,7 @@ func TestInFlightLimit(t *testing.T) {
existingSwaps []*loopdb.LoopOut existingSwaps []*loopdb.LoopOut
// peerRules will only be set (instead of test default values) // peerRules will only be set (instead of test default values)
// is it is non-nil. // is it is non-nil.
peerRules map[route.Vertex]*ThresholdRule peerRules map[route.Vertex]*SwapRule
suggestions *Suggestions suggestions *Suggestions
}{ }{
{ {
@ -1189,9 +1217,15 @@ func TestInFlightLimit(t *testing.T) {
// Create two peer-level rules, both in need of a swap, // Create two peer-level rules, both in need of a swap,
// but peer 1 needs a larger swap so will be // but peer 1 needs a larger swap so will be
// prioritized. // prioritized.
peerRules: map[route.Vertex]*ThresholdRule{ peerRules: map[route.Vertex]*SwapRule{
peer1: NewThresholdRule(50, 0), peer1: {
peer2: NewThresholdRule(40, 0), ThresholdRule: NewThresholdRule(50, 0),
Type: swap.TypeOut,
},
peer2: {
ThresholdRule: NewThresholdRule(40, 0),
Type: swap.TypeOut,
},
}, },
suggestions: &Suggestions{ suggestions: &Suggestions{
OutSwaps: []loop.OutRequest{ OutSwaps: []loop.OutRequest{
@ -1224,7 +1258,7 @@ func TestInFlightLimit(t *testing.T) {
params.PeerRules = testCase.peerRules params.PeerRules = testCase.peerRules
} else { } else {
params.ChannelRules = params.ChannelRules =
map[lnwire.ShortChannelID]*ThresholdRule{ map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
chanID2: chanRule, chanID2: chanRule,
} }
@ -1364,7 +1398,7 @@ func TestSizeRestrictions(t *testing.T) {
params := defaultParameters params := defaultParameters
params.ClientRestrictions = testCase.clientRestrictions params.ClientRestrictions = testCase.clientRestrictions
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -1522,7 +1556,7 @@ func TestFeePercentage(t *testing.T) {
params := defaultParameters params := defaultParameters
params.FeeLimit = NewFeePortion(testCase.feePPM) params.FeeLimit = NewFeePortion(testCase.feePPM)
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -1572,7 +1606,7 @@ func testSuggestSwaps(t *testing.T, setup *testSuggestSwapsSetup,
} }
params := defaultParameters params := defaultParameters
params.ChannelRules = map[lnwire.ShortChannelID]*ThresholdRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
chanID2: chanRule, chanID2: chanRule,
} }

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightninglabs/loop/swap"
) )
var ( var (
@ -19,6 +20,12 @@ var (
"percentages must be < 100") "percentages must be < 100")
) )
// SwapRule is a liquidity rule with a specific swap type.
type SwapRule struct {
*ThresholdRule
swap.Type
}
// ThresholdRule is a liquidity rule that implements minimum incoming and // ThresholdRule is a liquidity rule that implements minimum incoming and
// outgoing liquidity threshold. // outgoing liquidity threshold.
type ThresholdRule struct { type ThresholdRule struct {

@ -750,7 +750,7 @@ func (s *swapClientServer) GetLiquidityParams(_ context.Context,
} }
func newRPCRule(channelID uint64, peer []byte, func newRPCRule(channelID uint64, peer []byte,
rule *liquidity.ThresholdRule) *looprpc.LiquidityRule { rule *liquidity.SwapRule) *looprpc.LiquidityRule {
return &looprpc.LiquidityRule{ return &looprpc.LiquidityRule{
ChannelId: channelID, ChannelId: channelID,
@ -781,10 +781,10 @@ func (s *swapClientServer) SetLiquidityParams(ctx context.Context,
AutoFeeBudget: btcutil.Amount(in.Parameters.AutoloopBudgetSat), AutoFeeBudget: btcutil.Amount(in.Parameters.AutoloopBudgetSat),
MaxAutoInFlight: int(in.Parameters.AutoMaxInFlight), MaxAutoInFlight: int(in.Parameters.AutoMaxInFlight),
ChannelRules: make( ChannelRules: make(
map[lnwire.ShortChannelID]*liquidity.ThresholdRule, map[lnwire.ShortChannelID]*liquidity.SwapRule,
), ),
PeerRules: make( PeerRules: make(
map[route.Vertex]*liquidity.ThresholdRule, map[route.Vertex]*liquidity.SwapRule,
), ),
ClientRestrictions: liquidity.Restrictions{ ClientRestrictions: liquidity.Restrictions{
Minimum: btcutil.Amount(in.Parameters.MinSwapAmount), Minimum: btcutil.Amount(in.Parameters.MinSwapAmount),
@ -890,16 +890,19 @@ func rpcToFee(req *looprpc.LiquidityParameters) (liquidity.FeeLimit,
} }
// rpcToRule switches on rpc rule type to convert to our rule interface. // rpcToRule switches on rpc rule type to convert to our rule interface.
func rpcToRule(rule *looprpc.LiquidityRule) (*liquidity.ThresholdRule, error) { func rpcToRule(rule *looprpc.LiquidityRule) (*liquidity.SwapRule, error) {
switch rule.Type { switch rule.Type {
case looprpc.LiquidityRuleType_UNKNOWN: case looprpc.LiquidityRuleType_UNKNOWN:
return nil, fmt.Errorf("rule type field must be set") return nil, fmt.Errorf("rule type field must be set")
case looprpc.LiquidityRuleType_THRESHOLD: case looprpc.LiquidityRuleType_THRESHOLD:
return liquidity.NewThresholdRule( return &liquidity.SwapRule{
int(rule.IncomingThreshold), ThresholdRule: liquidity.NewThresholdRule(
int(rule.OutgoingThreshold), int(rule.IncomingThreshold),
), nil int(rule.OutgoingThreshold),
),
Type: swap.TypeOut,
}, nil
default: default:
return nil, fmt.Errorf("unknown rule: %T", rule) return nil, fmt.Errorf("unknown rule: %T", rule)

Loading…
Cancel
Save