From f4306b117811ace2dfbc9eb117b6cb777a050ef1 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Thu, 23 May 2019 20:05:30 +0200 Subject: [PATCH] routing/payment_session+router: make PaymentSession interface --- routing/missioncontrol.go | 6 ++--- routing/payment_lifecycle.go | 2 +- routing/payment_session.go | 45 ++++++++++++++++++++++++++++++++++-- routing/router.go | 4 ++-- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index aa4cd064..1d79e0fe 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -155,7 +155,7 @@ func (m *MissionControl) graphPruneView() graphPruneView { // in order to populate additional edges to explore when finding a path to the // payment's destination. func (m *MissionControl) NewPaymentSession(routeHints [][]zpay32.HopHint, - target route.Vertex) (*paymentSession, error) { + target route.Vertex) (PaymentSession, error) { viewSnapshot := m.graphPruneView() @@ -233,7 +233,7 @@ func (m *MissionControl) NewPaymentSession(routeHints [][]zpay32.HopHint, // NewPaymentSessionForRoute creates a new paymentSession instance that is just // used for failure reporting to missioncontrol. -func (m *MissionControl) NewPaymentSessionForRoute(preBuiltRoute *route.Route) *paymentSession { +func (m *MissionControl) NewPaymentSessionForRoute(preBuiltRoute *route.Route) PaymentSession { return &paymentSession{ pruneViewSnapshot: m.graphPruneView(), errFailedPolicyChans: make(map[EdgeLocator]struct{}), @@ -245,7 +245,7 @@ func (m *MissionControl) NewPaymentSessionForRoute(preBuiltRoute *route.Route) * // NewPaymentSessionEmpty creates a new paymentSession instance that is empty, // and will be exhausted immediately. Used for failure reporting to // missioncontrol for resumed payment we don't want to make more attempts for. -func (m *MissionControl) NewPaymentSessionEmpty() *paymentSession { +func (m *MissionControl) NewPaymentSessionEmpty() PaymentSession { return &paymentSession{ pruneViewSnapshot: m.graphPruneView(), errFailedPolicyChans: make(map[EdgeLocator]struct{}), diff --git a/routing/payment_lifecycle.go b/routing/payment_lifecycle.go index 3c72958d..29b4bf1f 100644 --- a/routing/payment_lifecycle.go +++ b/routing/payment_lifecycle.go @@ -17,7 +17,7 @@ import ( type paymentLifecycle struct { router *ChannelRouter payment *LightningPayment - paySession *paymentSession + paySession PaymentSession timeoutChan <-chan time.Time currentHeight int32 finalCLTVDelta uint16 diff --git a/routing/payment_session.go b/routing/payment_session.go index 78926ce3..28047f53 100644 --- a/routing/payment_session.go +++ b/routing/payment_session.go @@ -9,6 +9,36 @@ import ( "github.com/lightningnetwork/lnd/routing/route" ) +// PaymentSession is used during SendPayment attempts to provide routes to +// attempt. It also defines methods to give the PaymentSession additional +// information learned during the previous attempts. +type PaymentSession interface { + // RequestRoute returns the next route to attempt for routing the + // specified HTLC payment to the target node. + RequestRoute(payment *LightningPayment, + height uint32, finalCltvDelta uint16) (*route.Route, error) + + // ReportVertexFailure reports to the PaymentSession that the passsed + // vertex failed to route the previous payment attempt. The + // PaymentSession will use this information to produce a better next + // route. + ReportVertexFailure(v route.Vertex) + + // ReportEdgeFailure reports to the PaymentSession that the passed + // channel failed to route the previous payment attempt. The + // PaymentSession will use this information to produce a better next + // route. + ReportEdgeFailure(e *EdgeLocator) + + // ReportEdgePolicyFailure reports to the PaymentSession that we + // received a failure message that relates to a channel policy. For + // these types of failures, the PaymentSession can decide whether to to + // keep the edge included in the next attempted route. The + // PaymentSession will use this information to produce a better next + // route. + ReportEdgePolicyFailure(errSource route.Vertex, failedEdge *EdgeLocator) +} + // paymentSession is used during an HTLC routings session to prune the local // chain view in response to failures, and also report those failures back to // MissionControl. The snapshot copied for this session will only ever grow, @@ -38,11 +68,17 @@ type paymentSession struct { pathFinder pathFinder } +// A compile time assertion to ensure paymentSession meets the PaymentSession +// interface. +var _ PaymentSession = (*paymentSession)(nil) + // ReportVertexFailure adds a vertex to the graph prune view after a client // reports a routing failure localized to the vertex. The time the vertex was // added is noted, as it'll be pruned from the shared view after a period of // vertexDecay. However, the vertex will remain pruned for the *local* session. // This ensures we don't retry this vertex during the payment attempt. +// +// NOTE: Part of the PaymentSession interface. func (p *paymentSession) ReportVertexFailure(v route.Vertex) { log.Debugf("Reporting vertex %v failure to Mission Control", v) @@ -57,13 +93,15 @@ func (p *paymentSession) ReportVertexFailure(v route.Vertex) { p.mc.Unlock() } -// ReportChannelFailure adds a channel to the graph prune view. The time the +// ReportEdgeFailure adds a channel to the graph prune view. The time the // channel was added is noted, as it'll be pruned from the global view after a // period of edgeDecay. However, the edge will remain pruned for the duration // of the *local* session. This ensures that we don't flap by continually // retrying an edge after its pruning has expired. // // TODO(roasbeef): also add value attempted to send and capacity of channel +// +// NOTE: Part of the PaymentSession interface. func (p *paymentSession) ReportEdgeFailure(e *EdgeLocator) { log.Debugf("Reporting edge %v failure to Mission Control", e) @@ -78,12 +116,14 @@ func (p *paymentSession) ReportEdgeFailure(e *EdgeLocator) { p.mc.Unlock() } -// ReportChannelPolicyFailure handles a failure message that relates to a +// ReportEdgePolicyFailure handles a failure message that relates to a // channel policy. For these types of failures, the policy is updated and we // want to keep it included during path finding. This function does mark the // edge as 'policy failed once'. The next time it fails, the whole node will be // pruned. This is to prevent nodes from keeping us busy by continuously sending // new channel updates. +// +// NOTE: Part of the PaymentSession interface. func (p *paymentSession) ReportEdgePolicyFailure( errSource route.Vertex, failedEdge *EdgeLocator) { @@ -111,6 +151,7 @@ func (p *paymentSession) ReportEdgePolicyFailure( // will be explored, which feeds into the recommendations made for routing. // // NOTE: This function is safe for concurrent access. +// NOTE: Part of the PaymentSession interface. func (p *paymentSession) RequestRoute(payment *LightningPayment, height uint32, finalCltvDelta uint16) (*route.Route, error) { diff --git a/routing/router.go b/routing/router.go index 34b48102..a7d70114 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1661,7 +1661,7 @@ func (r *ChannelRouter) SendToRoute(hash lntypes.Hash, route *route.Route) ( // the ControlTower. func (r *ChannelRouter) sendPayment( existingAttempt *channeldb.PaymentAttemptInfo, - payment *LightningPayment, paySession *paymentSession) ( + payment *LightningPayment, paySession PaymentSession) ( [32]byte, *route.Route, error) { log.Tracef("Dispatching route for lightning payment: %v", @@ -1721,7 +1721,7 @@ func (r *ChannelRouter) sendPayment( // error type, this error is either the final outcome of the payment or we need // to continue with an alternative route. This is indicated by the boolean // return value. -func (r *ChannelRouter) processSendError(paySession *paymentSession, +func (r *ChannelRouter) processSendError(paySession PaymentSession, rt *route.Route, err error) bool { fErr, ok := err.(*htlcswitch.ForwardingError)