liquidity+loopd: refactor `SetParameters` to take a rpc request

This commit refactors the method `manager.SetParameters` to take a
`SetLiquidityParamsRequest`. As we'll see in the following commit, this
will enable us saving the params to disk more easily.
pull/493/head
yyforyongyu 2 years ago
parent 9c5ac0fb36
commit 8217ee31c3
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868

@ -179,7 +179,7 @@ func newAutoloopTestCtx(t *testing.T, parameters Parameters,
// Create a manager with our test config and set our starting set of
// parameters.
testCtx.manager = NewManager(cfg)
err := testCtx.manager.SetParameters(context.Background(), parameters)
err := testCtx.manager.setParameters(context.Background(), parameters)
assert.NoError(t, err)
<-done
return testCtx

@ -52,6 +52,8 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/ticker"
clientrpc "github.com/lightninglabs/loop/looprpc"
)
const (
@ -239,9 +241,24 @@ func (m *Manager) GetParameters() Parameters {
return cloneParameters(m.params)
}
// SetParameters takes an RPC request and calls the internal method to set
// parameters for the manager.
func (m *Manager) SetParameters(ctx context.Context,
req *clientrpc.LiquidityParameters) error {
params, err := rpcToParameters(req)
if err != nil {
return err
}
return m.setParameters(ctx, *params)
}
// SetParameters updates our current set of parameters if the new parameters
// provided are valid.
func (m *Manager) SetParameters(ctx context.Context, params Parameters) error {
func (m *Manager) setParameters(ctx context.Context,
params Parameters) error {
restrictions, err := m.cfg.Restrictions(ctx, swap.TypeOut)
if err != nil {
return err
@ -252,7 +269,9 @@ func (m *Manager) SetParameters(ctx context.Context, params Parameters) error {
return err
}
err = params.validate(m.cfg.MinimumConfirmations, channels, restrictions)
err = params.validate(
m.cfg.MinimumConfirmations, channels, restrictions,
)
if err != nil {
return err
}

@ -221,7 +221,7 @@ func TestParameters(t *testing.T) {
chanID: originalRule,
}
err := manager.SetParameters(context.Background(), expected)
err := manager.setParameters(context.Background(), expected)
require.NoError(t, err)
// Check that changing the parameters we just set does not mutate
@ -242,7 +242,7 @@ func TestParameters(t *testing.T) {
Type: swap.TypeOut,
},
}
err = manager.SetParameters(context.Background(), expected)
err = manager.setParameters(context.Background(), expected)
require.Equal(t, ErrZeroChannelID, err)
}
@ -1778,7 +1778,7 @@ func testSuggestSwaps(t *testing.T, setup *testSuggestSwapsSetup,
// them to use the rules set by the test.
manager := NewManager(setup.cfg)
err := manager.SetParameters(context.Background(), setup.params)
err := manager.setParameters(context.Background(), setup.params)
require.NoError(t, err)
actual, err := manager.SuggestSwaps(context.Background(), false)
@ -1960,7 +1960,7 @@ func TestCurrentTraffic(t *testing.T) {
params := m.GetParameters()
params.FailureBackOff = backoff
require.NoError(t, m.SetParameters(context.Background(), params))
require.NoError(t, m.setParameters(context.Background(), params))
actual := m.currentSwapTraffic(testCase.loopOut, testCase.loopIn)
require.Equal(t, testCase.expected, actual)

@ -9,8 +9,11 @@ import (
"github.com/btcsuite/btcd/btcutil"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/swap"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
clientrpc "github.com/lightninglabs/loop/looprpc"
)
var (
@ -271,3 +274,150 @@ func cloneParameters(params Parameters) Parameters {
return paramCopy
}
// rpcToFee converts the values provided over rpc to a fee limit interface,
// failing if an inconsistent set of fields are set.
func rpcToFee(req *clientrpc.LiquidityParameters) (FeeLimit, error) {
// Check which fee limit type we have values set for. If any fields
// relevant to our individual categories are set, we count that type
// as set.
isFeePPM := req.FeePpm != 0
isCategories := req.MaxSwapFeePpm != 0 || req.MaxRoutingFeePpm != 0 ||
req.MaxPrepayRoutingFeePpm != 0 || req.MaxMinerFeeSat != 0 ||
req.MaxPrepaySat != 0 || req.SweepFeeRateSatPerVbyte != 0
switch {
case isFeePPM && isCategories:
return nil, errors.New("set either fee ppm, or individual " +
"fee categories")
case isFeePPM:
return NewFeePortion(req.FeePpm), nil
case isCategories:
satPerKVbyte := chainfee.SatPerKVByte(
req.SweepFeeRateSatPerVbyte * 1000,
)
return NewFeeCategoryLimit(
req.MaxSwapFeePpm,
req.MaxRoutingFeePpm,
req.MaxPrepayRoutingFeePpm,
btcutil.Amount(req.MaxMinerFeeSat),
btcutil.Amount(req.MaxPrepaySat),
satPerKVbyte.FeePerKWeight(),
), nil
default:
return nil, errors.New("no fee categories set")
}
}
// rpcToRule switches on rpc rule type to convert to our rule interface.
func rpcToRule(rule *clientrpc.LiquidityRule) (*SwapRule, error) {
swapType := swap.TypeOut
if rule.SwapType == clientrpc.SwapType_LOOP_IN {
swapType = swap.TypeIn
}
switch rule.Type {
case clientrpc.LiquidityRuleType_UNKNOWN:
return nil, fmt.Errorf("rule type field must be set")
case clientrpc.LiquidityRuleType_THRESHOLD:
return &SwapRule{
ThresholdRule: NewThresholdRule(
int(rule.IncomingThreshold),
int(rule.OutgoingThreshold),
),
Type: swapType,
}, nil
default:
return nil, fmt.Errorf("unknown rule: %T", rule)
}
}
// rpcToParameters takes a `LiquidityParameters` and creates a `Parameters`
// from it.
func rpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters,
error) {
feeLimit, err := rpcToFee(req)
if err != nil {
return nil, err
}
params := &Parameters{
FeeLimit: feeLimit,
SweepConfTarget: req.SweepConfTarget,
FailureBackOff: time.Duration(req.FailureBackoffSec) *
time.Second,
Autoloop: req.Autoloop,
AutoFeeBudget: btcutil.Amount(req.AutoloopBudgetSat),
MaxAutoInFlight: int(req.AutoMaxInFlight),
ChannelRules: make(
map[lnwire.ShortChannelID]*SwapRule,
),
PeerRules: make(
map[route.Vertex]*SwapRule,
),
ClientRestrictions: Restrictions{
Minimum: btcutil.Amount(req.MinSwapAmount),
Maximum: btcutil.Amount(req.MaxSwapAmount),
},
HtlcConfTarget: req.HtlcConfTarget,
}
// Zero unix time is different to zero golang time.
if req.AutoloopBudgetStartSec != 0 {
params.AutoFeeStartDate = time.Unix(
int64(req.AutoloopBudgetStartSec), 0,
)
}
for _, rule := range req.Rules {
peerRule := rule.Pubkey != nil
chanRule := rule.ChannelId != 0
liquidityRule, err := rpcToRule(rule)
if err != nil {
return nil, err
}
switch {
case peerRule && chanRule:
return nil, fmt.Errorf("cannot set channel: %v and "+
"peer: %v fields in rule", rule.ChannelId,
rule.Pubkey)
case peerRule:
pubkey, err := route.NewVertexFromBytes(rule.Pubkey)
if err != nil {
return nil, err
}
if _, ok := params.PeerRules[pubkey]; ok {
return nil, fmt.Errorf("multiple rules set "+
"for peer: %v", pubkey)
}
params.PeerRules[pubkey] = liquidityRule
case chanRule:
shortID := lnwire.NewShortChanIDFromInt(rule.ChannelId)
if _, ok := params.ChannelRules[shortID]; ok {
return nil, fmt.Errorf("multiple rules set "+
"for channel: %v", shortID)
}
params.ChannelRules[shortID] = liquidityRule
default:
return nil, errors.New("please set channel id or " +
"pubkey for rule")
}
}
return params, nil
}

@ -21,8 +21,6 @@ import (
"github.com/lightninglabs/loop/swap"
looprpc "github.com/lightninglabs/loop/swapserverrpc"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/queue"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/zpay32"
@ -806,154 +804,14 @@ func (s *swapClientServer) SetLiquidityParams(ctx context.Context,
in *clientrpc.SetLiquidityParamsRequest) (*clientrpc.SetLiquidityParamsResponse,
error) {
feeLimit, err := rpcToFee(in.Parameters)
err := s.liquidityMgr.SetParameters(ctx, in.Parameters)
if err != nil {
return nil, err
}
params := liquidity.Parameters{
FeeLimit: feeLimit,
SweepConfTarget: in.Parameters.SweepConfTarget,
FailureBackOff: time.Duration(in.Parameters.FailureBackoffSec) *
time.Second,
Autoloop: in.Parameters.Autoloop,
AutoFeeBudget: btcutil.Amount(in.Parameters.AutoloopBudgetSat),
MaxAutoInFlight: int(in.Parameters.AutoMaxInFlight),
ChannelRules: make(
map[lnwire.ShortChannelID]*liquidity.SwapRule,
),
PeerRules: make(
map[route.Vertex]*liquidity.SwapRule,
),
ClientRestrictions: liquidity.Restrictions{
Minimum: btcutil.Amount(in.Parameters.MinSwapAmount),
Maximum: btcutil.Amount(in.Parameters.MaxSwapAmount),
},
HtlcConfTarget: in.Parameters.HtlcConfTarget,
}
// Zero unix time is different to zero golang time.
if in.Parameters.AutoloopBudgetStartSec != 0 {
params.AutoFeeStartDate = time.Unix(
int64(in.Parameters.AutoloopBudgetStartSec), 0,
)
}
for _, rule := range in.Parameters.Rules {
peerRule := rule.Pubkey != nil
chanRule := rule.ChannelId != 0
liquidityRule, err := rpcToRule(rule)
if err != nil {
return nil, err
}
switch {
case peerRule && chanRule:
return nil, fmt.Errorf("cannot set channel: %v and "+
"peer: %v fields in rule", rule.ChannelId,
rule.Pubkey)
case peerRule:
pubkey, err := route.NewVertexFromBytes(rule.Pubkey)
if err != nil {
return nil, err
}
if _, ok := params.PeerRules[pubkey]; ok {
return nil, fmt.Errorf("multiple rules set "+
"for peer: %v", pubkey)
}
params.PeerRules[pubkey] = liquidityRule
case chanRule:
shortID := lnwire.NewShortChanIDFromInt(rule.ChannelId)
if _, ok := params.ChannelRules[shortID]; ok {
return nil, fmt.Errorf("multiple rules set "+
"for channel: %v", shortID)
}
params.ChannelRules[shortID] = liquidityRule
default:
return nil, errors.New("please set channel id or " +
"pubkey for rule")
}
}
if err := s.liquidityMgr.SetParameters(ctx, params); err != nil {
return nil, err
}
return &clientrpc.SetLiquidityParamsResponse{}, nil
}
// rpcToFee converts the values provided over rpc to a fee limit interface,
// failing if an inconsistent set of fields are set.
func rpcToFee(req *clientrpc.LiquidityParameters) (liquidity.FeeLimit,
error) {
// Check which fee limit type we have values set for. If any fields
// relevant to our individual categories are set, we count that type
// as set.
isFeePPM := req.FeePpm != 0
isCategories := req.MaxSwapFeePpm != 0 || req.MaxRoutingFeePpm != 0 ||
req.MaxPrepayRoutingFeePpm != 0 || req.MaxMinerFeeSat != 0 ||
req.MaxPrepaySat != 0 || req.SweepFeeRateSatPerVbyte != 0
switch {
case isFeePPM && isCategories:
return nil, errors.New("set either fee ppm, or individual " +
"fee categories")
case isFeePPM:
return liquidity.NewFeePortion(req.FeePpm), nil
case isCategories:
satPerVbyte := chainfee.SatPerKVByte(
req.SweepFeeRateSatPerVbyte * 1000,
)
return liquidity.NewFeeCategoryLimit(
req.MaxSwapFeePpm,
req.MaxRoutingFeePpm,
req.MaxPrepayRoutingFeePpm,
btcutil.Amount(req.MaxMinerFeeSat),
btcutil.Amount(req.MaxPrepaySat),
satPerVbyte.FeePerKWeight(),
), nil
default:
return nil, errors.New("no fee categories set")
}
}
// rpcToRule switches on rpc rule type to convert to our rule interface.
func rpcToRule(rule *clientrpc.LiquidityRule) (*liquidity.SwapRule, error) {
swapType := swap.TypeOut
if rule.SwapType == clientrpc.SwapType_LOOP_IN {
swapType = swap.TypeIn
}
switch rule.Type {
case clientrpc.LiquidityRuleType_UNKNOWN:
return nil, fmt.Errorf("rule type field must be set")
case clientrpc.LiquidityRuleType_THRESHOLD:
return &liquidity.SwapRule{
ThresholdRule: liquidity.NewThresholdRule(
int(rule.IncomingThreshold),
int(rule.OutgoingThreshold),
),
Type: swapType,
}, nil
default:
return nil, fmt.Errorf("unknown rule: %T", rule)
}
}
// SuggestSwaps provides a list of suggested swaps based on lnd's current
// channel balances and rules set by the liquidity manager.
func (s *swapClientServer) SuggestSwaps(ctx context.Context,

Loading…
Cancel
Save