Merge pull request #466 from bhandras/routing-plugin-force-mc-import

routing: integrate with the forced MC import to eliminate the "1 sec hack" when importing pair history
pull/467/head
András Bánki-Horváth 2 years ago committed by GitHub
commit a6350905d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,10 +11,10 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0
github.com/jessevdk/go-flags v1.4.0 github.com/jessevdk/go-flags v1.4.0
github.com/lightninglabs/aperture v0.1.6-beta github.com/lightninglabs/aperture v0.1.6-beta
github.com/lightninglabs/lndclient v0.14.0-8 github.com/lightninglabs/lndclient v0.14.2-3
github.com/lightninglabs/loop/swapserverrpc v1.0.0 github.com/lightninglabs/loop/swapserverrpc v1.0.0
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
github.com/lightningnetwork/lnd v0.14.2-beta.rc1 github.com/lightningnetwork/lnd v0.14.2-beta
github.com/lightningnetwork/lnd/cert v1.1.0 github.com/lightningnetwork/lnd/cert v1.1.0
github.com/lightningnetwork/lnd/clock v1.1.0 github.com/lightningnetwork/lnd/clock v1.1.0
github.com/lightningnetwork/lnd/queue v1.1.0 github.com/lightningnetwork/lnd/queue v1.1.0
@ -32,5 +32,5 @@ go 1.15
replace github.com/lightninglabs/loop/swapserverrpc => ./swapserverrpc replace github.com/lightninglabs/loop/swapserverrpc => ./swapserverrpc
// TODO(bhandras): remove once v0.14.2-beta is tagged. // TODO(bhandras): remove once v0.14.3-beta or v0.15.0-beta is tagged.
replace github.com/lightningnetwork/lnd => github.com/lightningnetwork/lnd v0.14.1-beta.0.20220131141659-60625b6c1a0b replace github.com/lightningnetwork/lnd => github.com/lightningnetwork/lnd v0.14.1-beta.0.20220131141659-60625b6c1a0b

@ -548,8 +548,8 @@ github.com/lightninglabs/aperture v0.1.6-beta/go.mod h1:9xl4mx778ZAzrB87nLHMqk+X
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
github.com/lightninglabs/lndclient v0.11.0-4/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI= github.com/lightninglabs/lndclient v0.11.0-4/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI=
github.com/lightninglabs/lndclient v0.14.0-8 h1:vdwV6yFU4A7BjG2V8cpI8Kqdl2M0NSfsA+RWR+JGTko= github.com/lightninglabs/lndclient v0.14.2-3 h1:19HWiGCUNejCAm9Ffl5Y56A8u6ZDhhfyjPSDbMDmjuw=
github.com/lightninglabs/lndclient v0.14.0-8/go.mod h1:YIE/Yac69hIMiq9cm/ZC2sP4F0Llv3tC4hZGfgOhdeY= github.com/lightninglabs/lndclient v0.14.2-3/go.mod h1:8fu/+OAK1PqUx9oglz5p0WPOSAwKBUwrC3q3D1yi6Oo=
github.com/lightninglabs/neutrino v0.12.1/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E= github.com/lightninglabs/neutrino v0.12.1/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E=
github.com/lightninglabs/neutrino v0.13.0 h1:j3PKWEJCwqwMn/qLASz2j0IuCF6AumS9DaM0i0pM/nY= github.com/lightninglabs/neutrino v0.13.0 h1:j3PKWEJCwqwMn/qLASz2j0IuCF6AumS9DaM0i0pM/nY=
github.com/lightninglabs/neutrino v0.13.0/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E= github.com/lightninglabs/neutrino v0.13.0/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E=
@ -568,7 +568,6 @@ github.com/lightningnetwork/lnd/clock v1.1.0/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ4
github.com/lightningnetwork/lnd/healthcheck v1.0.0/go.mod h1:u92p1JGFJNMSkMvztKEwmt1P3TRnLeJBXZ3M85xkU1E= github.com/lightningnetwork/lnd/healthcheck v1.0.0/go.mod h1:u92p1JGFJNMSkMvztKEwmt1P3TRnLeJBXZ3M85xkU1E=
github.com/lightningnetwork/lnd/healthcheck v1.2.0 h1:00bkNn+hGJM9j3Ht+ulf8YNcSx1HEYSDv5pf4HB1/uQ= github.com/lightningnetwork/lnd/healthcheck v1.2.0 h1:00bkNn+hGJM9j3Ht+ulf8YNcSx1HEYSDv5pf4HB1/uQ=
github.com/lightningnetwork/lnd/healthcheck v1.2.0/go.mod h1:WSz3lsUjErJQZ3gb+zW32nM3WIHNiZ3A40GVoaQY5wU= github.com/lightningnetwork/lnd/healthcheck v1.2.0/go.mod h1:WSz3lsUjErJQZ3gb+zW32nM3WIHNiZ3A40GVoaQY5wU=
github.com/lightningnetwork/lnd/kvdb v1.2.0/go.mod h1:4DW7zc9AWqqJBvwhSE251VasYikTELItN70hESIt9RU=
github.com/lightningnetwork/lnd/kvdb v1.3.0 h1:0sadTsmfIoorGvd2zf09q/H7sxa/OU48NCpCQUPNN48= github.com/lightningnetwork/lnd/kvdb v1.3.0 h1:0sadTsmfIoorGvd2zf09q/H7sxa/OU48NCpCQUPNN48=
github.com/lightningnetwork/lnd/kvdb v1.3.0/go.mod h1:x+IpsuDynubjokUofavLXroeGfS/WrqUXXTK6vN/gp4= github.com/lightningnetwork/lnd/kvdb v1.3.0/go.mod h1:x+IpsuDynubjokUofavLXroeGfS/WrqUXXTK6vN/gp4=
github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms= github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms=

@ -26,8 +26,8 @@ var (
// listed build tags/subservers need to be enabled. // listed build tags/subservers need to be enabled.
LoopMinRequiredLndVersion = &verrpc.Version{ LoopMinRequiredLndVersion = &verrpc.Version{
AppMajor: 0, AppMajor: 0,
AppMinor: 11, AppMinor: 14,
AppPatch: 1, AppPatch: 2,
BuildTags: []string{ BuildTags: []string{
"signrpc", "walletrpc", "chainrpc", "invoicesrpc", "signrpc", "walletrpc", "chainrpc", "invoicesrpc",
}, },

@ -19,6 +19,7 @@ This file tracks release notes for the loop client.
* Loop client now supports optional routing plugins to improve off-chain payment * Loop client now supports optional routing plugins to improve off-chain payment
reliability. One such plugin that the client implemenets will gradually prefer reliability. One such plugin that the client implemenets will gradually prefer
increasingly more expensive routes in case payments using cheap routes time out. increasingly more expensive routes in case payments using cheap routes time out.
Note that with this addition the minimum required LND version is LND 0.14.2-beta.
#### Breaking Changes #### Breaking Changes

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"sort" "sort"
"sync" "sync"
"time"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
@ -520,13 +519,10 @@ func (r *lowToHighRoutingPlugin) BeforePayment(ctx context.Context,
limit := minFee + limit := minFee +
((maxFee-minFee)/int64(maxAttempts))*int64(currAttempt) ((maxFee-minFee)/int64(maxAttempts))*int64(currAttempt)
// Create a timestamp just slightly in the future as Mission Control // With the forced MC import we can safely set the pair history
// stores timestamps with sub second precision where as we send a unix // timestamps to the current time as import will always just override
// timestamp it may occur that we can't override the last entries as // current MC state.
// they have the same unix timestamp. now := r.clock.Now()
// TODO(bhandras): not very reliable, ideally we'd need a force import
// for MC.
now := r.clock.Now().Add(time.Second)
allowed := 0 allowed := 0
entries := make( entries := make(
@ -566,7 +562,7 @@ func (r *lowToHighRoutingPlugin) BeforePayment(ctx context.Context,
return ErrRoutingPluginNoMoreRetries return ErrRoutingPluginNoMoreRetries
} }
err := r.lnd.Router.ImportMissionControl(ctx, entries) err := r.lnd.Router.ImportMissionControl(ctx, entries, true)
if err != nil { if err != nil {
return err return err
} }
@ -606,10 +602,10 @@ func (r *lowToHighRoutingPlugin) Done(ctx context.Context) error {
return nil return nil
} }
// Roll the entry times forward (to be able to override recent updates). // With the forced import we're safe to just set the pair history
// Use the "time travel" trick which is required to make overrides // timestamps to the current time as import will always succeed and
// succeed. // override current MC state.
now := r.clock.Now().Add(time.Second) now := r.clock.Now()
entries := make( entries := make(
[]lndclient.MissionControlEntry, 0, len(r.nodesByMaxFee), []lndclient.MissionControlEntry, 0, len(r.nodesByMaxFee),
) )
@ -647,7 +643,7 @@ func (r *lowToHighRoutingPlugin) Done(ctx context.Context) error {
} }
} }
err := r.lnd.Router.ImportMissionControl(ctx, entries) err := r.lnd.Router.ImportMissionControl(ctx, entries, true)
if err != nil { if err != nil {
return err return err
} }

@ -81,8 +81,6 @@ func TestLowHighRoutingPlugin(t *testing.T) {
target := loopNode target := loopNode
amt := btcutil.Amount(50) amt := btcutil.Amount(50)
testTime := time.Now().UTC() testTime := time.Now().UTC()
// We expect Mission Control entries to be set to now + 1 sec.
testTimeMc := testTime.Add(time.Second)
tests := []struct { tests := []struct {
name string name string
@ -168,7 +166,7 @@ func TestLowHighRoutingPlugin(t *testing.T) {
NodeTo: dave, NodeTo: dave,
FailTime: time.Time{}, FailTime: time.Time{},
FailAmt: 0, FailAmt: 0,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 10000, SuccessAmt: 10000,
}, },
}, },
@ -210,14 +208,14 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: bob, NodeFrom: bob,
NodeTo: dave, NodeTo: dave,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1, FailAmt: 1,
}, },
// Encourage Charlie - Dave // Encourage Charlie - Dave
{ {
NodeFrom: charlie, NodeFrom: charlie,
NodeTo: dave, NodeTo: dave,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },
@ -228,15 +226,15 @@ func TestLowHighRoutingPlugin(t *testing.T) {
NodeTo: dave, NodeTo: dave,
FailTime: time.Time{}, FailTime: time.Time{},
FailAmt: 0, FailAmt: 0,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 10000, SuccessAmt: 10000,
}, },
{ {
NodeFrom: charlie, NodeFrom: charlie,
NodeTo: dave, NodeTo: dave,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1000001, FailAmt: 1000001,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },
@ -283,13 +281,13 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: bob, NodeFrom: bob,
NodeTo: dave, NodeTo: dave,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 999000, SuccessAmt: 999000,
}, },
{ {
NodeFrom: charlie, NodeFrom: charlie,
NodeTo: dave, NodeTo: dave,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 999000, SuccessAmt: 999000,
}, },
}, },
@ -304,17 +302,17 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: bob, NodeFrom: bob,
NodeTo: dave, NodeTo: dave,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 999000, SuccessAmt: 999000,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 999001, FailAmt: 999001,
}, },
{ {
NodeFrom: charlie, NodeFrom: charlie,
NodeTo: dave, NodeTo: dave,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 999000, SuccessAmt: 999000,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 999001, FailAmt: 999001,
}, },
}, },
@ -375,21 +373,21 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: bob, NodeFrom: bob,
NodeTo: eugene, NodeTo: eugene,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1, FailAmt: 1,
}, },
// Encourage Charlie - Eugene // Encourage Charlie - Eugene
{ {
NodeFrom: charlie, NodeFrom: charlie,
NodeTo: eugene, NodeTo: eugene,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
// Encourage Dave - Eugene // Encourage Dave - Eugene
{ {
NodeFrom: dave, NodeFrom: dave,
NodeTo: eugene, NodeTo: eugene,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },
@ -399,21 +397,21 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: bob, NodeFrom: bob,
NodeTo: eugene, NodeTo: eugene,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1, FailAmt: 1,
}, },
// Discourage Charlie - Eugene // Discourage Charlie - Eugene
{ {
NodeFrom: charlie, NodeFrom: charlie,
NodeTo: eugene, NodeTo: eugene,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1, FailAmt: 1,
}, },
// Encourage Dave - Eugene // Encourage Dave - Eugene
{ {
NodeFrom: dave, NodeFrom: dave,
NodeTo: eugene, NodeTo: eugene,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },
@ -422,9 +420,9 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: bob, NodeFrom: bob,
NodeTo: eugene, NodeTo: eugene,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1000001, FailAmt: 1000001,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
{ {
@ -432,15 +430,15 @@ func TestLowHighRoutingPlugin(t *testing.T) {
NodeTo: eugene, NodeTo: eugene,
FailTime: time.Time{}, FailTime: time.Time{},
FailAmt: 0, FailAmt: 0,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 10000, SuccessAmt: 10000,
}, },
{ {
NodeFrom: dave, NodeFrom: dave,
NodeTo: eugene, NodeTo: eugene,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1000001, FailAmt: 1000001,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },
@ -500,14 +498,14 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: frank, NodeFrom: frank,
NodeTo: george, NodeTo: george,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1, FailAmt: 1,
}, },
// Encourage Dave - George // Encourage Dave - George
{ {
NodeFrom: dave, NodeFrom: dave,
NodeTo: george, NodeTo: george,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },
@ -522,17 +520,17 @@ func TestLowHighRoutingPlugin(t *testing.T) {
{ {
NodeFrom: frank, NodeFrom: frank,
NodeTo: george, NodeTo: george,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1000001, FailAmt: 1000001,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
{ {
NodeFrom: dave, NodeFrom: dave,
NodeTo: george, NodeTo: george,
FailTime: testTimeMc, FailTime: testTime,
FailAmt: 1000001, FailAmt: 1000001,
SuccessTime: testTimeMc, SuccessTime: testTime,
SuccessAmt: 1000000, SuccessAmt: 1000000,
}, },
}, },

@ -52,7 +52,7 @@ func (r *mockRouter) QueryMissionControl(ctx context.Context) (
// ImpotMissionControl is a mocked reimplementation of the pair import. // ImpotMissionControl is a mocked reimplementation of the pair import.
// Reference: lnd/router/missioncontrol_state.go:importSnapshot(). // Reference: lnd/router/missioncontrol_state.go:importSnapshot().
func (r *mockRouter) ImportMissionControl(ctx context.Context, func (r *mockRouter) ImportMissionControl(ctx context.Context,
entries []lndclient.MissionControlEntry) error { entries []lndclient.MissionControlEntry, force bool) error {
for _, entry := range entries { for _, entry := range entries {
found := false found := false
@ -79,12 +79,14 @@ func (r *mockRouter) ImportMissionControl(ctx context.Context,
// Import success result second. // Import success result second.
current.SuccessTime = entry.SuccessTime current.SuccessTime = entry.SuccessTime
if entry.SuccessAmt > current.SuccessAmt { if force ||
entry.SuccessAmt > current.SuccessAmt {
current.SuccessAmt = entry.SuccessAmt current.SuccessAmt = entry.SuccessAmt
} }
if !current.FailTime.IsZero() && if !force && (!current.FailTime.IsZero() &&
entry.SuccessAmt >= current.FailAmt { entry.SuccessAmt >= current.FailAmt) {
current.FailAmt = entry.SuccessAmt + 1 current.FailAmt = entry.SuccessAmt + 1
} }

Loading…
Cancel
Save