mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 18:10:34 +01:00
routing: move payment session to separate file
This commit is contained in:
parent
b7387a5972
commit
7b94d9adb0
@ -1,7 +1,6 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -149,33 +148,6 @@ func (m *missionControl) GraphPruneView() graphPruneView {
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
// and will now be pruned after a decay like the main view within mission
|
||||
// control. We do this as we want to avoid the case where we continually try a
|
||||
// bad edge or route multiple times in a session. This can lead to an infinite
|
||||
// loop if payment attempts take long enough. An additional set of edges can
|
||||
// also be provided to assist in reaching the payment's destination.
|
||||
type paymentSession struct {
|
||||
pruneViewSnapshot graphPruneView
|
||||
|
||||
additionalEdges map[Vertex][]*channeldb.ChannelEdgePolicy
|
||||
|
||||
bandwidthHints map[uint64]lnwire.MilliSatoshi
|
||||
|
||||
// errFailedFeeChans is a map of the short channel IDs that were the
|
||||
// source of policy related routing failures during this payment attempt.
|
||||
// We'll use this map to prune out channels when the first error may not
|
||||
// require pruning, but any subsequent ones do.
|
||||
errFailedPolicyChans map[edgeLocator]struct{}
|
||||
|
||||
mc *missionControl
|
||||
|
||||
haveRoutes bool
|
||||
preBuiltRoutes []*Route
|
||||
}
|
||||
|
||||
// NewPaymentSession creates a new payment session backed by the latest prune
|
||||
// view from Mission Control. An optional set of routing hints can be provided
|
||||
// in order to populate additional edges to explore when finding a path to the
|
||||
@ -299,145 +271,6 @@ func generateBandwidthHints(sourceNode *channeldb.LightningNode,
|
||||
return bandwidthHints, 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.
|
||||
func (p *paymentSession) ReportVertexFailure(v Vertex) {
|
||||
log.Debugf("Reporting vertex %v failure to Mission Control", v)
|
||||
|
||||
// First, we'll add the failed vertex to our local prune view snapshot.
|
||||
p.pruneViewSnapshot.vertexes[v] = struct{}{}
|
||||
|
||||
// With the vertex added, we'll now report back to the global prune
|
||||
// view, with this new piece of information so it can be utilized for
|
||||
// new payment sessions.
|
||||
p.mc.Lock()
|
||||
p.mc.failedVertexes[v] = time.Now()
|
||||
p.mc.Unlock()
|
||||
}
|
||||
|
||||
// ReportChannelFailure 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
|
||||
func (p *paymentSession) ReportEdgeFailure(e *edgeLocator) {
|
||||
log.Debugf("Reporting edge %v failure to Mission Control", e)
|
||||
|
||||
// First, we'll add the failed edge to our local prune view snapshot.
|
||||
p.pruneViewSnapshot.edges[*e] = struct{}{}
|
||||
|
||||
// With the edge added, we'll now report back to the global prune view,
|
||||
// with this new piece of information so it can be utilized for new
|
||||
// payment sessions.
|
||||
p.mc.Lock()
|
||||
p.mc.failedEdges[*e] = time.Now()
|
||||
p.mc.Unlock()
|
||||
}
|
||||
|
||||
// ReportChannelPolicyFailure 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.
|
||||
func (p *paymentSession) ReportEdgePolicyFailure(
|
||||
errSource Vertex, failedEdge *edgeLocator) {
|
||||
|
||||
// Check to see if we've already reported a policy related failure for
|
||||
// this channel. If so, then we'll prune out the vertex.
|
||||
_, ok := p.errFailedPolicyChans[*failedEdge]
|
||||
if ok {
|
||||
// TODO(joostjager): is this aggresive pruning still necessary?
|
||||
// Just pruning edges may also work unless there is a huge
|
||||
// number of failing channels from that node?
|
||||
p.ReportVertexFailure(errSource)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, we'll record a policy failure from this node and move on.
|
||||
p.errFailedPolicyChans[*failedEdge] = struct{}{}
|
||||
}
|
||||
|
||||
// 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
|
||||
// the way, however as more payments are sent, mission control will start to
|
||||
// build an up to date view of the network itself. With each payment a new area
|
||||
// will be explored, which feeds into the recommendations made for routing.
|
||||
//
|
||||
// NOTE: This function is safe for concurrent access.
|
||||
func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
||||
height uint32, finalCltvDelta uint16) (*Route, error) {
|
||||
|
||||
switch {
|
||||
// If we have a set of pre-built routes, then we'll just pop off the
|
||||
// next route from the queue, and use it directly.
|
||||
case p.haveRoutes && len(p.preBuiltRoutes) > 0:
|
||||
nextRoute := p.preBuiltRoutes[0]
|
||||
p.preBuiltRoutes[0] = nil // Set to nil to avoid GC leak.
|
||||
p.preBuiltRoutes = p.preBuiltRoutes[1:]
|
||||
|
||||
return nextRoute, nil
|
||||
|
||||
// If we were instantiated with a set of pre-built routes, and we've
|
||||
// run out, then we'll return a terminal error.
|
||||
case p.haveRoutes && len(p.preBuiltRoutes) == 0:
|
||||
return nil, fmt.Errorf("pre-built routes exhausted")
|
||||
}
|
||||
|
||||
// Otherwise we actually need to perform path finding, so we'll obtain
|
||||
// our current prune view snapshot. This view will only ever grow
|
||||
// during the duration of this payment session, never shrinking.
|
||||
pruneView := p.pruneViewSnapshot
|
||||
|
||||
log.Debugf("Mission Control session using prune view of %v "+
|
||||
"edges, %v vertexes", len(pruneView.edges),
|
||||
len(pruneView.vertexes))
|
||||
|
||||
// TODO(roasbeef): sync logic amongst dist sys
|
||||
|
||||
// Taking into account this prune view, we'll attempt to locate a path
|
||||
// to our destination, respecting the recommendations from
|
||||
// missionControl.
|
||||
path, err := findPath(
|
||||
&graphParams{
|
||||
graph: p.mc.graph,
|
||||
additionalEdges: p.additionalEdges,
|
||||
bandwidthHints: p.bandwidthHints,
|
||||
},
|
||||
&restrictParams{
|
||||
ignoredNodes: pruneView.vertexes,
|
||||
ignoredEdges: pruneView.edges,
|
||||
feeLimit: payment.FeeLimit,
|
||||
},
|
||||
p.mc.selfNode, payment.Target, payment.Amount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// With the next candidate path found, we'll attempt to turn this into
|
||||
// a route by applying the time-lock and fee requirements.
|
||||
sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes)
|
||||
route, err := newRoute(
|
||||
payment.Amount, payment.FeeLimit, sourceVertex, path, height,
|
||||
finalCltvDelta,
|
||||
)
|
||||
if err != nil {
|
||||
// TODO(roasbeef): return which edge/vertex didn't work
|
||||
// out
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return route, err
|
||||
}
|
||||
|
||||
// ResetHistory resets the history of missionControl returning it to a state as
|
||||
// if no payment attempts have been made.
|
||||
func (m *missionControl) ResetHistory() {
|
||||
|
175
routing/payment_session.go
Normal file
175
routing/payment_session.go
Normal file
@ -0,0 +1,175 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// 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,
|
||||
// and will now be pruned after a decay like the main view within mission
|
||||
// control. We do this as we want to avoid the case where we continually try a
|
||||
// bad edge or route multiple times in a session. This can lead to an infinite
|
||||
// loop if payment attempts take long enough. An additional set of edges can
|
||||
// also be provided to assist in reaching the payment's destination.
|
||||
type paymentSession struct {
|
||||
pruneViewSnapshot graphPruneView
|
||||
|
||||
additionalEdges map[Vertex][]*channeldb.ChannelEdgePolicy
|
||||
|
||||
bandwidthHints map[uint64]lnwire.MilliSatoshi
|
||||
|
||||
// errFailedFeeChans is a map of the short channel IDs that were the
|
||||
// source of policy related routing failures during this payment attempt.
|
||||
// We'll use this map to prune out channels when the first error may not
|
||||
// require pruning, but any subsequent ones do.
|
||||
errFailedPolicyChans map[edgeLocator]struct{}
|
||||
|
||||
mc *missionControl
|
||||
|
||||
haveRoutes bool
|
||||
preBuiltRoutes []*Route
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (p *paymentSession) ReportVertexFailure(v Vertex) {
|
||||
log.Debugf("Reporting vertex %v failure to Mission Control", v)
|
||||
|
||||
// First, we'll add the failed vertex to our local prune view snapshot.
|
||||
p.pruneViewSnapshot.vertexes[v] = struct{}{}
|
||||
|
||||
// With the vertex added, we'll now report back to the global prune
|
||||
// view, with this new piece of information so it can be utilized for
|
||||
// new payment sessions.
|
||||
p.mc.Lock()
|
||||
p.mc.failedVertexes[v] = time.Now()
|
||||
p.mc.Unlock()
|
||||
}
|
||||
|
||||
// ReportChannelFailure 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
|
||||
func (p *paymentSession) ReportEdgeFailure(e *edgeLocator) {
|
||||
log.Debugf("Reporting edge %v failure to Mission Control", e)
|
||||
|
||||
// First, we'll add the failed edge to our local prune view snapshot.
|
||||
p.pruneViewSnapshot.edges[*e] = struct{}{}
|
||||
|
||||
// With the edge added, we'll now report back to the global prune view,
|
||||
// with this new piece of information so it can be utilized for new
|
||||
// payment sessions.
|
||||
p.mc.Lock()
|
||||
p.mc.failedEdges[*e] = time.Now()
|
||||
p.mc.Unlock()
|
||||
}
|
||||
|
||||
// ReportChannelPolicyFailure 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.
|
||||
func (p *paymentSession) ReportEdgePolicyFailure(
|
||||
errSource Vertex, failedEdge *edgeLocator) {
|
||||
|
||||
// Check to see if we've already reported a policy related failure for
|
||||
// this channel. If so, then we'll prune out the vertex.
|
||||
_, ok := p.errFailedPolicyChans[*failedEdge]
|
||||
if ok {
|
||||
// TODO(joostjager): is this aggresive pruning still necessary?
|
||||
// Just pruning edges may also work unless there is a huge
|
||||
// number of failing channels from that node?
|
||||
p.ReportVertexFailure(errSource)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, we'll record a policy failure from this node and move on.
|
||||
p.errFailedPolicyChans[*failedEdge] = struct{}{}
|
||||
}
|
||||
|
||||
// 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
|
||||
// the way, however as more payments are sent, mission control will start to
|
||||
// build an up to date view of the network itself. With each payment a new area
|
||||
// will be explored, which feeds into the recommendations made for routing.
|
||||
//
|
||||
// NOTE: This function is safe for concurrent access.
|
||||
func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
||||
height uint32, finalCltvDelta uint16) (*Route, error) {
|
||||
|
||||
switch {
|
||||
// If we have a set of pre-built routes, then we'll just pop off the
|
||||
// next route from the queue, and use it directly.
|
||||
case p.haveRoutes && len(p.preBuiltRoutes) > 0:
|
||||
nextRoute := p.preBuiltRoutes[0]
|
||||
p.preBuiltRoutes[0] = nil // Set to nil to avoid GC leak.
|
||||
p.preBuiltRoutes = p.preBuiltRoutes[1:]
|
||||
|
||||
return nextRoute, nil
|
||||
|
||||
// If we were instantiated with a set of pre-built routes, and we've
|
||||
// run out, then we'll return a terminal error.
|
||||
case p.haveRoutes && len(p.preBuiltRoutes) == 0:
|
||||
return nil, fmt.Errorf("pre-built routes exhausted")
|
||||
}
|
||||
|
||||
// Otherwise we actually need to perform path finding, so we'll obtain
|
||||
// our current prune view snapshot. This view will only ever grow
|
||||
// during the duration of this payment session, never shrinking.
|
||||
pruneView := p.pruneViewSnapshot
|
||||
|
||||
log.Debugf("Mission Control session using prune view of %v "+
|
||||
"edges, %v vertexes", len(pruneView.edges),
|
||||
len(pruneView.vertexes))
|
||||
|
||||
// TODO(roasbeef): sync logic amongst dist sys
|
||||
|
||||
// Taking into account this prune view, we'll attempt to locate a path
|
||||
// to our destination, respecting the recommendations from
|
||||
// missionControl.
|
||||
path, err := findPath(
|
||||
&graphParams{
|
||||
graph: p.mc.graph,
|
||||
additionalEdges: p.additionalEdges,
|
||||
bandwidthHints: p.bandwidthHints,
|
||||
},
|
||||
&restrictParams{
|
||||
ignoredNodes: pruneView.vertexes,
|
||||
ignoredEdges: pruneView.edges,
|
||||
feeLimit: payment.FeeLimit,
|
||||
},
|
||||
p.mc.selfNode, payment.Target, payment.Amount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// With the next candidate path found, we'll attempt to turn this into
|
||||
// a route by applying the time-lock and fee requirements.
|
||||
sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes)
|
||||
route, err := newRoute(
|
||||
payment.Amount, payment.FeeLimit, sourceVertex, path, height,
|
||||
finalCltvDelta,
|
||||
)
|
||||
if err != nil {
|
||||
// TODO(roasbeef): return which edge/vertex didn't work
|
||||
// out
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return route, err
|
||||
}
|
Loading…
Reference in New Issue
Block a user