routing: use absolute final expiry in pathfinding

This commit is contained in:
Joost Jager 2019-12-17 11:55:03 +01:00
parent e546a2c42b
commit 72a6383975
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
7 changed files with 48 additions and 37 deletions

@ -24,9 +24,10 @@ type nodeWithDist struct {
// amount that includes also the fees for subsequent hops.
amountToReceive lnwire.MilliSatoshi
// incomingCltv is the expected cltv value for the incoming htlc of this
// node. This value does not include the final cltv.
incomingCltv uint32
// 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
// probability is the probability that from this node onward the route
// is successful.

@ -47,7 +47,8 @@ const (
// pathFinder defines the interface of a path finding algorithm.
type pathFinder = func(g *graphParams, r *RestrictParams,
cfg *PathFindingConfig, source, target route.Vertex,
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy, error)
amt lnwire.MilliSatoshi, finalHtlcExpiry int32) (
[]*channeldb.ChannelEdgePolicy, error)
var (
// 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
// to forward at every node against the available bandwidth.
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) {
// Pathfinding can be a significant portion of the total payment
@ -542,10 +543,14 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
weight: 0,
node: target,
amountToReceive: amt,
incomingCltv: 0,
incomingCltv: finalHtlcExpiry,
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
// satisfy our specific requirements.
processEdge := func(fromVertex route.Vertex,
@ -590,11 +595,10 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
timeLockDelta = edge.TimeLockDelta
}
incomingCltv := toNodeDist.incomingCltv +
uint32(timeLockDelta)
incomingCltv := toNodeDist.incomingCltv + int32(timeLockDelta)
// Check that we are within our CLTV limit.
if incomingCltv > r.CltvLimit {
if uint64(incomingCltv) > absoluteCltvLimit {
return
}

@ -823,6 +823,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
},
testPathFindingConfig,
sourceNode.PubKeyBytes, target, paymentAmt,
startingHeight+finalHopCLTV,
)
if test.expectFailureNoPath {
if err == nil {
@ -1012,6 +1013,7 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
},
r, testPathFindingConfig,
sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
0,
)
}
@ -1383,7 +1385,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, paymentAmt,
sourceNode.PubKeyBytes, target, paymentAmt, 0,
)
if err != nil {
t.Fatalf("path should have been found")
@ -1397,7 +1399,7 @@ func TestNewRoutePathTooLong(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, paymentAmt,
sourceNode.PubKeyBytes, target, paymentAmt, 0,
)
if err == nil {
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,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, unknownNode, 100,
sourceNode.PubKeyBytes, unknownNode, 100, 0,
)
if err != errNoPathFound {
t.Fatalf("path shouldn't have been found: %v", err)
@ -1495,7 +1497,7 @@ func TestDestTLVGraphFallback(t *testing.T) {
graph: ctx.graphParams.graph,
},
r, testPathFindingConfig,
sourceNode.PubKeyBytes, target, 100,
sourceNode.PubKeyBytes, target, 100, 0,
)
}
@ -1604,7 +1606,7 @@ func TestMissingFeatureDep(t *testing.T) {
graph: ctx.graphParams.graph,
},
r, testPathFindingConfig,
sourceNode.PubKeyBytes, target, 100,
sourceNode.PubKeyBytes, target, 100, 0,
)
}
@ -1682,7 +1684,7 @@ func TestDestPaymentAddr(t *testing.T) {
graph: ctx.graphParams.graph,
},
r, testPathFindingConfig,
sourceNode.PubKeyBytes, target, 100,
sourceNode.PubKeyBytes, target, 100, 0,
)
}
@ -1743,7 +1745,7 @@ func TestPathInsufficientCapacity(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != errNoPathFound {
t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1776,7 +1778,7 @@ func TestRouteFailMinHTLC(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != errNoPathFound {
t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1875,7 +1877,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != nil {
t.Fatalf("unable to find path: %v", err)
@ -1903,7 +1905,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != nil {
t.Fatalf("unable to find path: %v", err)
@ -1928,7 +1930,7 @@ func TestRouteFailDisabledEdge(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != errNoPathFound {
t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1962,7 +1964,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
graph: graph.graph,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != nil {
t.Fatalf("unable to find path: %v", err)
@ -1986,7 +1988,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
bandwidthHints: bandwidths,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != errNoPathFound {
t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -2004,7 +2006,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
bandwidthHints: bandwidths,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != nil {
t.Fatalf("unable to find path: %v", err)
@ -2035,7 +2037,7 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
bandwidthHints: bandwidths,
},
noRestrictions, testPathFindingConfig,
sourceNode.PubKeyBytes, target, payAmt,
sourceNode.PubKeyBytes, target, payAmt, 0,
)
if err != nil {
t.Fatalf("unable to find path: %v", err)
@ -2872,7 +2874,7 @@ func (c *pathFindingTestContext) findPath(target route.Vertex,
return findPath(
&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
}
finalHtlcExpiry := int32(height) + int32(finalCltvDelta)
path, err := p.pathFinder(
&graphParams{
graph: ss.Graph,
@ -121,7 +123,7 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
},
restrictions, &ss.PathFindingConfig,
ss.SelfNode.PubKeyBytes, payment.Target,
payment.Amount,
payment.Amount, finalHtlcExpiry,
)
if err != nil {
return nil, err

@ -15,8 +15,8 @@ func TestRequestRoute(t *testing.T) {
findPath := func(g *graphParams, r *RestrictParams,
cfg *PathFindingConfig, source, target route.Vertex,
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy,
error) {
amt lnwire.MilliSatoshi, finalHtlcExpiry int32) (
[]*channeldb.ChannelEdgePolicy, error) {
// We expect find path to receive a cltv limit excluding the
// final cltv delta (including the block padding).

@ -1431,27 +1431,29 @@ func (r *ChannelRouter) FindRoute(source, target route.Vertex,
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
// execute our path finding algorithm.
finalHtlcExpiry := currentHeight + int32(finalCLTVDelta)
path, err := findPath(
&graphParams{
graph: r.cfg.Graph,
bandwidthHints: bandwidthHints,
},
restrictions, &r.cfg.PathFindingConfig,
source, target, amt,
source, target, amt, finalHtlcExpiry,
)
if err != nil {
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.
route, err := newRoute(
source, path, uint32(currentHeight),

@ -2174,7 +2174,7 @@ func TestFindPathFeeWeighting(t *testing.T) {
},
noRestrictions,
testPathFindingConfig,
sourceNode.PubKeyBytes, target, amt,
sourceNode.PubKeyBytes, target, amt, 0,
)
if err != nil {
t.Fatalf("unable to find path: %v", err)