routing: use absolute final expiry in pathfinding
This commit is contained in:
parent
e546a2c42b
commit
72a6383975
@ -24,9 +24,10 @@ type nodeWithDist struct {
|
|||||||
// amount that includes also the fees for subsequent hops.
|
// amount that includes also the fees for subsequent hops.
|
||||||
amountToReceive lnwire.MilliSatoshi
|
amountToReceive lnwire.MilliSatoshi
|
||||||
|
|
||||||
// incomingCltv is the expected cltv value for the incoming htlc of this
|
// incomingCltv is the expected absolute expiry height for the incoming
|
||||||
// node. This value does not include the final cltv.
|
// htlc of this node. This value should already include the final cltv
|
||||||
incomingCltv uint32
|
// delta.
|
||||||
|
incomingCltv int32
|
||||||
|
|
||||||
// probability is the probability that from this node onward the route
|
// probability is the probability that from this node onward the route
|
||||||
// is successful.
|
// is successful.
|
||||||
|
@ -47,7 +47,8 @@ const (
|
|||||||
// pathFinder defines the interface of a path finding algorithm.
|
// pathFinder defines the interface of a path finding algorithm.
|
||||||
type pathFinder = func(g *graphParams, r *RestrictParams,
|
type pathFinder = func(g *graphParams, r *RestrictParams,
|
||||||
cfg *PathFindingConfig, source, target route.Vertex,
|
cfg *PathFindingConfig, source, target route.Vertex,
|
||||||
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy, error)
|
amt lnwire.MilliSatoshi, finalHtlcExpiry int32) (
|
||||||
|
[]*channeldb.ChannelEdgePolicy, error)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultPaymentAttemptPenalty is the virtual cost in path finding weight
|
// DefaultPaymentAttemptPenalty is the virtual cost in path finding weight
|
||||||
@ -411,7 +412,7 @@ func getMaxOutgoingAmt(node route.Vertex, outgoingChan *uint64,
|
|||||||
// that need to be paid along the path and accurately check the amount
|
// that need to be paid along the path and accurately check the amount
|
||||||
// to forward at every node against the available bandwidth.
|
// to forward at every node against the available bandwidth.
|
||||||
func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
||||||
source, target route.Vertex, amt lnwire.MilliSatoshi) (
|
source, target route.Vertex, amt lnwire.MilliSatoshi, finalHtlcExpiry int32) (
|
||||||
[]*channeldb.ChannelEdgePolicy, error) {
|
[]*channeldb.ChannelEdgePolicy, error) {
|
||||||
|
|
||||||
// Pathfinding can be a significant portion of the total payment
|
// Pathfinding can be a significant portion of the total payment
|
||||||
@ -542,10 +543,14 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
|||||||
weight: 0,
|
weight: 0,
|
||||||
node: target,
|
node: target,
|
||||||
amountToReceive: amt,
|
amountToReceive: amt,
|
||||||
incomingCltv: 0,
|
incomingCltv: finalHtlcExpiry,
|
||||||
probability: 1,
|
probability: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the absolute cltv limit. Use uint64 to prevent an overflow
|
||||||
|
// if the cltv limit is MaxUint32.
|
||||||
|
absoluteCltvLimit := uint64(r.CltvLimit) + uint64(finalHtlcExpiry)
|
||||||
|
|
||||||
// processEdge is a helper closure that will be used to make sure edges
|
// processEdge is a helper closure that will be used to make sure edges
|
||||||
// satisfy our specific requirements.
|
// satisfy our specific requirements.
|
||||||
processEdge := func(fromVertex route.Vertex,
|
processEdge := func(fromVertex route.Vertex,
|
||||||
@ -590,11 +595,10 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
|||||||
timeLockDelta = edge.TimeLockDelta
|
timeLockDelta = edge.TimeLockDelta
|
||||||
}
|
}
|
||||||
|
|
||||||
incomingCltv := toNodeDist.incomingCltv +
|
incomingCltv := toNodeDist.incomingCltv + int32(timeLockDelta)
|
||||||
uint32(timeLockDelta)
|
|
||||||
|
|
||||||
// Check that we are within our CLTV limit.
|
// Check that we are within our CLTV limit.
|
||||||
if incomingCltv > r.CltvLimit {
|
if uint64(incomingCltv) > absoluteCltvLimit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,6 +823,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
|
|||||||
},
|
},
|
||||||
testPathFindingConfig,
|
testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt,
|
||||||
|
startingHeight+finalHopCLTV,
|
||||||
)
|
)
|
||||||
if test.expectFailureNoPath {
|
if test.expectFailureNoPath {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -1012,6 +1013,7 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
|
|||||||
},
|
},
|
||||||
r, testPathFindingConfig,
|
r, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
|
sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
|
||||||
|
0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1383,7 +1385,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("path should have been found")
|
t.Fatalf("path should have been found")
|
||||||
@ -1397,7 +1399,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, paymentAmt,
|
sourceNode.PubKeyBytes, target, paymentAmt, 0,
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("should not have been able to find path, supposed to be "+
|
t.Fatalf("should not have been able to find path, supposed to be "+
|
||||||
@ -1437,7 +1439,7 @@ func TestPathNotAvailable(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, unknownNode, 100,
|
sourceNode.PubKeyBytes, unknownNode, 100, 0,
|
||||||
)
|
)
|
||||||
if err != errNoPathFound {
|
if err != errNoPathFound {
|
||||||
t.Fatalf("path shouldn't have been found: %v", err)
|
t.Fatalf("path shouldn't have been found: %v", err)
|
||||||
@ -1495,7 +1497,7 @@ func TestDestTLVGraphFallback(t *testing.T) {
|
|||||||
graph: ctx.graphParams.graph,
|
graph: ctx.graphParams.graph,
|
||||||
},
|
},
|
||||||
r, testPathFindingConfig,
|
r, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, 100,
|
sourceNode.PubKeyBytes, target, 100, 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1604,7 +1606,7 @@ func TestMissingFeatureDep(t *testing.T) {
|
|||||||
graph: ctx.graphParams.graph,
|
graph: ctx.graphParams.graph,
|
||||||
},
|
},
|
||||||
r, testPathFindingConfig,
|
r, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, 100,
|
sourceNode.PubKeyBytes, target, 100, 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1682,7 +1684,7 @@ func TestDestPaymentAddr(t *testing.T) {
|
|||||||
graph: ctx.graphParams.graph,
|
graph: ctx.graphParams.graph,
|
||||||
},
|
},
|
||||||
r, testPathFindingConfig,
|
r, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, 100,
|
sourceNode.PubKeyBytes, target, 100, 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1743,7 +1745,7 @@ func TestPathInsufficientCapacity(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != errNoPathFound {
|
if err != errNoPathFound {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
@ -1776,7 +1778,7 @@ func TestRouteFailMinHTLC(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != errNoPathFound {
|
if err != errNoPathFound {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
@ -1875,7 +1877,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
@ -1903,7 +1905,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
@ -1928,7 +1930,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != errNoPathFound {
|
if err != errNoPathFound {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
@ -1962,7 +1964,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
graph: graph.graph,
|
graph: graph.graph,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
@ -1986,7 +1988,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
bandwidthHints: bandwidths,
|
bandwidthHints: bandwidths,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != errNoPathFound {
|
if err != errNoPathFound {
|
||||||
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
t.Fatalf("graph shouldn't be able to support payment: %v", err)
|
||||||
@ -2004,7 +2006,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
bandwidthHints: bandwidths,
|
bandwidthHints: bandwidths,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
@ -2035,7 +2037,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
|
|||||||
bandwidthHints: bandwidths,
|
bandwidthHints: bandwidths,
|
||||||
},
|
},
|
||||||
noRestrictions, testPathFindingConfig,
|
noRestrictions, testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, payAmt,
|
sourceNode.PubKeyBytes, target, payAmt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
@ -2872,7 +2874,7 @@ func (c *pathFindingTestContext) findPath(target route.Vertex,
|
|||||||
|
|
||||||
return findPath(
|
return findPath(
|
||||||
&c.graphParams, &c.restrictParams, &c.pathFindingConfig,
|
&c.graphParams, &c.restrictParams, &c.pathFindingConfig,
|
||||||
c.source, target, amt,
|
c.source, target, amt, 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +113,8 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalHtlcExpiry := int32(height) + int32(finalCltvDelta)
|
||||||
|
|
||||||
path, err := p.pathFinder(
|
path, err := p.pathFinder(
|
||||||
&graphParams{
|
&graphParams{
|
||||||
graph: ss.Graph,
|
graph: ss.Graph,
|
||||||
@ -121,7 +123,7 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
|
|||||||
},
|
},
|
||||||
restrictions, &ss.PathFindingConfig,
|
restrictions, &ss.PathFindingConfig,
|
||||||
ss.SelfNode.PubKeyBytes, payment.Target,
|
ss.SelfNode.PubKeyBytes, payment.Target,
|
||||||
payment.Amount,
|
payment.Amount, finalHtlcExpiry,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -15,8 +15,8 @@ func TestRequestRoute(t *testing.T) {
|
|||||||
|
|
||||||
findPath := func(g *graphParams, r *RestrictParams,
|
findPath := func(g *graphParams, r *RestrictParams,
|
||||||
cfg *PathFindingConfig, source, target route.Vertex,
|
cfg *PathFindingConfig, source, target route.Vertex,
|
||||||
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy,
|
amt lnwire.MilliSatoshi, finalHtlcExpiry int32) (
|
||||||
error) {
|
[]*channeldb.ChannelEdgePolicy, error) {
|
||||||
|
|
||||||
// We expect find path to receive a cltv limit excluding the
|
// We expect find path to receive a cltv limit excluding the
|
||||||
// final cltv delta (including the block padding).
|
// final cltv delta (including the block padding).
|
||||||
|
@ -1431,27 +1431,29 @@ func (r *ChannelRouter) FindRoute(source, target route.Vertex,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll fetch the current block height so we can properly calculate the
|
||||||
|
// required HTLC time locks within the route.
|
||||||
|
_, currentHeight, err := r.cfg.Chain.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we know the destination is reachable within the graph, we'll
|
// Now that we know the destination is reachable within the graph, we'll
|
||||||
// execute our path finding algorithm.
|
// execute our path finding algorithm.
|
||||||
|
finalHtlcExpiry := currentHeight + int32(finalCLTVDelta)
|
||||||
|
|
||||||
path, err := findPath(
|
path, err := findPath(
|
||||||
&graphParams{
|
&graphParams{
|
||||||
graph: r.cfg.Graph,
|
graph: r.cfg.Graph,
|
||||||
bandwidthHints: bandwidthHints,
|
bandwidthHints: bandwidthHints,
|
||||||
},
|
},
|
||||||
restrictions, &r.cfg.PathFindingConfig,
|
restrictions, &r.cfg.PathFindingConfig,
|
||||||
source, target, amt,
|
source, target, amt, finalHtlcExpiry,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll fetch the current block height so we can properly calculate the
|
|
||||||
// required HTLC time locks within the route.
|
|
||||||
_, currentHeight, err := r.cfg.Chain.GetBestBlock()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the route with absolute time lock values.
|
// Create the route with absolute time lock values.
|
||||||
route, err := newRoute(
|
route, err := newRoute(
|
||||||
source, path, uint32(currentHeight),
|
source, path, uint32(currentHeight),
|
||||||
|
@ -2174,7 +2174,7 @@ func TestFindPathFeeWeighting(t *testing.T) {
|
|||||||
},
|
},
|
||||||
noRestrictions,
|
noRestrictions,
|
||||||
testPathFindingConfig,
|
testPathFindingConfig,
|
||||||
sourceNode.PubKeyBytes, target, amt,
|
sourceNode.PubKeyBytes, target, amt, 0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to find path: %v", err)
|
t.Fatalf("unable to find path: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user