From 6e8442b3339bdae89f048f1dca8474310a4f1573 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 16 Apr 2020 15:20:23 +0200 Subject: [PATCH 1/3] routing: move payment session constructor --- routing/integrated_routing_context_test.go | 18 ++++--- routing/payment_session.go | 24 +++++++++ routing/payment_session_source.go | 24 ++++----- routing/payment_session_test.go | 59 +++++++++++----------- 4 files changed, 73 insertions(+), 52 deletions(-) diff --git a/routing/integrated_routing_context_test.go b/routing/integrated_routing_context_test.go index 457ed4f4..cc71560d 100644 --- a/routing/integrated_routing_context_test.go +++ b/routing/integrated_routing_context_test.go @@ -140,18 +140,20 @@ func (c *integratedRoutingContext) testPayment(maxShards uint32) ([]htlcAttempt, MaxShards: maxShards, } - session := &paymentSession{ - getBandwidthHints: getBandwidthHints, - payment: &payment, - pathFinder: findPath, - getRoutingGraph: func() (routingGraph, func(), error) { + session, err := newPaymentSession( + &payment, getBandwidthHints, + func() (routingGraph, func(), error) { return c.graph, func() {}, nil }, - pathFindingConfig: c.pathFindingCfg, - missionControl: mc, - minShardAmt: lnwire.NewMSatFromSatoshis(5000), + mc, c.pathFindingCfg, + ) + if err != nil { + c.t.Fatal(err) } + // Override default minimum shard amount. + session.minShardAmt = lnwire.NewMSatFromSatoshis(5000) + // Now the payment control loop starts. It will keep trying routes until // the payment succeeds. var ( diff --git a/routing/payment_session.go b/routing/payment_session.go index c5a20f7a..2eef929e 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -126,6 +126,30 @@ type paymentSession struct { minShardAmt lnwire.MilliSatoshi } +// newPaymentSession instantiates a new payment session. +func newPaymentSession(p *LightningPayment, + getBandwidthHints func() (map[uint64]lnwire.MilliSatoshi, error), + getRoutingGraph func() (routingGraph, func(), error), + missionControl MissionController, pathFindingConfig PathFindingConfig) ( + *paymentSession, error) { + + edges, err := RouteHintsToEdges(p.RouteHints, p.Target) + if err != nil { + return nil, err + } + + return &paymentSession{ + additionalEdges: edges, + getBandwidthHints: getBandwidthHints, + payment: p, + pathFinder: findPath, + getRoutingGraph: getRoutingGraph, + pathFindingConfig: pathFindingConfig, + missionControl: missionControl, + minShardAmt: DefaultShardMinAmt, + }, nil +} + // RequestRoute returns a route which is likely to be capable for successfully // routing the specified HTLC payment to the target node. Initially the first // set of paths returned from this method may encounter routing failure along diff --git a/routing/payment_session_source.go b/routing/payment_session_source.go index a6016ab8..8122ff71 100644 --- a/routing/payment_session_source.go +++ b/routing/payment_session_source.go @@ -62,11 +62,6 @@ func (m *SessionSource) getRoutingGraph() (routingGraph, func(), error) { func (m *SessionSource) NewPaymentSession(p *LightningPayment) ( PaymentSession, error) { - edges, err := RouteHintsToEdges(p.RouteHints, p.Target) - if err != nil { - return nil, err - } - sourceNode, err := m.Graph.SourceNode() if err != nil { return nil, err @@ -78,16 +73,15 @@ func (m *SessionSource) NewPaymentSession(p *LightningPayment) ( return generateBandwidthHints(sourceNode, m.QueryBandwidth) } - return &paymentSession{ - additionalEdges: edges, - getBandwidthHints: getBandwidthHints, - payment: p, - pathFinder: findPath, - getRoutingGraph: m.getRoutingGraph, - pathFindingConfig: m.PathFindingConfig, - missionControl: m.MissionControl, - minShardAmt: DefaultShardMinAmt, - }, nil + session, err := newPaymentSession( + p, getBandwidthHints, m.getRoutingGraph, + m.MissionControl, m.PathFindingConfig, + ) + if err != nil { + return nil, err + } + + return session, nil } // NewPaymentSessionEmpty creates a new paymentSession instance that is empty, diff --git a/routing/payment_session_test.go b/routing/payment_session_test.go index 60d960b8..ba55fcea 100644 --- a/routing/payment_session_test.go +++ b/routing/payment_session_test.go @@ -13,9 +13,36 @@ func TestRequestRoute(t *testing.T) { height = 10 ) - findPath := func( - g *graphParams, - r *RestrictParams, cfg *PathFindingConfig, + cltvLimit := uint32(30) + finalCltvDelta := uint16(8) + + payment := &LightningPayment{ + CltvLimit: cltvLimit, + FinalCLTVDelta: finalCltvDelta, + Amount: 1000, + FeeLimit: 1000, + } + + session, err := newPaymentSession( + payment, + func() (map[uint64]lnwire.MilliSatoshi, + error) { + + return nil, nil + }, + func() (routingGraph, func(), error) { + return &sessionGraph{}, func() {}, nil + }, + &MissionControl{cfg: &MissionControlConfig{}}, + PathFindingConfig{}, + ) + if err != nil { + t.Fatal(err) + } + + // Override pathfinder with a mock. + session.pathFinder = func( + g *graphParams, r *RestrictParams, cfg *PathFindingConfig, source, target route.Vertex, amt lnwire.MilliSatoshi, finalHtlcExpiry int32) ([]*channeldb.ChannelEdgePolicy, error) { @@ -38,32 +65,6 @@ func TestRequestRoute(t *testing.T) { return path, nil } - cltvLimit := uint32(30) - finalCltvDelta := uint16(8) - - payment := &LightningPayment{ - CltvLimit: cltvLimit, - FinalCLTVDelta: finalCltvDelta, - Amount: 1000, - FeeLimit: 1000, - } - - session := &paymentSession{ - getBandwidthHints: func() (map[uint64]lnwire.MilliSatoshi, - error) { - - return nil, nil - }, - payment: payment, - pathFinder: findPath, - missionControl: &MissionControl{ - cfg: &MissionControlConfig{}, - }, - getRoutingGraph: func() (routingGraph, func(), error) { - return &sessionGraph{}, func() {}, nil - }, - } - route, err := session.RequestRoute( payment.Amount, payment.FeeLimit, 0, height, ) From 9bd7eb74b68504d683a5310b406a1e68c4f3bef6 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 16 Apr 2020 15:22:44 +0200 Subject: [PATCH 2/3] routing: add prefix logger for payment session --- routing/payment_session.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/routing/payment_session.go b/routing/payment_session.go index 2eef929e..6c467768 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -1,6 +1,10 @@ package routing import ( + "fmt" + + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" @@ -124,6 +128,9 @@ type paymentSession struct { // specified in the payment is one, under no circumstances splitting // will happen and this value remains unused. minShardAmt lnwire.MilliSatoshi + + // log is a payment session-specific logger. + log btclog.Logger } // newPaymentSession instantiates a new payment session. @@ -138,6 +145,8 @@ func newPaymentSession(p *LightningPayment, return nil, err } + logPrefix := fmt.Sprintf("PaymentSession(%x):", p.PaymentHash) + return &paymentSession{ additionalEdges: edges, getBandwidthHints: getBandwidthHints, @@ -147,6 +156,7 @@ func newPaymentSession(p *LightningPayment, pathFindingConfig: pathFindingConfig, missionControl: missionControl, minShardAmt: DefaultShardMinAmt, + log: build.NewPrefixLog(logPrefix, log), }, nil } @@ -206,8 +216,7 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, return nil, err } - log.Debugf("PaymentSession for %x: trying pathfinding with %v", - p.payment.PaymentHash, maxAmt) + p.log.Debugf("pathfinding for amt=%v", maxAmt) // Get a routing graph. routingGraph, cleanup, err := p.getRoutingGraph() @@ -237,6 +246,10 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, // No splitting if this is the last shard. isLastShard := activeShards+1 >= p.payment.MaxShards if isLastShard { + p.log.Debugf("not splitting because shard "+ + "limit %v has been reached", + p.payment.MaxShards) + return nil, errNoPathFound } @@ -246,6 +259,10 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, // Put a lower bound on the minimum shard size. if maxAmt < p.minShardAmt { + p.log.Debugf("not splitting because minimum "+ + "shard amount %v has been reached", + p.minShardAmt) + return nil, errNoPathFound } From 805641adf5e771e4f29375da547bdd988ccf8c24 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 16 Apr 2020 15:08:07 +0200 Subject: [PATCH 3/3] routing: do not split payment if destination does not support mpp --- routing/payment_session.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/routing/payment_session.go b/routing/payment_session.go index 6c467768..f5a49eff 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -243,6 +243,15 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, switch { case err == errNoPathFound: + // Don't split if this is a legacy payment without mpp + // record. + if p.payment.PaymentAddr == nil { + p.log.Debugf("not splitting because payment " + + "address is unspecified") + + return nil, errNoPathFound + } + // No splitting if this is the last shard. isLastShard := activeShards+1 >= p.payment.MaxShards if isLastShard {