diff --git a/routing/heap.go b/routing/heap.go index a20f1d57..62b3e3dd 100644 --- a/routing/heap.go +++ b/routing/heap.go @@ -3,6 +3,7 @@ package routing import ( "container/heap" + "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" ) @@ -35,12 +36,15 @@ type nodeWithDist struct { // Includes the routing fees and a virtual cost factor to account for // time locks. weight int64 + + // nextHop is the edge this route comes from. + nextHop *channeldb.ChannelEdgePolicy } // distanceHeap is a min-distance heap that's used within our path finding // algorithm to keep track of the "closest" node to our source node. type distanceHeap struct { - nodes []nodeWithDist + nodes []*nodeWithDist // pubkeyIndices maps public keys of nodes to their respective index in // the heap. This is used as a way to avoid db lookups by using heap.Fix @@ -53,7 +57,7 @@ type distanceHeap struct { func newDistanceHeap(numNodes int) distanceHeap { distHeap := distanceHeap{ pubkeyIndices: make(map[route.Vertex]int, numNodes), - nodes: make([]nodeWithDist, 0, numNodes), + nodes: make([]*nodeWithDist, 0, numNodes), } return distHeap @@ -85,7 +89,7 @@ func (d *distanceHeap) Swap(i, j int) { // // NOTE: This is part of the heap.Interface implementation. func (d *distanceHeap) Push(x interface{}) { - n := x.(nodeWithDist) + n := x.(*nodeWithDist) d.nodes = append(d.nodes, n) d.pubkeyIndices[n.node] = len(d.nodes) - 1 } @@ -97,6 +101,7 @@ func (d *distanceHeap) Push(x interface{}) { func (d *distanceHeap) Pop() interface{} { n := len(d.nodes) x := d.nodes[n-1] + d.nodes[n-1] = nil d.nodes = d.nodes[0 : n-1] delete(d.pubkeyIndices, x.node) return x @@ -107,7 +112,7 @@ func (d *distanceHeap) Pop() interface{} { // modify its position and reorder the heap. If the vertex does not already // exist in the heap, then it is pushed onto the heap. Otherwise, we will end // up performing more db lookups on the same node in the pathfinding algorithm. -func (d *distanceHeap) PushOrFix(dist nodeWithDist) { +func (d *distanceHeap) PushOrFix(dist *nodeWithDist) { index, ok := d.pubkeyIndices[dist.node] if !ok { heap.Push(d, dist) diff --git a/routing/heap_test.go b/routing/heap_test.go index 178bd9f1..659653f7 100644 --- a/routing/heap_test.go +++ b/routing/heap_test.go @@ -24,12 +24,12 @@ func TestHeapOrdering(t *testing.T) { // Create 100 random entries adding them to the heap created above, but // also a list that we'll sort with the entries. const numEntries = 100 - sortedEntries := make([]nodeWithDist, 0, numEntries) + sortedEntries := make([]*nodeWithDist, 0, numEntries) for i := 0; i < numEntries; i++ { var pubKey [33]byte prand.Read(pubKey[:]) - entry := nodeWithDist{ + entry := &nodeWithDist{ node: route.Vertex(pubKey), dist: prand.Int63(), } @@ -55,9 +55,9 @@ func TestHeapOrdering(t *testing.T) { // One by one, pop of all the entries from the heap, they should come // out in sorted order. - var poppedEntries []nodeWithDist + var poppedEntries []*nodeWithDist for nodeHeap.Len() != 0 { - e := heap.Pop(&nodeHeap).(nodeWithDist) + e := heap.Pop(&nodeHeap).(*nodeWithDist) poppedEntries = append(poppedEntries, e) } diff --git a/routing/pathfind.go b/routing/pathfind.go index 8a67ccf1..4fa4d15f 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -355,12 +355,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, nodeHeap := newDistanceHeap(estimatedNodeCount) // Holds the current best distance for a given node. - distance := make(map[route.Vertex]nodeWithDist, estimatedNodeCount) - - // We'll use this map as a series of "next" hop pointers. So to get - // from `Vertex` to the target node, we'll take the edge that it's - // mapped to within `next`. - next := make(map[route.Vertex]*channeldb.ChannelEdgePolicy, estimatedNodeCount) + distance := make(map[route.Vertex]*nodeWithDist, estimatedNodeCount) additionalEdgesWithSrc := make(map[route.Vertex][]*edgePolicyWithSource) for vertex, outgoingEdgePolicies := range g.additionalEdges { @@ -386,7 +381,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, // is the starting point of the graph traversal. We are searching // backwards to get the fees first time right and correctly match // channel bandwidth. - distance[target] = nodeWithDist{ + distance[target] = &nodeWithDist{ dist: 0, weight: 0, node: target, @@ -552,18 +547,17 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, // better than the current best known distance to this node. // The new better distance is recorded, and also our "next hop" // map is populated with this edge. - withDist := nodeWithDist{ + withDist := &nodeWithDist{ dist: tempDist, weight: tempWeight, node: fromVertex, amountToReceive: amountToReceive, incomingCltv: incomingCltv, probability: probability, + nextHop: edge, } distance[fromVertex] = withDist - next[fromVertex] = edge - // Either push withDist onto the heap if the node // represented by fromVertex is not already on the heap OR adjust // its position within the heap via heap.Fix. @@ -582,7 +576,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, // Fetch the node within the smallest distance from our source // from the heap. - partialPath := heap.Pop(&nodeHeap).(nodeWithDist) + partialPath := heap.Pop(&nodeHeap).(*nodeWithDist) pivot := partialPath.node // If we've reached our source (or we don't have any incoming @@ -632,7 +626,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, // Check if this candidate node is better than what we // already have. - processEdge(route.Vertex(chanSource), edgeBandwidth, inEdge, pivot) + processEdge(chanSource, edgeBandwidth, inEdge, pivot) return nil } @@ -656,26 +650,24 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, } } - // If the source node isn't found in the next hop map, then a path - // doesn't exist, so we terminate in an error. - if _, ok := next[source]; !ok { - return nil, newErrf(ErrNoPathFound, "unable to find a path to "+ - "destination") - } - - // Use the nextHop map to unravel the forward path from source to + // Use the distance map to unravel the forward path from source to // target. var pathEdges []*channeldb.ChannelEdgePolicy currentNode := source for currentNode != target { // TODO(roasbeef): assumes no cycles // Determine the next hop forward using the next map. - nextNode := next[currentNode] + currentNodeWithDist, ok := distance[currentNode] + if !ok { + // If the node doesnt have a next hop it means we didn't find a path. + return nil, newErrf(ErrNoPathFound, "unable to find a "+ + "path to destination") + } // Add the next hop to the list of path edges. - pathEdges = append(pathEdges, nextNode) + pathEdges = append(pathEdges, currentNodeWithDist.nextHop) // Advance current node. - currentNode = route.Vertex(nextNode.Node.PubKeyBytes) + currentNode = currentNodeWithDist.nextHop.Node.PubKeyBytes } // The route is invalid if it spans more than 20 hops. The current