mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
tests: add unit tests for the low/high routing plugin
This commit is contained in:
parent
ffd52aba2f
commit
01bf94ad11
4 changed files with 655 additions and 8 deletions
|
|
@ -3,12 +3,15 @@ package loop
|
|||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightninglabs/loop/test"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/zpay32"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -71,6 +74,551 @@ func makeTestNetwork(channels []testChan) ([]lndclient.ChannelInfo,
|
|||
return chanInfos, edges
|
||||
}
|
||||
|
||||
// TestLowHighRoutingPlugin tests that the low-high routing plugin does indeed
|
||||
// gradually change MC settings in favour of more expensive inbound channels
|
||||
// towards the Loop server.
|
||||
func TestLowHighRoutingPlugin(t *testing.T) {
|
||||
target := loopNode
|
||||
amt := btcutil.Amount(50)
|
||||
testTime := time.Now().UTC()
|
||||
// We expect Mission Control entries to be set to now + 1 sec.
|
||||
testTimeMc := testTime.Add(time.Second)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
channels []testChan
|
||||
routeHints [][]zpay32.HopHint
|
||||
initError error
|
||||
missionControlState [][]lndclient.MissionControlEntry
|
||||
restoredMissionControlState []lndclient.MissionControlEntry
|
||||
}{
|
||||
{
|
||||
name: "degenerate network 1",
|
||||
//
|
||||
// Alice --- Loop
|
||||
//
|
||||
channels: []testChan{
|
||||
{alice, loopNode, 1, 1000, 1000, 1, 1000, 1},
|
||||
},
|
||||
initError: ErrRoutingPluginNotApplicable,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{
|
||||
NodeFrom: alice,
|
||||
NodeTo: loopNode,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "degenerate network 2",
|
||||
//
|
||||
// Alice --- Bob --- Loop
|
||||
//
|
||||
channels: []testChan{
|
||||
// Alice - Bob
|
||||
{alice, bob, 1, 1000, 1000, 1, 1000, 1},
|
||||
// Bob - Loop
|
||||
{bob, loopNode, 2, 1000, 1000, 1, 1000, 1},
|
||||
},
|
||||
initError: ErrRoutingPluginNotApplicable,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "degenrate network 3",
|
||||
//
|
||||
// _____Bob_____
|
||||
// / \
|
||||
// Alice Dave---Loop
|
||||
// \___
|
||||
// Charlie
|
||||
//
|
||||
channels: []testChan{
|
||||
{alice, bob, 1, 1000, 1000, 1, 1000, 1},
|
||||
{alice, charlie, 2, 1000, 1000, 1, 1000, 1},
|
||||
// Bob - Dave (cheap)
|
||||
{bob, dave, 3, 1000, 1000, 1, 1000, 1},
|
||||
{dave, loopNode, 5, 1000, 1000, 1, 1000, 1},
|
||||
},
|
||||
initError: ErrRoutingPluginNotApplicable,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
FailTime: time.Time{},
|
||||
FailAmt: 0,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
restoredMissionControlState: []lndclient.MissionControlEntry{
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
FailTime: time.Time{},
|
||||
FailAmt: 0,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // nolint: dupl
|
||||
name: "fork before loop node 1",
|
||||
//
|
||||
// _____Bob_____
|
||||
// / \
|
||||
// Alice Dave---Loop
|
||||
// \___ ___/
|
||||
// Charlie
|
||||
//
|
||||
channels: []testChan{
|
||||
{alice, bob, 1, 1000, 1000, 1, 1000, 1},
|
||||
{alice, charlie, 2, 1000, 1000, 1, 1000, 1},
|
||||
// Bob - Dave (cheap)
|
||||
{bob, dave, 3, 1000, 1000, 1, 1000, 1},
|
||||
// Charlie - Dave (expensive)
|
||||
{charlie, dave, 4, 1000, 1000, 100, 1000, 1},
|
||||
{dave, loopNode, 5, 1000, 1000, 1, 1000, 1},
|
||||
},
|
||||
initError: nil,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
FailTime: time.Time{},
|
||||
FailAmt: 0,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
// MC state set on the second attempt.
|
||||
{
|
||||
// Discourage Bob - Dave
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1,
|
||||
},
|
||||
// Encourage Charlie - Dave
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: dave,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
restoredMissionControlState: []lndclient.MissionControlEntry{
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
FailTime: time.Time{},
|
||||
FailAmt: 0,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: dave,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1000001,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // nolint: dupl
|
||||
name: "fork before loop node 1 with equal inbound fees",
|
||||
//
|
||||
// _____Bob_____
|
||||
// / \
|
||||
// Alice Dave---Loop
|
||||
// \___ ___/
|
||||
// Charlie
|
||||
//
|
||||
channels: []testChan{
|
||||
{alice, bob, 1, 999, 1000, 1, 1000, 1},
|
||||
{alice, charlie, 2, 9999, 1000, 1, 1000, 1},
|
||||
// Bob - Dave (expensive)
|
||||
{bob, dave, 3, 999, 1000, 100, 1000, 1},
|
||||
// Charlie - Dave (expensive)
|
||||
{charlie, dave, 4, 999, 1000, 100, 1000, 1},
|
||||
{dave, loopNode, 5, 999, 1000, 1, 1000, 1},
|
||||
},
|
||||
initError: nil,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: loopNode,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
// MC state on the second attempt encourages
|
||||
// both inbound peers to make sure we do try
|
||||
// to route through both.
|
||||
{
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: loopNode,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 999000,
|
||||
},
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: dave,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 999000,
|
||||
},
|
||||
},
|
||||
},
|
||||
restoredMissionControlState: []lndclient.MissionControlEntry{
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: loopNode,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: dave,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 999000,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 999001,
|
||||
},
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: dave,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 999000,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 999001,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fork before loop node 2",
|
||||
//
|
||||
// _____Bob_____
|
||||
// / \
|
||||
// Alice Eugene---Frank---George---Loop
|
||||
// |\___ ___//
|
||||
// | Charlie /
|
||||
// \ /
|
||||
// \___ ___/
|
||||
// Dave
|
||||
//
|
||||
channels: []testChan{
|
||||
{alice, bob, 1, 1000, 1000, 1, 1000, 1},
|
||||
{alice, charlie, 2, 1000, 1000, 1, 1000, 1},
|
||||
{alice, dave, 3, 1000, 1000, 1, 1000, 1},
|
||||
// Bob - Eugene (cheap)
|
||||
{bob, eugene, 4, 1000, 1000, 1, 1000, 1},
|
||||
// Charlie - Eugene (more expensive)
|
||||
{charlie, eugene, 5, 1000, 1000, 2, 1000, 1},
|
||||
// Dave - Eugene (most expensive)
|
||||
{dave, eugene, 6, 1000, 1001, 2, 1000, 1},
|
||||
{eugene, frank, 7, 1000, 1000, 1, 1000, 1},
|
||||
},
|
||||
// Private channels: Frank - George - Loop
|
||||
routeHints: [][]zpay32.HopHint{{
|
||||
{
|
||||
NodeID: frankPubKey,
|
||||
ChannelID: 8,
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 1,
|
||||
},
|
||||
{
|
||||
NodeID: georgePubKey,
|
||||
ChannelID: 9,
|
||||
FeeBaseMSat: 1000,
|
||||
FeeProportionalMillionths: 1,
|
||||
},
|
||||
}},
|
||||
initError: nil,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
// MC state set on the second attempt.
|
||||
{
|
||||
// Discourage Bob - Eugene
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: eugene,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1,
|
||||
},
|
||||
// Encourage Charlie - Eugene
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
// Encourage Dave - Eugene
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
// MC state set on the third attempt.
|
||||
{
|
||||
// Discourage Bob - Eugene
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: eugene,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1,
|
||||
},
|
||||
// Discourage Charlie - Eugene
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1,
|
||||
},
|
||||
// Encourage Dave - Eugene
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
restoredMissionControlState: []lndclient.MissionControlEntry{
|
||||
{
|
||||
NodeFrom: bob,
|
||||
NodeTo: eugene,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1000001,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
FailTime: time.Time{},
|
||||
FailAmt: 0,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: eugene,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1000001,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fork before loop node 3",
|
||||
//
|
||||
// _____Bob_____
|
||||
// / \
|
||||
// Alice Eugene---Frank---George---Loop
|
||||
// |\___ ___/ /
|
||||
// | Charlie /
|
||||
// \ /
|
||||
// \___ ___________________/
|
||||
// Dave
|
||||
//
|
||||
channels: []testChan{
|
||||
// Alice - Bob
|
||||
{alice, bob, 1, 1000, 1000, 1, 1000, 1},
|
||||
// Alice - Charlie
|
||||
{alice, charlie, 2, 1000, 1000, 1, 1000, 1},
|
||||
// Alice - Dave
|
||||
{alice, dave, 3, 1000, 1000, 1, 1000, 1},
|
||||
// Bob - Eugene
|
||||
{bob, eugene, 4, 1000, 1000, 1, 1000, 1},
|
||||
// Charlie - Eugene
|
||||
{charlie, eugene, 5, 1000, 1000, 2, 1000, 1},
|
||||
// Dave - George (expensive)
|
||||
{dave, george, 6, 1000, 1001, 2, 1000, 1},
|
||||
// Eugene - Frank
|
||||
{eugene, frank, 7, 1000, 1000, 1, 1000, 1},
|
||||
// Frank - George (cheap)
|
||||
{frank, george, 8, 1000, 1000, 1, 1000, 1},
|
||||
// George - Loop
|
||||
{george, loopNode, 9, 1000, 1000, 1, 1000, 1},
|
||||
},
|
||||
initError: nil,
|
||||
missionControlState: [][]lndclient.MissionControlEntry{
|
||||
// The original MC state we start with.
|
||||
{
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
},
|
||||
// MC state set on the second attempt.
|
||||
{
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
// Discourage Frank - George
|
||||
{
|
||||
NodeFrom: frank,
|
||||
NodeTo: george,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1,
|
||||
},
|
||||
// Encourage Dave - George
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: george,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
restoredMissionControlState: []lndclient.MissionControlEntry{
|
||||
{
|
||||
NodeFrom: charlie,
|
||||
NodeTo: eugene,
|
||||
SuccessTime: testTime,
|
||||
SuccessAmt: 10000,
|
||||
},
|
||||
{
|
||||
NodeFrom: frank,
|
||||
NodeTo: george,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1000001,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
{
|
||||
NodeFrom: dave,
|
||||
NodeTo: george,
|
||||
FailTime: testTimeMc,
|
||||
FailAmt: 1000001,
|
||||
SuccessTime: testTimeMc,
|
||||
SuccessAmt: 1000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mockLnd := test.NewMockLnd()
|
||||
|
||||
mockLnd.Channels, mockLnd.ChannelEdges =
|
||||
makeTestNetwork(tc.channels)
|
||||
|
||||
lnd := lndclient.LndServices{
|
||||
Client: mockLnd.Client,
|
||||
Router: mockLnd.Router,
|
||||
}
|
||||
|
||||
testClock := clock.NewTestClock(testTime)
|
||||
plugin := makeRoutingPlugin(
|
||||
RoutingPluginLowHigh, lnd, testClock,
|
||||
)
|
||||
require.NotNil(t, plugin)
|
||||
|
||||
// Set start state for MC.
|
||||
mockLnd.MissionControlState = tc.missionControlState[0]
|
||||
|
||||
// Initialize the routing plugin.
|
||||
require.Equal(
|
||||
t, tc.initError,
|
||||
plugin.Init(
|
||||
context.TODO(), target, tc.routeHints,
|
||||
amt,
|
||||
),
|
||||
)
|
||||
|
||||
if tc.initError != nil {
|
||||
// Make sure that MC state is untouched.
|
||||
require.Equal(
|
||||
t, tc.missionControlState[0],
|
||||
mockLnd.MissionControlState,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
maxAttempts := len(tc.missionControlState)
|
||||
for i, expectedState := range tc.missionControlState {
|
||||
// Check that after each step, MC state is what
|
||||
// we expect it to be.
|
||||
require.NoError(
|
||||
t, plugin.BeforePayment(
|
||||
context.TODO(),
|
||||
i+1, maxAttempts,
|
||||
),
|
||||
)
|
||||
|
||||
require.ElementsMatch(
|
||||
t, expectedState,
|
||||
mockLnd.MissionControlState,
|
||||
)
|
||||
}
|
||||
|
||||
// Make sure we covered all inbound channels.
|
||||
require.Error(
|
||||
t, ErrRoutingPluginNoMoreRetries,
|
||||
plugin.BeforePayment(
|
||||
context.TODO(), maxAttempts, maxAttempts,
|
||||
),
|
||||
)
|
||||
|
||||
// Deinitialize the routing plugin.
|
||||
require.NoError(t, plugin.Done(context.TODO()))
|
||||
|
||||
// Make sure that MC state is reset after Done() is
|
||||
// called.
|
||||
require.ElementsMatch(
|
||||
t, tc.restoredMissionControlState,
|
||||
mockLnd.MissionControlState,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoutingPluginAcquireRelease(t *testing.T) {
|
||||
mockLnd := test.NewMockLnd()
|
||||
|
||||
|
|
@ -116,4 +664,35 @@ func TestRoutingPluginAcquireRelease(t *testing.T) {
|
|||
// plugin is acquired.
|
||||
ReleaseRoutingPlugin(ctx)
|
||||
ReleaseRoutingPlugin(ctx)
|
||||
|
||||
// RoutingPluginNone returns nil.
|
||||
plugin2, err := AcquireRoutingPlugin(
|
||||
ctx, RoutingPluginNone, lnd, target, nil, amt,
|
||||
)
|
||||
require.Nil(t, plugin2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Acquire is successful.
|
||||
plugin, err = AcquireRoutingPlugin(
|
||||
ctx, RoutingPluginLowHigh, lnd, target, nil, amt,
|
||||
)
|
||||
require.NotNil(t, plugin)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Plugin already acquired, above.
|
||||
plugin2, err = AcquireRoutingPlugin(
|
||||
ctx, RoutingPluginLowHigh, lnd, target, nil, amt,
|
||||
)
|
||||
require.Nil(t, plugin2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Release acruired plugin.
|
||||
ReleaseRoutingPlugin(ctx)
|
||||
|
||||
// Acquire is successful.
|
||||
plugin2, err = AcquireRoutingPlugin(
|
||||
ctx, RoutingPluginLowHigh, lnd, target, nil, amt,
|
||||
)
|
||||
require.NotNil(t, plugin2)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,10 +186,14 @@ func (h *mockLightningClient) ListTransactions(
|
|||
func (h *mockLightningClient) GetNodeInfo(ctx context.Context,
|
||||
pubKeyBytes route.Vertex, includeChannels bool) (*lndclient.NodeInfo, error) {
|
||||
|
||||
nodeInfo := lndclient.NodeInfo{}
|
||||
nodeInfo := &lndclient.NodeInfo{
|
||||
Node: &lndclient.Node{
|
||||
PubKey: pubKeyBytes,
|
||||
},
|
||||
}
|
||||
|
||||
if !includeChannels {
|
||||
return nil, nil
|
||||
return nodeInfo, nil
|
||||
}
|
||||
|
||||
nodePubKey, err := route.NewVertexFromStr(h.lnd.NodePubkey)
|
||||
|
|
@ -214,7 +218,7 @@ func (h *mockLightningClient) GetNodeInfo(ctx context.Context,
|
|||
|
||||
nodeInfo.ChannelCount = len(nodeInfo.Channels)
|
||||
|
||||
return &nodeInfo, nil
|
||||
return nodeInfo, nil
|
||||
}
|
||||
|
||||
// GetChanInfo retrieves all the info the node has on the given channel
|
||||
|
|
|
|||
|
|
@ -163,11 +163,12 @@ type LndMockServices struct {
|
|||
// keyed by hash string.
|
||||
Invoices map[lntypes.Hash]*lndclient.Invoice
|
||||
|
||||
Channels []lndclient.ChannelInfo
|
||||
ChannelEdges map[uint64]*lndclient.ChannelEdge
|
||||
ClosedChannels []lndclient.ClosedChannel
|
||||
ForwardingEvents []lndclient.ForwardingEvent
|
||||
Payments []lndclient.Payment
|
||||
Channels []lndclient.ChannelInfo
|
||||
ChannelEdges map[uint64]*lndclient.ChannelEdge
|
||||
ClosedChannels []lndclient.ClosedChannel
|
||||
ForwardingEvents []lndclient.ForwardingEvent
|
||||
Payments []lndclient.Payment
|
||||
MissionControlState []lndclient.MissionControlEntry
|
||||
|
||||
WaitForFinished func()
|
||||
|
||||
|
|
|
|||
|
|
@ -42,3 +42,66 @@ func (r *mockRouter) TrackPayment(ctx context.Context,
|
|||
|
||||
return statusChan, errorChan, nil
|
||||
}
|
||||
|
||||
func (r *mockRouter) QueryMissionControl(ctx context.Context) (
|
||||
[]lndclient.MissionControlEntry, error) {
|
||||
|
||||
return r.lnd.MissionControlState, nil
|
||||
}
|
||||
|
||||
// ImpotMissionControl is a mocked reimplementation of the pair import.
|
||||
// Reference: lnd/router/missioncontrol_state.go:importSnapshot().
|
||||
func (r *mockRouter) ImportMissionControl(ctx context.Context,
|
||||
entries []lndclient.MissionControlEntry) error {
|
||||
|
||||
for _, entry := range entries {
|
||||
found := false
|
||||
for i := range r.lnd.MissionControlState {
|
||||
current := &r.lnd.MissionControlState[i]
|
||||
if entry.NodeFrom == current.NodeFrom &&
|
||||
entry.NodeTo == current.NodeTo {
|
||||
|
||||
// Mark that the entry has been found and updated.
|
||||
found = true
|
||||
|
||||
// Import failure result first. We ignore failure
|
||||
// relax interval here for convenience.
|
||||
current.FailTime = entry.FailTime
|
||||
current.FailAmt = entry.FailAmt
|
||||
|
||||
switch {
|
||||
case entry.FailAmt == 0:
|
||||
current.SuccessAmt = 0
|
||||
|
||||
case entry.FailAmt <= current.SuccessAmt:
|
||||
current.SuccessAmt = entry.FailAmt - 1
|
||||
}
|
||||
|
||||
// Import success result second.
|
||||
current.SuccessTime = entry.SuccessTime
|
||||
if entry.SuccessAmt > current.SuccessAmt {
|
||||
current.SuccessAmt = entry.SuccessAmt
|
||||
}
|
||||
|
||||
if !current.FailTime.IsZero() &&
|
||||
entry.SuccessAmt >= current.FailAmt {
|
||||
|
||||
current.FailAmt = entry.SuccessAmt + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
r.lnd.MissionControlState = append(
|
||||
r.lnd.MissionControlState, entry,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *mockRouter) ResetMissionControl(ctx context.Context) error {
|
||||
r.lnd.MissionControlState = []lndclient.MissionControlEntry{}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue