@@ -1353,12 +1353,39 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13531353 keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
13541354 prng_seed : [ u8 ; 32 ] ,
13551355) -> 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 > {
13571382 let mut outer_total_msat = total_msat;
13581383 let mut outer_starting_htlc_offset = cur_block_height;
13591384 let mut outer_session_priv_override = None ;
1385+ let mut trampoline_packet_option = None ;
13601386
13611387 if !path. trampoline_hops . is_empty ( ) {
1388+ let trampoline_payloads;
13621389 ( trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
13631390 build_trampoline_onion_payloads (
13641391 path,
@@ -1367,18 +1394,7 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13671394 cur_block_height,
13681395 keysend_preimage,
13691396 ) ?;
1370- }
13711397
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 ( ) {
13821398 let onion_keys =
13831399 construct_trampoline_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
13841400 APIError :: InvalidRoute {
@@ -1396,26 +1412,39 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13961412 err : "Route size too large considering onion data" . to_owned ( ) ,
13971413 } ) ?;
13981414
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 ( ) {
13991428 let last_payload = onion_payloads. pop ( ) . ok_or ( APIError :: InvalidRoute {
14001429 err : "Non-Trampoline path needs at least one hop" . to_owned ( ) ,
14011430 } ) ?;
14021431
14031432 match last_payload {
14041433 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 ) ;
14051436 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 }
14131442 } ) ;
14141443 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 ,
14171446 multipath_trampoline_data,
1418- trampoline_packet,
1447+ trampoline_packet : trampoline_packet_option . unwrap ( ) ,
14191448 } ) ;
14201449 } ,
14211450 _ => {
@@ -1426,19 +1455,22 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
14261455 } ,
14271456 } ;
14281457
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+ } ) ) ;
14321462 }
14331463
14341464 let outer_session_priv = outer_session_priv_override. as_ref ( ) . unwrap_or ( session_priv) ;
14351465 let onion_keys = construct_onion_keys ( & secp_ctx, & path, outer_session_priv) . map_err ( |_| {
14361466 APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
14371467 } ) ?;
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+ } ) ?;
14421474 Ok ( ( onion_packet, htlc_msat, htlc_cltv) )
14431475}
14441476
0 commit comments