@@ -1353,12 +1353,39 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
1353
1353
keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
1354
1354
prng_seed : [ u8 ; 32 ] ,
1355
1355
) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1356
- let mut trampoline_payloads = vec ! [ ] ;
1356
+ create_payment_onion_internal (
1357
+ secp_ctx,
1358
+ path,
1359
+ session_priv,
1360
+ total_msat,
1361
+ recipient_onion,
1362
+ cur_block_height,
1363
+ payment_hash,
1364
+ keysend_preimage,
1365
+ invoice_request,
1366
+ prng_seed,
1367
+ None ,
1368
+ None ,
1369
+ None ,
1370
+ )
1371
+ }
1372
+
1373
+ /// Build a payment onion, returning the first hop msat and cltv values as well.
1374
+ /// `cur_block_height` should be set to the best known block height + 1.
1375
+ pub ( crate ) fn create_payment_onion_internal < T : secp256k1:: Signing > (
1376
+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
1377
+ recipient_onion : & RecipientOnionFields , cur_block_height : u32 , payment_hash : & PaymentHash ,
1378
+ keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
1379
+ prng_seed : [ u8 ; 32 ] , secondary_payment_secret : Option < PaymentSecret > ,
1380
+ secondary_session_priv : Option < SecretKey > , secondary_prng_seed : Option < [ u8 ; 32 ] > ,
1381
+ ) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1357
1382
let mut outer_total_msat = total_msat;
1358
1383
let mut outer_starting_htlc_offset = cur_block_height;
1359
1384
let mut outer_session_priv_override = None ;
1385
+ let mut trampoline_packet_option = None ;
1360
1386
1361
1387
if !path. trampoline_hops . is_empty ( ) {
1388
+ let trampoline_payloads;
1362
1389
( trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1363
1390
build_trampoline_onion_payloads (
1364
1391
path,
@@ -1367,18 +1394,7 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
1367
1394
cur_block_height,
1368
1395
keysend_preimage,
1369
1396
) ?;
1370
- }
1371
1397
1372
- let ( mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1373
- & path,
1374
- total_msat,
1375
- recipient_onion,
1376
- cur_block_height,
1377
- keysend_preimage,
1378
- invoice_request,
1379
- ) ?;
1380
-
1381
- if !path. trampoline_hops . is_empty ( ) {
1382
1398
let onion_keys =
1383
1399
construct_trampoline_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1384
1400
APIError :: InvalidRoute {
@@ -1396,26 +1412,39 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
1396
1412
err : "Route size too large considering onion data" . to_owned ( ) ,
1397
1413
} ) ?;
1398
1414
1415
+ trampoline_packet_option = Some ( trampoline_packet) ;
1416
+ }
1417
+
1418
+ let ( mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1419
+ & path,
1420
+ outer_total_msat,
1421
+ recipient_onion,
1422
+ outer_starting_htlc_offset,
1423
+ keysend_preimage,
1424
+ invoice_request,
1425
+ ) ?;
1426
+
1427
+ if !path. trampoline_hops . is_empty ( ) {
1399
1428
let last_payload = onion_payloads. pop ( ) . ok_or ( APIError :: InvalidRoute {
1400
1429
err : "Non-Trampoline path needs at least one hop" . to_owned ( ) ,
1401
1430
} ) ?;
1402
1431
1403
1432
match last_payload {
1404
1433
OutboundOnionPayload :: Receive { payment_data, .. } => {
1434
+ let fee_delta = path. hops . last ( ) . map_or ( 0 , |h| h. fee_msat ) ;
1435
+ let cltv_delta = path. hops . last ( ) . map_or ( 0 , |h| h. cltv_expiry_delta ) ;
1405
1436
let multipath_trampoline_data = payment_data. map ( |d| {
1406
- let trampoline_payment_secret =
1407
- Sha256 :: hash ( & d. payment_secret . 0 ) . to_byte_array ( ) ;
1408
- let total_msat = d. total_msat + path. hops . last ( ) . map_or ( 0 , |h| h. fee_msat ) ;
1409
- FinalOnionHopData {
1410
- payment_secret : PaymentSecret ( trampoline_payment_secret) ,
1411
- total_msat,
1412
- }
1437
+ let trampoline_payment_secret = secondary_payment_secret. unwrap_or_else ( || {
1438
+ PaymentSecret ( Sha256 :: hash ( & d. payment_secret . 0 ) . to_byte_array ( ) )
1439
+ } ) ;
1440
+ let total_msat = fee_delta;
1441
+ FinalOnionHopData { payment_secret : trampoline_payment_secret, total_msat }
1413
1442
} ) ;
1414
1443
onion_payloads. push ( OutboundOnionPayload :: TrampolineEntrypoint {
1415
- amt_to_forward : outer_total_msat ,
1416
- outgoing_cltv_value : outer_starting_htlc_offset,
1444
+ amt_to_forward : fee_delta ,
1445
+ outgoing_cltv_value : outer_starting_htlc_offset + cltv_delta ,
1417
1446
multipath_trampoline_data,
1418
- trampoline_packet,
1447
+ trampoline_packet : trampoline_packet_option . unwrap ( ) ,
1419
1448
} ) ;
1420
1449
} ,
1421
1450
_ => {
@@ -1426,19 +1455,22 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
1426
1455
} ,
1427
1456
} ;
1428
1457
1429
- let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1430
- outer_session_priv_override =
1431
- Some ( SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" ) ) ;
1458
+ outer_session_priv_override = Some ( secondary_session_priv. unwrap_or_else ( || {
1459
+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1460
+ SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1461
+ } ) ) ;
1432
1462
}
1433
1463
1434
1464
let outer_session_priv = outer_session_priv_override. as_ref ( ) . unwrap_or ( session_priv) ;
1435
1465
let onion_keys = construct_onion_keys ( & secp_ctx, & path, outer_session_priv) . map_err ( |_| {
1436
1466
APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1437
1467
} ) ?;
1438
- let onion_packet = construct_onion_packet ( onion_payloads, onion_keys, prng_seed, payment_hash)
1439
- . map_err ( |_| APIError :: InvalidRoute {
1440
- err : "Route size too large considering onion data" . to_owned ( ) ,
1441
- } ) ?;
1468
+ let outer_onion_prng_seed = secondary_prng_seed. unwrap_or ( prng_seed) ;
1469
+ let onion_packet =
1470
+ construct_onion_packet ( onion_payloads, onion_keys, outer_onion_prng_seed, payment_hash)
1471
+ . map_err ( |_| APIError :: InvalidRoute {
1472
+ err : "Route size too large considering onion data" . to_owned ( ) ,
1473
+ } ) ?;
1442
1474
Ok ( ( onion_packet, htlc_msat, htlc_cltv) )
1443
1475
}
1444
1476
0 commit comments