Skip to content

Commit 3cec72a

Browse files
committed
routing: improve lasthoppaylaod size calculation
Fixes a bug and makes the function more robust. Before we would always return the encrypted data size of last hop of the last path. Now we return the greatest last hop payload not always the one of the last path.
1 parent e47024b commit 3cec72a

File tree

3 files changed

+81
-33
lines changed

3 files changed

+81
-33
lines changed

routing/blinding.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,33 @@ func (s *BlindedPaymentPathSet) FinalCLTVDelta() uint16 {
235235
// LargestLastHopPayloadPath returns the BlindedPayment in the set that has the
236236
// largest last-hop payload. This is to be used for onion size estimation in
237237
// path finding.
238-
func (s *BlindedPaymentPathSet) LargestLastHopPayloadPath() *BlindedPayment {
238+
func (s *BlindedPaymentPathSet) LargestLastHopPayloadPath() (*BlindedPayment,
239+
error) {
240+
239241
var (
240242
largestPath *BlindedPayment
241243
currentMax int
242244
)
245+
246+
if len(s.paths) == 0 {
247+
return nil, fmt.Errorf("no blinded paths in the set")
248+
}
249+
250+
// We set the largest path to make sure we always return a path even
251+
// if the cipher text is empty.
252+
largestPath = s.paths[0]
253+
243254
for _, path := range s.paths {
244255
numHops := len(path.BlindedPath.BlindedHops)
245256
lastHop := path.BlindedPath.BlindedHops[numHops-1]
246257

247258
if len(lastHop.CipherText) > currentMax {
248259
largestPath = path
260+
currentMax = len(lastHop.CipherText)
249261
}
250262
}
251263

252-
return largestPath
264+
return largestPath, nil
253265
}
254266

255267
// ToRouteHints converts the blinded path payment set into a RouteHints map so

routing/pathfind.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,10 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
700700

701701
// The payload size of the final hop differ from intermediate hops
702702
// and depends on whether the destination is blinded or not.
703-
lastHopPayloadSize := lastHopPayloadSize(r, finalHtlcExpiry, amt)
703+
lastHopPayloadSize, err := lastHopPayloadSize(r, finalHtlcExpiry, amt)
704+
if err != nil {
705+
return nil, 0, err
706+
}
704707

705708
// We can't always assume that the end destination is publicly
706709
// advertised to the network so we'll manually include the target node.
@@ -1433,11 +1436,15 @@ func getProbabilityBasedDist(weight int64, probability float64,
14331436
// It depends on the tlv types which are present and also whether the hop is
14341437
// part of a blinded route or not.
14351438
func lastHopPayloadSize(r *RestrictParams, finalHtlcExpiry int32,
1436-
amount lnwire.MilliSatoshi) uint64 {
1439+
amount lnwire.MilliSatoshi) (uint64, error) {
14371440

14381441
if r.BlindedPaymentPathSet != nil {
1439-
paymentPath := r.BlindedPaymentPathSet.
1442+
paymentPath, err := r.BlindedPaymentPathSet.
14401443
LargestLastHopPayloadPath()
1444+
if err != nil {
1445+
return 0, err
1446+
}
1447+
14411448
blindedPath := paymentPath.BlindedPath.BlindedHops
14421449
blindedPoint := paymentPath.BlindedPath.BlindingPoint
14431450

@@ -1452,7 +1459,7 @@ func lastHopPayloadSize(r *RestrictParams, finalHtlcExpiry int32,
14521459
}
14531460

14541461
// The final hop does not have a short chanID set.
1455-
return finalHop.PayloadSize(0)
1462+
return finalHop.PayloadSize(0), nil
14561463
}
14571464

14581465
var mpp *record.MPP
@@ -1478,7 +1485,7 @@ func lastHopPayloadSize(r *RestrictParams, finalHtlcExpiry int32,
14781485
}
14791486

14801487
// The final hop does not have a short chanID set.
1481-
return finalHop.PayloadSize(0)
1488+
return finalHop.PayloadSize(0), nil
14821489
}
14831490

14841491
// overflowSafeAdd adds two MilliSatoshi values and returns the result. If an

routing/pathfind_test.go

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3413,32 +3413,48 @@ func TestLastHopPayloadSize(t *testing.T) {
34133413
customRecords = map[uint64][]byte{
34143414
record.CustomTypeStart: {1, 2, 3},
34153415
}
3416-
sizeEncryptedData = 100
3417-
encrypedData = bytes.Repeat(
3418-
[]byte{1}, sizeEncryptedData,
3416+
3417+
encrypedDataSmall = bytes.Repeat(
3418+
[]byte{1}, 5,
3419+
)
3420+
encrypedDataLarge = bytes.Repeat(
3421+
[]byte{1}, 100,
34193422
)
3420-
_, blindedPoint = btcec.PrivKeyFromBytes([]byte{5})
3421-
paymentAddr = &[32]byte{1}
3422-
ampOptions = &AMPOptions{}
3423-
amtToForward = lnwire.MilliSatoshi(10000)
3424-
finalHopExpiry int32 = 144
3423+
_, blindedPoint = btcec.PrivKeyFromBytes([]byte{5})
3424+
paymentAddr = &[32]byte{1}
3425+
ampOptions = &AMPOptions{}
3426+
amtToForward = lnwire.MilliSatoshi(10000)
3427+
emptyEncryptedData = []byte{}
3428+
finalHopExpiry int32 = 144
34253429

34263430
oneHopPath = &sphinx.BlindedPath{
34273431
BlindedHops: []*sphinx.BlindedHopInfo{
34283432
{
3429-
CipherText: encrypedData,
3433+
CipherText: emptyEncryptedData,
3434+
},
3435+
},
3436+
BlindingPoint: blindedPoint,
3437+
}
3438+
3439+
twoHopPathSmallHopSize = &sphinx.BlindedPath{
3440+
BlindedHops: []*sphinx.BlindedHopInfo{
3441+
{
3442+
CipherText: encrypedDataLarge,
3443+
},
3444+
{
3445+
CipherText: encrypedDataLarge,
34303446
},
34313447
},
34323448
BlindingPoint: blindedPoint,
34333449
}
34343450

3435-
twoHopPath = &sphinx.BlindedPath{
3451+
twoHopPathLargeHopSize = &sphinx.BlindedPath{
34363452
BlindedHops: []*sphinx.BlindedHopInfo{
34373453
{
3438-
CipherText: encrypedData,
3454+
CipherText: encrypedDataSmall,
34393455
},
34403456
{
3441-
CipherText: encrypedData,
3457+
CipherText: encrypedDataSmall,
34423458
},
34433459
},
34443460
BlindingPoint: blindedPoint,
@@ -3451,15 +3467,19 @@ func TestLastHopPayloadSize(t *testing.T) {
34513467
require.NoError(t, err)
34523468

34533469
twoHopBlindedPayment, err := NewBlindedPaymentPathSet(
3454-
[]*BlindedPayment{{BlindedPath: twoHopPath}},
3470+
[]*BlindedPayment{
3471+
{BlindedPath: twoHopPathLargeHopSize},
3472+
{BlindedPath: twoHopPathSmallHopSize},
3473+
},
34553474
)
34563475
require.NoError(t, err)
34573476

34583477
testCases := []struct {
3459-
name string
3460-
restrictions *RestrictParams
3461-
finalHopExpiry int32
3462-
amount lnwire.MilliSatoshi
3478+
name string
3479+
restrictions *RestrictParams
3480+
finalHopExpiry int32
3481+
amount lnwire.MilliSatoshi
3482+
expectedEncryptedData []byte
34633483
}{
34643484
{
34653485
name: "Non blinded final hop",
@@ -3477,16 +3497,18 @@ func TestLastHopPayloadSize(t *testing.T) {
34773497
restrictions: &RestrictParams{
34783498
BlindedPaymentPathSet: oneHopBlindedPayment,
34793499
},
3480-
amount: amtToForward,
3481-
finalHopExpiry: finalHopExpiry,
3500+
amount: amtToForward,
3501+
finalHopExpiry: finalHopExpiry,
3502+
expectedEncryptedData: emptyEncryptedData,
34823503
},
34833504
{
34843505
name: "Blinded final hop of a two hop payment",
34853506
restrictions: &RestrictParams{
34863507
BlindedPaymentPathSet: twoHopBlindedPayment,
34873508
},
3488-
amount: amtToForward,
3489-
finalHopExpiry: finalHopExpiry,
3509+
amount: amtToForward,
3510+
finalHopExpiry: finalHopExpiry,
3511+
expectedEncryptedData: encrypedDataLarge,
34903512
},
34913513
}
34923514

@@ -3510,16 +3532,23 @@ func TestLastHopPayloadSize(t *testing.T) {
35103532

35113533
var finalHop route.Hop
35123534
if tc.restrictions.BlindedPaymentPathSet != nil {
3513-
path := tc.restrictions.BlindedPaymentPathSet.
3514-
LargestLastHopPayloadPath()
3535+
bPSet := tc.restrictions.BlindedPaymentPathSet
3536+
path, err := bPSet.LargestLastHopPayloadPath()
3537+
require.NotNil(t, path)
3538+
3539+
require.NoError(t, err)
3540+
35153541
blindedPath := path.BlindedPath.BlindedHops
35163542
blindedPoint := path.BlindedPath.BlindingPoint
3543+
lastHop := blindedPath[len(blindedPath)-1]
3544+
require.Equal(t, lastHop.CipherText,
3545+
tc.expectedEncryptedData)
35173546

35183547
//nolint:ll
35193548
finalHop = route.Hop{
35203549
AmtToForward: tc.amount,
35213550
OutgoingTimeLock: uint32(tc.finalHopExpiry),
3522-
EncryptedData: blindedPath[len(blindedPath)-1].CipherText,
3551+
EncryptedData: lastHop.CipherText,
35233552
}
35243553
if len(blindedPath) == 1 {
35253554
finalHop.BlindingPoint = blindedPoint
@@ -3539,11 +3568,11 @@ func TestLastHopPayloadSize(t *testing.T) {
35393568
payLoad, err := createHopPayload(finalHop, 0, true)
35403569
require.NoErrorf(t, err, "failed to create hop payload")
35413570

3542-
expectedPayloadSize := lastHopPayloadSize(
3571+
expectedPayloadSize, err := lastHopPayloadSize(
35433572
tc.restrictions, tc.finalHopExpiry,
35443573
tc.amount,
35453574
)
3546-
3575+
require.NoError(t, err)
35473576
require.Equal(
35483577
t, expectedPayloadSize,
35493578
uint64(payLoad.NumBytes()),

0 commit comments

Comments
 (0)