mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-28 10:41:57 +01:00
invoicesrpc: unit tests for invoice hop hints
This commit is contained in:
parent
fbe79811cf
commit
4b0bc9a7c6
786
lnrpc/invoicesrpc/addinvoice_test.go
Normal file
786
lnrpc/invoicesrpc/addinvoice_test.go
Normal file
@ -0,0 +1,786 @@
|
||||
package invoicesrpc
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/zpay32"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type hopHintsConfigMock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// IsPublicNode mocks node public state lookup.
|
||||
func (h *hopHintsConfigMock) IsPublicNode(pubKey [33]byte) (bool, error) {
|
||||
args := h.Mock.Called(pubKey)
|
||||
return args.Bool(0), args.Error(1)
|
||||
}
|
||||
|
||||
// IsChannelActive is used to generate valid hop hints.
|
||||
func (h *hopHintsConfigMock) IsChannelActive(chanID lnwire.ChannelID) bool {
|
||||
args := h.Mock.Called(chanID)
|
||||
return args.Bool(0)
|
||||
}
|
||||
|
||||
// GetAlias allows the peer's alias SCID to be retrieved for private
|
||||
// option_scid_alias channels.
|
||||
func (h *hopHintsConfigMock) GetAlias(
|
||||
chanID lnwire.ChannelID) (lnwire.ShortChannelID, error) {
|
||||
|
||||
args := h.Mock.Called(chanID)
|
||||
return args.Get(0).(lnwire.ShortChannelID), args.Error(1)
|
||||
}
|
||||
|
||||
// FetchAllChannels retrieves all open channels currently stored
|
||||
// within the database.
|
||||
func (h *hopHintsConfigMock) FetchAllChannels() ([]*channeldb.OpenChannel,
|
||||
error) {
|
||||
|
||||
args := h.Mock.Called()
|
||||
return args.Get(0).([]*channeldb.OpenChannel), args.Error(1)
|
||||
}
|
||||
|
||||
// FetchChannelEdgesByID attempts to lookup the two directed edges for
|
||||
// the channel identified by the channel ID.
|
||||
func (h *hopHintsConfigMock) FetchChannelEdgesByID(chanID uint64) (
|
||||
*channeldb.ChannelEdgeInfo, *channeldb.ChannelEdgePolicy,
|
||||
*channeldb.ChannelEdgePolicy, error) {
|
||||
|
||||
args := h.Mock.Called(chanID)
|
||||
|
||||
// If our error is non-nil, we expect nil responses otherwise. Our
|
||||
// casts below will fail with nil values, so we check our error and
|
||||
// return early on failure first.
|
||||
err := args.Error(3)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
edgeInfo := args.Get(0).(*channeldb.ChannelEdgeInfo)
|
||||
policy1 := args.Get(1).(*channeldb.ChannelEdgePolicy)
|
||||
policy2 := args.Get(2).(*channeldb.ChannelEdgePolicy)
|
||||
|
||||
return edgeInfo, policy1, policy2, err
|
||||
}
|
||||
|
||||
// getTestPubKey returns a valid parsed pub key to be used in our tests.
|
||||
func getTestPubKey() *btcec.PublicKey {
|
||||
pubkeyBytes, _ := hex.DecodeString(
|
||||
"598ec453728e0ffe0ae2f5e174243cf58f2" +
|
||||
"a3f2c83d2457b43036db568b11093",
|
||||
)
|
||||
pubKeyY := new(btcec.FieldVal)
|
||||
_ = pubKeyY.SetByteSlice(pubkeyBytes)
|
||||
pubkey := btcec.NewPublicKey(
|
||||
new(btcec.FieldVal).SetInt(4),
|
||||
pubKeyY,
|
||||
)
|
||||
return pubkey
|
||||
}
|
||||
|
||||
var shouldIncludeChannelTestCases = []struct {
|
||||
name string
|
||||
setupMock func(*hopHintsConfigMock)
|
||||
channel *channeldb.OpenChannel
|
||||
alreadyIncluded map[uint64]bool
|
||||
cfg *SelectHopHintsCfg
|
||||
hopHint zpay32.HopHint
|
||||
remoteBalance lnwire.MilliSatoshi
|
||||
include bool
|
||||
}{{
|
||||
name: "already included channels should not be included " +
|
||||
"again",
|
||||
alreadyIncluded: map[uint64]bool{1: true},
|
||||
channel: &channeldb.OpenChannel{
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(1),
|
||||
},
|
||||
include: false,
|
||||
}, {
|
||||
name: "public channels should not be included",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 0,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 0,
|
||||
},
|
||||
ChannelFlags: lnwire.FFAnnounceChannel,
|
||||
},
|
||||
}, {
|
||||
name: "not active channels should not be included",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 0,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(false)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 0,
|
||||
},
|
||||
},
|
||||
include: false,
|
||||
}, {
|
||||
name: "a channel with a not public peer should not be included",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 0,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(false, nil)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 0,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
include: false,
|
||||
}, {
|
||||
name: "if we are unable to fetch the edge policy for the channel it " +
|
||||
"should not be included",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 0,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(nil, nil, nil, fmt.Errorf("no edge"))
|
||||
|
||||
// TODO(positiveblue): check that the func is called with the
|
||||
// right scid when we have access to the `confirmedscid` form
|
||||
// here.
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(nil, nil, nil, fmt.Errorf("no edge"))
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 0,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
include: false,
|
||||
}, {
|
||||
name: "channels with the option-scid-alias but not assigned alias " +
|
||||
"yet should not be included",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 0,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
|
||||
h.Mock.On(
|
||||
"GetAlias", mock.Anything,
|
||||
).Once().Return(lnwire.ShortChannelID{}, nil)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 0,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
ChanType: channeldb.ScidAliasFeatureBit,
|
||||
},
|
||||
include: false,
|
||||
}, {
|
||||
name: "channels with the option-scid-alias and an alias that has " +
|
||||
"already been included should not be included again",
|
||||
alreadyIncluded: map[uint64]bool{5: true},
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 0,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
alias := lnwire.ShortChannelID{TxPosition: 5}
|
||||
h.Mock.On(
|
||||
"GetAlias", mock.Anything,
|
||||
).Once().Return(alias, nil)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 0,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
ChanType: channeldb.ScidAliasFeatureBit,
|
||||
},
|
||||
include: false,
|
||||
}, {
|
||||
name: "channels that pass all the checks should be " +
|
||||
"included, using policy 1",
|
||||
alreadyIncluded: map[uint64]bool{5: true},
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 1,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
var selectedPolicy [33]byte
|
||||
copy(selectedPolicy[:], getTestPubKey().SerializeCompressed())
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{
|
||||
NodeKey1Bytes: selectedPolicy,
|
||||
},
|
||||
&channeldb.ChannelEdgePolicy{
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 20,
|
||||
TimeLockDelta: 13,
|
||||
},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
nil,
|
||||
)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 1,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(12),
|
||||
},
|
||||
hopHint: zpay32.HopHint{
|
||||
NodeID: getTestPubKey(),
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 20,
|
||||
ChannelID: 12,
|
||||
CLTVExpiryDelta: 13,
|
||||
},
|
||||
include: true,
|
||||
}, {
|
||||
name: "channels that pass all the checks should be " +
|
||||
"included, using policy 2",
|
||||
alreadyIncluded: map[uint64]bool{5: true},
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 1,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 20,
|
||||
TimeLockDelta: 13,
|
||||
}, nil,
|
||||
)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 1,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(12),
|
||||
},
|
||||
hopHint: zpay32.HopHint{
|
||||
NodeID: getTestPubKey(),
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 20,
|
||||
ChannelID: 12,
|
||||
CLTVExpiryDelta: 13,
|
||||
},
|
||||
include: true,
|
||||
}, {
|
||||
name: "channels that pass all the checks and have an alias " +
|
||||
"should be included with the alias",
|
||||
alreadyIncluded: map[uint64]bool{5: true},
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{
|
||||
Index: 1,
|
||||
}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 20,
|
||||
TimeLockDelta: 13,
|
||||
}, nil,
|
||||
)
|
||||
|
||||
aliasSCID := lnwire.NewShortChanIDFromInt(15)
|
||||
|
||||
h.Mock.On(
|
||||
"GetAlias", mock.Anything,
|
||||
).Once().Return(aliasSCID, nil)
|
||||
},
|
||||
channel: &channeldb.OpenChannel{
|
||||
FundingOutpoint: wire.OutPoint{
|
||||
Index: 1,
|
||||
},
|
||||
IdentityPub: getTestPubKey(),
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(12),
|
||||
ChanType: channeldb.ScidAliasFeatureBit,
|
||||
},
|
||||
hopHint: zpay32.HopHint{
|
||||
NodeID: getTestPubKey(),
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 20,
|
||||
ChannelID: 15,
|
||||
CLTVExpiryDelta: 13,
|
||||
},
|
||||
include: true,
|
||||
}}
|
||||
|
||||
func TestShouldIncludeChannel(t *testing.T) {
|
||||
for _, tc := range shouldIncludeChannelTestCases {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create mock and prime it for the test case.
|
||||
mock := &hopHintsConfigMock{}
|
||||
if tc.setupMock != nil {
|
||||
tc.setupMock(mock)
|
||||
}
|
||||
defer mock.AssertExpectations(t)
|
||||
|
||||
cfg := &SelectHopHintsCfg{
|
||||
IsPublicNode: mock.IsPublicNode,
|
||||
IsChannelActive: mock.IsChannelActive,
|
||||
FetchChannelEdgesByID: mock.FetchChannelEdgesByID,
|
||||
GetAlias: mock.GetAlias,
|
||||
}
|
||||
|
||||
hopHint, remoteBalance, include := shouldIncludeChannel(
|
||||
cfg, tc.channel, tc.alreadyIncluded,
|
||||
)
|
||||
|
||||
require.Equal(t, tc.include, include)
|
||||
if include {
|
||||
require.Equal(t, tc.hopHint, hopHint)
|
||||
require.Equal(
|
||||
t, tc.remoteBalance, remoteBalance,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var sufficientHintsTestCases = []struct {
|
||||
name string
|
||||
nHintsLeft int
|
||||
currentAmount lnwire.MilliSatoshi
|
||||
targetAmount lnwire.MilliSatoshi
|
||||
done bool
|
||||
}{{
|
||||
name: "not enoguh hints neither bandwidth",
|
||||
nHintsLeft: 3,
|
||||
currentAmount: 100,
|
||||
targetAmount: 200,
|
||||
done: false,
|
||||
}, {
|
||||
name: "enough hints",
|
||||
nHintsLeft: 0,
|
||||
done: true,
|
||||
}, {
|
||||
name: "enoguh bandwidth",
|
||||
nHintsLeft: 1,
|
||||
currentAmount: 200,
|
||||
targetAmount: 200,
|
||||
done: true,
|
||||
}}
|
||||
|
||||
func TestSufficientHints(t *testing.T) {
|
||||
for _, tc := range sufficientHintsTestCases {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
enoughHints := sufficientHints(
|
||||
tc.nHintsLeft, tc.currentAmount,
|
||||
tc.targetAmount,
|
||||
)
|
||||
require.Equal(t, tc.done, enoughHints)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var populateHopHintsTestCases = []struct {
|
||||
name string
|
||||
setupMock func(*hopHintsConfigMock)
|
||||
amount lnwire.MilliSatoshi
|
||||
maxHopHints int
|
||||
forcedHints [][]zpay32.HopHint
|
||||
expectedHopHints [][]zpay32.HopHint
|
||||
}{{
|
||||
name: "populate hop hints with forced hints",
|
||||
maxHopHints: 1,
|
||||
forcedHints: [][]zpay32.HopHint{
|
||||
{
|
||||
{ChannelID: 12},
|
||||
},
|
||||
},
|
||||
expectedHopHints: [][]zpay32.HopHint{
|
||||
{
|
||||
{ChannelID: 12},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "populate hop hints stops when we reached the max number of " +
|
||||
"hop hints allowed",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{Index: 9}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
allChannels := []*channeldb.OpenChannel{
|
||||
{
|
||||
FundingOutpoint: fundingOutpoint,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(9),
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
// Have one empty channel that we should not process
|
||||
// because we have already finished.
|
||||
{},
|
||||
}
|
||||
|
||||
h.Mock.On(
|
||||
"FetchAllChannels",
|
||||
).Once().Return(allChannels, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
},
|
||||
maxHopHints: 1,
|
||||
amount: 1_000_000,
|
||||
expectedHopHints: [][]zpay32.HopHint{
|
||||
{
|
||||
{
|
||||
NodeID: getTestPubKey(),
|
||||
ChannelID: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "populate hop hints stops when we reached the targeted bandwidth",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{Index: 9}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
remoteBalance := lnwire.MilliSatoshi(10_000_000)
|
||||
allChannels := []*channeldb.OpenChannel{
|
||||
{
|
||||
LocalCommitment: channeldb.ChannelCommitment{
|
||||
RemoteBalance: remoteBalance,
|
||||
},
|
||||
FundingOutpoint: fundingOutpoint,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(9),
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
// Have one empty channel that we should not process
|
||||
// because we have already finished.
|
||||
{},
|
||||
}
|
||||
|
||||
h.Mock.On(
|
||||
"FetchAllChannels",
|
||||
).Once().Return(allChannels, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
},
|
||||
maxHopHints: 10,
|
||||
amount: 1_000_000,
|
||||
expectedHopHints: [][]zpay32.HopHint{
|
||||
{
|
||||
{
|
||||
NodeID: getTestPubKey(),
|
||||
ChannelID: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "populate hop hints tries to use the channels with higher " +
|
||||
"remote balance frist",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint := wire.OutPoint{Index: 9}
|
||||
chanID := lnwire.NewChanIDFromOutPoint(&fundingOutpoint)
|
||||
remoteBalance := lnwire.MilliSatoshi(10_000_000)
|
||||
allChannels := []*channeldb.OpenChannel{
|
||||
// Because the channels with higher remote balance have
|
||||
// enough bandwidth we should never use this one.
|
||||
{},
|
||||
{
|
||||
LocalCommitment: channeldb.ChannelCommitment{
|
||||
RemoteBalance: remoteBalance,
|
||||
},
|
||||
FundingOutpoint: fundingOutpoint,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(9),
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
}
|
||||
|
||||
h.Mock.On(
|
||||
"FetchAllChannels",
|
||||
).Once().Return(allChannels, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
},
|
||||
maxHopHints: 1,
|
||||
amount: 1_000_000,
|
||||
expectedHopHints: [][]zpay32.HopHint{
|
||||
{
|
||||
{
|
||||
NodeID: getTestPubKey(),
|
||||
ChannelID: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "populate hop hints stops after having considered all the open " +
|
||||
"channels",
|
||||
setupMock: func(h *hopHintsConfigMock) {
|
||||
fundingOutpoint1 := wire.OutPoint{Index: 9}
|
||||
chanID1 := lnwire.NewChanIDFromOutPoint(&fundingOutpoint1)
|
||||
remoteBalance1 := lnwire.MilliSatoshi(10_000_000)
|
||||
|
||||
fundingOutpoint2 := wire.OutPoint{Index: 2}
|
||||
chanID2 := lnwire.NewChanIDFromOutPoint(&fundingOutpoint2)
|
||||
remoteBalance2 := lnwire.MilliSatoshi(1_000_000)
|
||||
|
||||
allChannels := []*channeldb.OpenChannel{
|
||||
// After sorting we will first process chanID1 and then
|
||||
// chanID2.
|
||||
{
|
||||
LocalCommitment: channeldb.ChannelCommitment{
|
||||
RemoteBalance: remoteBalance2,
|
||||
},
|
||||
FundingOutpoint: fundingOutpoint2,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(2),
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
{
|
||||
LocalCommitment: channeldb.ChannelCommitment{
|
||||
RemoteBalance: remoteBalance1,
|
||||
},
|
||||
FundingOutpoint: fundingOutpoint1,
|
||||
ShortChannelID: lnwire.NewShortChanIDFromInt(9),
|
||||
IdentityPub: getTestPubKey(),
|
||||
},
|
||||
}
|
||||
|
||||
h.Mock.On(
|
||||
"FetchAllChannels",
|
||||
).Once().Return(allChannels, nil)
|
||||
|
||||
// Prepare the mock for the first channel.
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID1,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
|
||||
// Prepare the mock for the second channel.
|
||||
h.Mock.On(
|
||||
"IsChannelActive", chanID2,
|
||||
).Once().Return(true)
|
||||
|
||||
h.Mock.On(
|
||||
"IsPublicNode", mock.Anything,
|
||||
).Once().Return(true, nil)
|
||||
|
||||
h.Mock.On(
|
||||
"FetchChannelEdgesByID", mock.Anything,
|
||||
).Once().Return(
|
||||
&channeldb.ChannelEdgeInfo{},
|
||||
&channeldb.ChannelEdgePolicy{},
|
||||
&channeldb.ChannelEdgePolicy{}, nil,
|
||||
)
|
||||
},
|
||||
maxHopHints: 10,
|
||||
amount: 100_000_000,
|
||||
expectedHopHints: [][]zpay32.HopHint{
|
||||
{
|
||||
{
|
||||
NodeID: getTestPubKey(),
|
||||
ChannelID: 9,
|
||||
},
|
||||
}, {
|
||||
{
|
||||
NodeID: getTestPubKey(),
|
||||
ChannelID: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
func TestPopulateHopHints(t *testing.T) {
|
||||
for _, tc := range populateHopHintsTestCases {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create mock and prime it for the test case.
|
||||
mock := &hopHintsConfigMock{}
|
||||
if tc.setupMock != nil {
|
||||
tc.setupMock(mock)
|
||||
}
|
||||
defer mock.AssertExpectations(t)
|
||||
|
||||
cfg := &SelectHopHintsCfg{
|
||||
IsPublicNode: mock.IsPublicNode,
|
||||
IsChannelActive: mock.IsChannelActive,
|
||||
FetchChannelEdgesByID: mock.FetchChannelEdgesByID,
|
||||
GetAlias: mock.GetAlias,
|
||||
FetchAllChannels: mock.FetchAllChannels,
|
||||
MaxHopHints: tc.maxHopHints,
|
||||
}
|
||||
hopHints, err := PopulateHopHints(
|
||||
cfg, tc.amount, tc.forcedHints,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
// We shuffle the elements in the hop hint list so we
|
||||
// need to compare the elements here.
|
||||
require.ElementsMatch(t, tc.expectedHopHints, hopHints)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user