2017-03-19 22:06:08 +01:00
|
|
|
package routing
|
|
|
|
|
2018-06-04 22:10:05 +02:00
|
|
|
import (
|
2019-06-19 04:26:09 +02:00
|
|
|
"container/heap"
|
|
|
|
|
2018-06-04 22:10:05 +02:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2019-06-19 04:19:37 +02:00
|
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
2018-06-04 22:10:05 +02:00
|
|
|
)
|
2017-03-19 22:06:08 +01:00
|
|
|
|
|
|
|
// nodeWithDist is a helper struct that couples the distance from the current
|
|
|
|
// source to a node with a pointer to the node itself.
|
|
|
|
type nodeWithDist struct {
|
|
|
|
// dist is the distance to this node from the source node in our
|
|
|
|
// current context.
|
2018-02-13 01:27:30 +01:00
|
|
|
dist int64
|
2017-03-19 22:06:08 +01:00
|
|
|
|
2019-06-19 04:19:37 +02:00
|
|
|
// node is the vertex itself. This can be used to explore all the
|
|
|
|
// outgoing edges (channels) emanating from a node.
|
|
|
|
node route.Vertex
|
2018-06-04 22:10:05 +02:00
|
|
|
|
2022-07-05 15:01:18 +02:00
|
|
|
// netAmountReceived is the amount that should be received by this node.
|
2018-06-04 22:10:05 +02:00
|
|
|
// Either as final payment to the final node or as an intermediate
|
2022-07-05 15:01:18 +02:00
|
|
|
// amount that includes also the fees for subsequent hops. This node's
|
|
|
|
// inbound fee is already subtracted from the htlc amount - if
|
|
|
|
// applicable.
|
|
|
|
netAmountReceived lnwire.MilliSatoshi
|
|
|
|
|
|
|
|
// outboundFee is the fee that this node charges on the outgoing
|
|
|
|
// channel.
|
|
|
|
outboundFee lnwire.MilliSatoshi
|
2018-06-04 22:10:05 +02:00
|
|
|
|
2019-12-17 11:55:03 +01:00
|
|
|
// incomingCltv is the expected absolute expiry height for the incoming
|
|
|
|
// htlc of this node. This value should already include the final cltv
|
|
|
|
// delta.
|
|
|
|
incomingCltv int32
|
2019-02-13 10:08:53 +01:00
|
|
|
|
2019-03-19 11:45:10 +01:00
|
|
|
// probability is the probability that from this node onward the route
|
|
|
|
// is successful.
|
|
|
|
probability float64
|
|
|
|
|
|
|
|
// weight is the cost of the route from this node to the destination.
|
|
|
|
// Includes the routing fees and a virtual cost factor to account for
|
|
|
|
// time locks.
|
|
|
|
weight int64
|
2019-08-25 03:52:13 +02:00
|
|
|
|
|
|
|
// nextHop is the edge this route comes from.
|
2022-09-03 13:59:10 +02:00
|
|
|
nextHop *unifiedEdge
|
2019-12-16 14:22:42 +01:00
|
|
|
|
|
|
|
// routingInfoSize is the total size requirement for the payloads field
|
|
|
|
// in the onion packet from this hop towards the final destination.
|
|
|
|
routingInfoSize uint64
|
2017-03-19 22:06:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2019-08-25 03:52:13 +02:00
|
|
|
nodes []*nodeWithDist
|
2019-06-19 04:26:09 +02:00
|
|
|
|
|
|
|
// 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
|
|
|
|
// instead of having duplicate entries on the heap.
|
|
|
|
pubkeyIndices map[route.Vertex]int
|
|
|
|
}
|
|
|
|
|
|
|
|
// newDistanceHeap initializes a new distance heap. This is required because
|
|
|
|
// we must initialize the pubkeyIndices map for path-finding optimizations.
|
2019-08-23 17:27:02 +02:00
|
|
|
func newDistanceHeap(numNodes int) distanceHeap {
|
2019-06-19 04:26:09 +02:00
|
|
|
distHeap := distanceHeap{
|
2019-08-23 17:27:02 +02:00
|
|
|
pubkeyIndices: make(map[route.Vertex]int, numNodes),
|
2019-08-25 03:52:13 +02:00
|
|
|
nodes: make([]*nodeWithDist, 0, numNodes),
|
2019-06-19 04:26:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return distHeap
|
2017-03-19 22:06:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Len returns the number of nodes in the priority queue.
|
|
|
|
//
|
|
|
|
// NOTE: This is part of the heap.Interface implementation.
|
|
|
|
func (d *distanceHeap) Len() int { return len(d.nodes) }
|
|
|
|
|
|
|
|
// Less returns whether the item in the priority queue with index i should sort
|
|
|
|
// before the item with index j.
|
|
|
|
//
|
|
|
|
// NOTE: This is part of the heap.Interface implementation.
|
|
|
|
func (d *distanceHeap) Less(i, j int) bool {
|
2019-12-01 14:55:01 +01:00
|
|
|
// If distances are equal, tie break on probability.
|
|
|
|
if d.nodes[i].dist == d.nodes[j].dist {
|
|
|
|
return d.nodes[i].probability > d.nodes[j].probability
|
|
|
|
}
|
|
|
|
|
2017-03-19 22:06:08 +01:00
|
|
|
return d.nodes[i].dist < d.nodes[j].dist
|
|
|
|
}
|
|
|
|
|
|
|
|
// Swap swaps the nodes at the passed indices in the priority queue.
|
|
|
|
//
|
|
|
|
// NOTE: This is part of the heap.Interface implementation.
|
|
|
|
func (d *distanceHeap) Swap(i, j int) {
|
|
|
|
d.nodes[i], d.nodes[j] = d.nodes[j], d.nodes[i]
|
2019-06-19 04:26:09 +02:00
|
|
|
d.pubkeyIndices[d.nodes[i].node] = i
|
|
|
|
d.pubkeyIndices[d.nodes[j].node] = j
|
2017-03-19 22:06:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Push pushes the passed item onto the priority queue.
|
|
|
|
//
|
|
|
|
// NOTE: This is part of the heap.Interface implementation.
|
|
|
|
func (d *distanceHeap) Push(x interface{}) {
|
2019-08-25 03:52:13 +02:00
|
|
|
n := x.(*nodeWithDist)
|
2019-06-19 04:26:09 +02:00
|
|
|
d.nodes = append(d.nodes, n)
|
|
|
|
d.pubkeyIndices[n.node] = len(d.nodes) - 1
|
2017-03-19 22:06:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pop removes the highest priority item (according to Less) from the priority
|
|
|
|
// queue and returns it.
|
|
|
|
//
|
|
|
|
// NOTE: This is part of the heap.Interface implementation.
|
|
|
|
func (d *distanceHeap) Pop() interface{} {
|
|
|
|
n := len(d.nodes)
|
|
|
|
x := d.nodes[n-1]
|
2019-08-25 03:52:13 +02:00
|
|
|
d.nodes[n-1] = nil
|
2017-03-19 22:06:08 +01:00
|
|
|
d.nodes = d.nodes[0 : n-1]
|
2019-06-19 04:26:09 +02:00
|
|
|
delete(d.pubkeyIndices, x.node)
|
2017-03-19 22:06:08 +01:00
|
|
|
return x
|
|
|
|
}
|
2017-03-21 02:09:01 +01:00
|
|
|
|
2019-06-19 04:26:09 +02:00
|
|
|
// PushOrFix attempts to adjust the position of a given node in the heap.
|
|
|
|
// If the vertex already exists in the heap, then we must call heap.Fix to
|
|
|
|
// 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.
|
2019-08-25 03:52:13 +02:00
|
|
|
func (d *distanceHeap) PushOrFix(dist *nodeWithDist) {
|
2019-06-19 04:26:09 +02:00
|
|
|
index, ok := d.pubkeyIndices[dist.node]
|
|
|
|
if !ok {
|
|
|
|
heap.Push(d, dist)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change the value at the specified index.
|
|
|
|
d.nodes[index] = dist
|
|
|
|
|
|
|
|
// Call heap.Fix to reorder the heap.
|
|
|
|
heap.Fix(d, index)
|
|
|
|
}
|