routing: local balance check

This commit is contained in:
Joost Jager committed 2019-12-04 09:45:07 +01:00
1 parent c15b0316a2
commit 97344af8f3
7 files changed
+250 -131

No files matched your search

+67 -2
View File
@@ -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 {