routing: local balance check
This commit is contained in:
7 files changed
+250
-131
No files matched your search
+67
-2
@@ -76,6 +76,10 @@ var (
|
||||
// errMaxHopsExceeded is returned when a candidate path is found, but
|
||||
// the length of that path exceeds HopLimit.
|
||||
errMaxHopsExceeded = errors.New("potential path has too many hops")
|
||||
|
||||
// errInsufficientLocalBalance is returned when none of the local
|
||||
// channels have enough balance for the payment.
|
||||
errInsufficientBalance = errors.New("insufficient local balance")
|
||||
)
|
||||
|
||||
// edgePolicyWithSource is a helper struct to keep track of the source node
|
||||
@@ -305,6 +309,50 @@ type PathFindingConfig struct {
|
||||
MinProbability float64
|
||||
}
|
||||
|
||||
// getMaxOutgoingAmt returns the maximum available balance in any of the
|
||||
// channels of the given node.
|
||||
func getMaxOutgoingAmt(node route.Vertex, outgoingChan *uint64,
|
||||
g *graphParams, tx *bbolt.Tx) (lnwire.MilliSatoshi, error) {
|
||||
|
||||
var max lnwire.MilliSatoshi
|
||||
cb := func(_ *bbolt.Tx, edgeInfo *channeldb.ChannelEdgeInfo, outEdge,
|
||||
_ *channeldb.ChannelEdgePolicy) error {
|
||||
|
||||
if outEdge == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
chanID := outEdge.ChannelID
|
||||
|
||||
// Enforce outgoing channel restriction.
|
||||
if outgoingChan != nil && chanID != *outgoingChan {
|
||||
return nil
|
||||
}
|
||||
|
||||
bandwidth, ok := g.bandwidthHints[chanID]
|
||||
|
||||
// If the bandwidth is not available for whatever reason, don't
|
||||
// fail the pathfinding early.
|
||||
if !ok {
|
||||
max = lnwire.MaxMilliSatoshi
|
||||
return nil
|
||||
}
|
||||
|
||||
if bandwidth > max {
|
||||
max = bandwidth
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Iterate over all channels of the to node.
|
||||
err := g.graph.ForEachNodeChannel(tx, node[:], cb)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return max, err
|
||||
}
|
||||
|
||||
// findPath attempts to find a path from the source node within the
|
||||
// ChannelGraph to the target node that's capable of supporting a payment of
|
||||
// `amt` value. The current approach implemented is modified version of
|
||||
@@ -332,7 +380,13 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
||||
"time=%v", nodesVisited, edgesExpanded, timeElapsed)
|
||||
}()
|
||||
|
||||
var err error
|
||||
// Get source node outside of the pathfinding tx, to prevent a deadlock.
|
||||
selfNode, err := g.graph.SourceNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
self := selfNode.PubKeyBytes
|
||||
|
||||
tx := g.tx
|
||||
if tx == nil {
|
||||
tx, err = g.graph.Database().Begin(false)
|
||||
@@ -365,6 +419,18 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// If we are routing from ourselves, check that we have enough local
|
||||
// balance available.
|
||||
if source == self {
|
||||
max, err := getMaxOutgoingAmt(self, r.OutgoingChannelID, g, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if max < amt {
|
||||
return nil, errInsufficientBalance
|
||||
}
|
||||
}
|
||||
|
||||
// First we'll initialize an empty heap which'll help us to quickly
|
||||
// locate the next edge we should visit next during our graph
|
||||
// traversal.
|
||||
@@ -375,7 +441,6 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
||||
|
||||
additionalEdgesWithSrc := make(map[route.Vertex][]*edgePolicyWithSource)
|
||||
for vertex, outgoingEdgePolicies := range g.additionalEdges {
|
||||
|
||||
// Build reverse lookup to find incoming edges. Needed because
|
||||
// search is taken place from target to source.
|
||||
for _, outgoingEdgePolicy := range outgoingEdgePolicies {
|
||||
|
||||
Reference in new issue
Block a user