mirror of
https://github.com/lightninglabs/loop
synced 2024-11-13 13:10:30 +00:00
a48924a664
Previously we would exclusively pass the autoloop boolean to multiple functions while they had directly access to the manager's parameters. With this commit we remove this explicit flag from the various function interfaces and retrieve the value directly from the parameters.
194 lines
4.5 KiB
Go
194 lines
4.5 KiB
Go
package liquidity
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/lightninglabs/loop"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
// TestLoopinInUse tests that the loop in swap builder prevents dispatching
|
|
// swaps for peers when there is already a swap running for that peer.
|
|
func TestLoopinInUse(t *testing.T) {
|
|
var (
|
|
peer1 = route.Vertex{1}
|
|
chan1 = lnwire.NewShortChanIDFromInt(1)
|
|
|
|
peer2 = route.Vertex{2}
|
|
chan2 = lnwire.NewShortChanIDFromInt(2)
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
ongoingLoopOut *lnwire.ShortChannelID
|
|
ongoingLoopIn *route.Vertex
|
|
failedLoopIn *route.Vertex
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "swap allowed",
|
|
ongoingLoopIn: &peer2,
|
|
ongoingLoopOut: &chan2,
|
|
failedLoopIn: &peer2,
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "conflicts with loop out",
|
|
ongoingLoopOut: &chan1,
|
|
expectedErr: newReasonError(ReasonLoopOut),
|
|
},
|
|
{
|
|
name: "conflicts with loop in",
|
|
ongoingLoopIn: &peer1,
|
|
expectedErr: newReasonError(ReasonLoopIn),
|
|
},
|
|
{
|
|
name: "previous failed loopin",
|
|
failedLoopIn: &peer1,
|
|
expectedErr: newReasonError(ReasonFailureBackoff),
|
|
},
|
|
}
|
|
|
|
for _, testCase := range tests {
|
|
traffic := newSwapTraffic()
|
|
|
|
if testCase.ongoingLoopOut != nil {
|
|
traffic.ongoingLoopOut[*testCase.ongoingLoopOut] = true
|
|
}
|
|
|
|
if testCase.ongoingLoopIn != nil {
|
|
traffic.ongoingLoopIn[*testCase.ongoingLoopIn] = true
|
|
}
|
|
|
|
if testCase.failedLoopIn != nil {
|
|
traffic.failedLoopIn[*testCase.failedLoopIn] = testTime
|
|
}
|
|
|
|
builder := newLoopInBuilder(nil)
|
|
err := builder.inUse(traffic, peer1, []lnwire.ShortChannelID{
|
|
chan1,
|
|
})
|
|
|
|
require.Equal(t, testCase.expectedErr, err)
|
|
}
|
|
}
|
|
|
|
// TestLoopinBuildSwap tests construction of loop in swaps for autoloop,
|
|
// including the case where the client cannot get a quote because it is not
|
|
// reachable from the server.
|
|
func TestLoopinBuildSwap(t *testing.T) {
|
|
var (
|
|
peer1 = route.Vertex{1}
|
|
chan1 = lnwire.NewShortChanIDFromInt(1)
|
|
|
|
htlcConfTarget int32 = 6
|
|
swapAmt btcutil.Amount = 100000
|
|
|
|
quote = &loop.LoopInQuote{
|
|
SwapFee: 1,
|
|
MinerFee: 2,
|
|
}
|
|
|
|
expectedSwap = &loopInSwapSuggestion{
|
|
loop.LoopInRequest{
|
|
Amount: swapAmt,
|
|
MaxSwapFee: quote.SwapFee,
|
|
MaxMinerFee: quote.MinerFee,
|
|
HtlcConfTarget: htlcConfTarget,
|
|
LastHop: &peer1,
|
|
Initiator: autoloopSwapInitiator,
|
|
},
|
|
}
|
|
|
|
quoteRequest = &loop.LoopInQuoteRequest{
|
|
Amount: swapAmt,
|
|
LastHop: &peer1,
|
|
HtlcConfTarget: htlcConfTarget,
|
|
}
|
|
|
|
errPrecondition = status.Error(codes.FailedPrecondition, "failed")
|
|
errOtherCode = status.Error(codes.DeadlineExceeded, "timeout")
|
|
errNoCode = errors.New("failure")
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
prepareMock func(*mockCfg)
|
|
expectedSwap swapSuggestion
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "quote successful",
|
|
prepareMock: func(m *mockCfg) {
|
|
m.On(
|
|
"LoopInQuote", mock.Anything,
|
|
quoteRequest,
|
|
).Return(quote, nil)
|
|
},
|
|
expectedSwap: expectedSwap,
|
|
},
|
|
{
|
|
name: "client unreachable",
|
|
prepareMock: func(m *mockCfg) {
|
|
m.On(
|
|
"LoopInQuote", mock.Anything,
|
|
quoteRequest,
|
|
).Return(quote, errPrecondition)
|
|
},
|
|
expectedSwap: nil,
|
|
expectedErr: newReasonError(ReasonLoopInUnreachable),
|
|
},
|
|
{
|
|
name: "other error code",
|
|
prepareMock: func(m *mockCfg) {
|
|
m.On(
|
|
"LoopInQuote", mock.Anything,
|
|
quoteRequest,
|
|
).Return(quote, errOtherCode)
|
|
},
|
|
expectedSwap: nil,
|
|
expectedErr: errOtherCode,
|
|
},
|
|
{
|
|
name: "no error code",
|
|
prepareMock: func(m *mockCfg) {
|
|
m.On(
|
|
"LoopInQuote", mock.Anything,
|
|
quoteRequest,
|
|
).Return(quote, errNoCode)
|
|
},
|
|
expectedSwap: nil,
|
|
expectedErr: errNoCode,
|
|
},
|
|
}
|
|
|
|
for _, testCase := range tests {
|
|
mock, cfg := newMockConfig()
|
|
params := defaultParameters
|
|
params.HtlcConfTarget = htlcConfTarget
|
|
params.AutoFeeBudget = 100000
|
|
|
|
testCase.prepareMock(mock)
|
|
|
|
builder := newLoopInBuilder(cfg)
|
|
swap, err := builder.buildSwap(
|
|
context.Background(), peer1, []lnwire.ShortChannelID{
|
|
chan1,
|
|
}, swapAmt, params,
|
|
)
|
|
assert.Equal(t, testCase.expectedSwap, swap)
|
|
assert.Equal(t, testCase.expectedErr, err)
|
|
|
|
mock.AssertExpectations(t)
|
|
}
|
|
}
|