Skip to content

Commit cd3da40

Browse files
committed
routing: dont include final hop cltv in blinded path
Only include the final hop's cltv delta in the total timelock calculation if the route does not include a blinded path. This is because in a blinded path, the final hops final cltv delta will be included in the blinded path's accumlated cltv delta value. With this commit, we remove the responsibility of remembering not to set the `finalHop.cltvDelta` from the caller of `newRoute`. The relevant test is updated accordingly.
1 parent 93f8951 commit cd3da40

File tree

4 files changed

+52
-14
lines changed

4 files changed

+52
-14
lines changed

cmd/lncli/cmd_payments.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,8 +1099,13 @@ var queryRoutesCommand = cli.Command{
10991099
},
11001100
cli.Int64Flag{
11011101
Name: "final_cltv_delta",
1102-
Usage: "(optional) number of blocks the last hop has to reveal " +
1103-
"the preimage",
1102+
Usage: "(optional) number of blocks the last hop has " +
1103+
"to reveal the preimage. Note that this " +
1104+
"should not be set in the case where the " +
1105+
"path includes a blinded path since in " +
1106+
"that case, the receiver will already have " +
1107+
"accounted for this value in the " +
1108+
"blinded_cltv value",
11041109
},
11051110
cli.BoolFlag{
11061111
Name: "use_mc",
@@ -1238,6 +1243,13 @@ func parseBlindedPaymentParameters(ctx *cli.Context) (
12381243
return nil, nil
12391244
}
12401245

1246+
// If a blinded path has been provided, then the final_cltv_delta flag
1247+
// should not be provided since this value will be ignored.
1248+
if ctx.IsSet("final_cltv_delta") {
1249+
return nil, fmt.Errorf("`final_cltv_delta` should not be " +
1250+
"provided if a blinded path is provided")
1251+
}
1252+
12411253
// If any one of our blinding related flags is set, we expect the
12421254
// full set to be set and we'll error out accordingly.
12431255
introNode, err := route.NewVertexFromStr(

routing/pathfind.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,17 @@ type edgePolicyWithSource struct {
9696
// such as amounts and cltvs, as well as more complex features like destination
9797
// custom records and payment address.
9898
type finalHopParams struct {
99-
amt lnwire.MilliSatoshi
100-
totalAmt lnwire.MilliSatoshi
101-
cltvDelta uint16
99+
amt lnwire.MilliSatoshi
100+
totalAmt lnwire.MilliSatoshi
101+
102+
// cltvDelta is the final hop's minimum CLTV expiry delta.
103+
//
104+
// NOTE that in the case of paying to a blinded path, this value will
105+
// be set to a duplicate of the blinded path's accumulated CLTV value.
106+
// We would then only need to use this value in the case where the
107+
// introduction node of the path is also the destination node.
108+
cltvDelta uint16
109+
102110
records record.CustomSet
103111
paymentAddr *[32]byte
104112

@@ -190,10 +198,21 @@ func newRoute(sourceVertex route.Vertex,
190198
// reporting through RPC. Set to zero for the final hop.
191199
fee = 0
192200

193-
// As this is the last hop, we'll use the specified
194-
// final CLTV delta value instead of the value from the
195-
// last link in the route.
196-
totalTimeLock += uint32(finalHop.cltvDelta)
201+
// Only include the final hop CLTV delta in the total
202+
// time lock value if this is not a route to a blinded
203+
// path. For blinded paths, the total time-lock from the
204+
// whole path will be deduced from the introduction
205+
// node's CLTV delta. The exception is for the case
206+
// where the final hop is the blinded path introduction
207+
// node.
208+
if blindedPath == nil ||
209+
len(blindedPath.BlindedHops) == 1 {
210+
211+
// As this is the last hop, we'll use the
212+
// specified final CLTV delta value instead of
213+
// the value from the last link in the route.
214+
totalTimeLock += uint32(finalHop.cltvDelta)
215+
}
197216
outgoingTimeLock = totalTimeLock
198217

199218
// Attach any custom records to the final hop.

routing/pathfind_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3322,16 +3322,19 @@ func TestBlindedRouteConstruction(t *testing.T) {
33223322
ToNodeFeatures: tlvFeatures,
33233323
}
33243324

3325-
// Create final hop parameters for payment amount = 110. Note
3326-
// that final cltv delta is not set because blinded paths
3327-
// include this final delta in their aggregate delta. A
3328-
// sender-set delta may be added to account for block arrival
3329-
// during payment, but we do not set it in this test.
3325+
// Create final hop parameters for payment amount = 110.
33303326
totalAmt lnwire.MilliSatoshi = 110
33313327
finalHopParams = finalHopParams{
33323328
amt: totalAmt,
33333329
totalAmt: totalAmt,
33343330
metadata: metadata,
3331+
3332+
// We set a CLTV delta here just to test that this will
3333+
// be ignored by newRoute since this is a blinded path
3334+
// where the accumulated CLTV delta for the route
3335+
// communicated in the blinded path should be assumed to
3336+
// include the CLTV delta of the final hop.
3337+
cltvDelta: MaxCLTVDelta,
33353338
}
33363339
)
33373340

zpay32/invoice.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ type Invoice struct {
156156
// This field is un-exported and can only be read by the
157157
// MinFinalCLTVExpiry() method. By forcing callers to read via this
158158
// method, we can easily enforce the default if not specified.
159+
//
160+
// NOTE: this field is ignored in the case that the invoice contains
161+
// blinded paths since then the final minimum cltv expiry delta is
162+
// expected to be included in the route's accumulated CLTV delta value.
159163
minFinalCLTVExpiry *uint64
160164

161165
// Description is a short description of the purpose of this invoice.

0 commit comments

Comments
 (0)