@@ -765,6 +765,9 @@ func TestPathFinding(t *testing.T) {
765
765
}, {
766
766
name : "path finding with additional edges" ,
767
767
fn : runPathFindingWithAdditionalEdges ,
768
+ }, {
769
+ name : "path finding with duplicate blinded hop" ,
770
+ fn : runPathFindingWithBlindedPathDuplicateHop ,
768
771
}, {
769
772
name : "path finding with redundant additional edges" ,
770
773
fn : runPathFindingWithRedundantAdditionalEdges ,
@@ -1265,6 +1268,107 @@ func runPathFindingWithAdditionalEdges(t *testing.T, useCache bool) {
1265
1268
assertExpectedPath (t , graph .aliasMap , path , "songoku" , "doge" )
1266
1269
}
1267
1270
1271
+ // runPathFindingWithBlindedPathDuplicateHop tests that in case a blinded path
1272
+ // has duplicate hops that the path finding algorithm does not fail or behave
1273
+ // incorrectly. This can happen because the creator of the blinded path can
1274
+ // specify the same hop multiple times and this will only be detected at the
1275
+ // forwarding nodes, so it is important that we can handle this case.
1276
+ func runPathFindingWithBlindedPathDuplicateHop (t * testing.T , useCache bool ) {
1277
+ graph , err := parseTestGraph (t , useCache , basicGraphFilePath )
1278
+ require .NoError (t , err , "unable to create graph" )
1279
+
1280
+ sourceNode , err := graph .graph .SourceNode ()
1281
+ require .NoError (t , err , "unable to fetch source node" )
1282
+
1283
+ paymentAmt := lnwire .NewMSatFromSatoshis (100 )
1284
+
1285
+ songokuPubKeyBytes := graph .aliasMap ["songoku" ]
1286
+ songokuPubKey , err := btcec .ParsePubKey (songokuPubKeyBytes [:])
1287
+ require .NoError (t , err , "unable to parse public key from bytes" )
1288
+
1289
+ _ , pkb1 := btcec .PrivKeyFromBytes ([]byte {2 })
1290
+ _ , pkb2 := btcec .PrivKeyFromBytes ([]byte {3 })
1291
+ _ , blindedPoint := btcec .PrivKeyFromBytes ([]byte {5 })
1292
+
1293
+ sizeEncryptedData := 100
1294
+ cipherText := bytes .Repeat (
1295
+ []byte {1 }, sizeEncryptedData ,
1296
+ )
1297
+
1298
+ vb1 := route .NewVertex (pkb1 )
1299
+ vb2 := route .NewVertex (pkb2 )
1300
+
1301
+ // Payments to blinded paths always pay to the NUMS target key.
1302
+ dummyTarget := route .NewVertex (& BlindedPathNUMSKey )
1303
+
1304
+ graph .aliasMap ["pkb1" ] = vb1
1305
+ graph .aliasMap ["pkb2" ] = vb2
1306
+ graph .aliasMap ["dummyTarget" ] = dummyTarget
1307
+
1308
+ // Create a blinded payment with duplicate hops and make sure the
1309
+ // path finding algorithm can cope with that. We add blinded hop 2
1310
+ // 3 times. The path finding algorithm should create a path with a
1311
+ // single hop to pkb2 (the first entry).
1312
+ blindedPayment := & BlindedPayment {
1313
+ BlindedPath : & sphinx.BlindedPath {
1314
+ IntroductionPoint : songokuPubKey ,
1315
+ BlindingPoint : blindedPoint ,
1316
+ BlindedHops : []* sphinx.BlindedHopInfo {
1317
+ {
1318
+ CipherText : cipherText ,
1319
+ },
1320
+ {
1321
+ BlindedNodePub : pkb2 ,
1322
+ CipherText : cipherText ,
1323
+ },
1324
+ {
1325
+ BlindedNodePub : pkb1 ,
1326
+ CipherText : cipherText ,
1327
+ },
1328
+ {
1329
+ BlindedNodePub : pkb2 ,
1330
+ CipherText : cipherText ,
1331
+ },
1332
+ {
1333
+ BlindedNodePub : & BlindedPathNUMSKey ,
1334
+ CipherText : cipherText ,
1335
+ },
1336
+ {
1337
+ BlindedNodePub : pkb2 ,
1338
+ CipherText : cipherText ,
1339
+ },
1340
+ },
1341
+ },
1342
+ HtlcMinimum : 1 ,
1343
+ HtlcMaximum : 100_000_000 ,
1344
+ CltvExpiryDelta : 140 ,
1345
+ }
1346
+
1347
+ blindedPath , err := blindedPayment .toRouteHints ()
1348
+ require .NoError (t , err )
1349
+
1350
+ find := func (r * RestrictParams ) (
1351
+ []* unifiedEdge , error ) {
1352
+
1353
+ return dbFindPath (
1354
+ graph .graph , blindedPath , & mockBandwidthHints {},
1355
+ r , testPathFindingConfig ,
1356
+ sourceNode .PubKeyBytes , dummyTarget , paymentAmt ,
1357
+ 0 , 0 ,
1358
+ )
1359
+ }
1360
+
1361
+ // We should now be able to find a path however not the chained path
1362
+ // of the blinded hops.
1363
+ path , err := find (noRestrictions )
1364
+ require .NoError (t , err , "unable to create route to blinded path" )
1365
+
1366
+ // The path should represent the following hops:
1367
+ // source node -> songoku -> pkb2 -> dummyTarget
1368
+ assertExpectedPath (t , graph .aliasMap , path , "songoku" , "pkb2" ,
1369
+ "dummyTarget" )
1370
+ }
1371
+
1268
1372
// runPathFindingWithRedundantAdditionalEdges asserts that we are able to find
1269
1373
// paths to nodes ignoring additional edges that are already known by self node.
1270
1374
func runPathFindingWithRedundantAdditionalEdges (t * testing.T , useCache bool ) {
0 commit comments