@@ -18,7 +18,7 @@ use crate::routing::gossip::NetworkUpdate;
1818use crate :: routing:: router:: { BlindedTail , Path , RouteHop , RouteParameters , TrampolineHop } ;
1919use crate :: sign:: NodeSigner ;
2020use crate :: types:: features:: { ChannelFeatures , NodeFeatures } ;
21- use crate :: types:: payment:: { PaymentHash , PaymentPreimage } ;
21+ use crate :: types:: payment:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
2222use crate :: util:: errors:: { self , APIError } ;
2323use crate :: util:: logger:: Logger ;
2424use crate :: util:: ser:: { LengthCalculatingWriter , Readable , ReadableArgs , Writeable , Writer } ;
@@ -32,9 +32,10 @@ use bitcoin::secp256k1;
3232use bitcoin:: secp256k1:: ecdh:: SharedSecret ;
3333use bitcoin:: secp256k1:: { PublicKey , Scalar , Secp256k1 , SecretKey } ;
3434
35- use crate :: io:: { Cursor , Read } ;
3635use core:: ops:: Deref ;
3736
37+ use crate :: io:: { Cursor , Read } ;
38+ use crate :: ln:: msgs:: { FinalOnionHopData , OutboundOnionPayload } ;
3839#[ allow( unused_imports) ]
3940use crate :: prelude:: * ;
4041
@@ -347,12 +348,18 @@ pub(super) fn build_onion_payloads<'a>(
347348 let mut res: Vec < msgs:: OutboundOnionPayload > = Vec :: with_capacity (
348349 path. hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) ,
349350 ) ;
350- let blinded_tail_with_hop_iter = path. blinded_tail . as_ref ( ) . map ( |bt| BlindedTailHopIter {
351- hops : bt. hops . iter ( ) ,
352- blinding_point : bt. blinding_point ,
353- final_value_msat : bt. final_value_msat ,
354- excess_final_cltv_expiry_delta : bt. excess_final_cltv_expiry_delta ,
355- } ) ;
351+
352+ // When Trampoline hops are present, they are presumed to follow the non-Trampoline hops, which
353+ // means that the blinded path needs not be appended to the regular hops, and is only included
354+ // among the Trampoline onion payloads.
355+ let blinded_tail_with_hop_iter = path. trampoline_hops . is_empty ( ) . then ( || {
356+ path. blinded_tail . as_ref ( ) . map ( |bt| BlindedTailHopIter {
357+ hops : bt. hops . iter ( ) ,
358+ blinding_point : bt. blinding_point ,
359+ final_value_msat : bt. final_value_msat ,
360+ excess_final_cltv_expiry_delta : bt. excess_final_cltv_expiry_delta ,
361+ } )
362+ } ) . flatten ( ) ;
356363
357364 let ( value_msat, cltv) = build_onion_payloads_callback (
358365 path. hops . iter ( ) ,
@@ -586,7 +593,6 @@ pub(super) fn construct_onion_packet(
586593 )
587594}
588595
589- #[ allow( unused) ]
590596pub ( super ) fn construct_trampoline_onion_packet (
591597 payloads : Vec < msgs:: OutboundTrampolinePayload > , onion_keys : Vec < OnionKeys > ,
592598 prng_seed : [ u8 ; 32 ] , associated_data : & PaymentHash , length : Option < u16 > ,
@@ -1355,21 +1361,124 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
13551361 keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
13561362 prng_seed : [ u8 ; 32 ] ,
13571363) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1358- let onion_keys = construct_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1359- APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1360- } ) ?;
1361- let ( onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1362- & path,
1364+ create_payment_onion_internal (
1365+ secp_ctx,
1366+ path,
1367+ session_priv,
13631368 total_msat,
13641369 recipient_onion,
13651370 cur_block_height,
1371+ payment_hash,
13661372 keysend_preimage,
13671373 invoice_request,
1368- ) ?;
1369- let onion_packet = construct_onion_packet ( onion_payloads, onion_keys, prng_seed, payment_hash)
1374+ prng_seed,
1375+ None ,
1376+ None ,
1377+ None ,
1378+ )
1379+ }
1380+
1381+ /// Build a payment onion, returning the first hop msat and cltv values as well.
1382+ /// `cur_block_height` should be set to the best known block height + 1.
1383+ pub ( crate ) fn create_payment_onion_internal < T : secp256k1:: Signing > (
1384+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
1385+ recipient_onion : & RecipientOnionFields , cur_block_height : u32 , payment_hash : & PaymentHash ,
1386+ keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
1387+ prng_seed : [ u8 ; 32 ] , secondary_payment_secret : Option < PaymentSecret > ,
1388+ secondary_session_priv : Option < SecretKey > , secondary_prng_seed : Option < [ u8 ; 32 ] > ,
1389+ ) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1390+ let mut outer_total_msat = total_msat;
1391+ let mut outer_starting_htlc_offset = cur_block_height;
1392+ let mut outer_session_priv_override = None ;
1393+ let mut trampoline_packet_option = None ;
1394+
1395+ if !path. trampoline_hops . is_empty ( ) {
1396+ let trampoline_payloads;
1397+ ( trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1398+ build_trampoline_onion_payloads (
1399+ path,
1400+ total_msat,
1401+ recipient_onion,
1402+ cur_block_height,
1403+ keysend_preimage,
1404+ ) ?;
1405+
1406+ let onion_keys =
1407+ construct_trampoline_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1408+ APIError :: InvalidRoute {
1409+ err : "Pubkey along hop was maliciously selected" . to_owned ( ) ,
1410+ }
1411+ } ) ?;
1412+ let trampoline_packet = construct_trampoline_onion_packet (
1413+ trampoline_payloads,
1414+ onion_keys,
1415+ prng_seed,
1416+ payment_hash,
1417+ None ,
1418+ )
13701419 . map_err ( |_| APIError :: InvalidRoute {
13711420 err : "Route size too large considering onion data" . to_owned ( ) ,
13721421 } ) ?;
1422+
1423+ trampoline_packet_option = Some ( trampoline_packet) ;
1424+ }
1425+
1426+ let ( mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1427+ & path,
1428+ outer_total_msat,
1429+ recipient_onion,
1430+ outer_starting_htlc_offset,
1431+ keysend_preimage,
1432+ invoice_request,
1433+ ) ?;
1434+
1435+ if !path. trampoline_hops . is_empty ( ) {
1436+ let last_payload = onion_payloads. pop ( ) . ok_or ( APIError :: InvalidRoute {
1437+ err : "Non-Trampoline path needs at least one hop" . to_owned ( ) ,
1438+ } ) ?;
1439+
1440+ match last_payload {
1441+ OutboundOnionPayload :: Receive { payment_data, .. } => {
1442+ let fee_delta = path. hops . last ( ) . map_or ( 0 , |h| h. fee_msat ) ;
1443+ let cltv_delta = path. hops . last ( ) . map_or ( 0 , |h| h. cltv_expiry_delta ) ;
1444+ let multipath_trampoline_data = payment_data. map ( |d| {
1445+ let trampoline_payment_secret = secondary_payment_secret. unwrap_or_else ( || {
1446+ PaymentSecret ( Sha256 :: hash ( & d. payment_secret . 0 ) . to_byte_array ( ) )
1447+ } ) ;
1448+ let total_msat = fee_delta;
1449+ FinalOnionHopData { payment_secret : trampoline_payment_secret, total_msat }
1450+ } ) ;
1451+ onion_payloads. push ( OutboundOnionPayload :: TrampolineEntrypoint {
1452+ amt_to_forward : fee_delta,
1453+ outgoing_cltv_value : outer_starting_htlc_offset + cltv_delta,
1454+ multipath_trampoline_data,
1455+ trampoline_packet : trampoline_packet_option. unwrap ( ) ,
1456+ } ) ;
1457+ } ,
1458+ _ => {
1459+ return Err ( APIError :: InvalidRoute {
1460+ err : "Last non-Trampoline hop must be of type OutboundOnionPayload::Receive"
1461+ . to_owned ( ) ,
1462+ } ) ;
1463+ } ,
1464+ } ;
1465+
1466+ outer_session_priv_override = Some ( secondary_session_priv. unwrap_or_else ( || {
1467+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1468+ SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1469+ } ) ) ;
1470+ }
1471+
1472+ let outer_session_priv = outer_session_priv_override. as_ref ( ) . unwrap_or ( session_priv) ;
1473+ let onion_keys = construct_onion_keys ( & secp_ctx, & path, outer_session_priv) . map_err ( |_| {
1474+ APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1475+ } ) ?;
1476+ let outer_onion_prng_seed = secondary_prng_seed. unwrap_or ( prng_seed) ;
1477+ let onion_packet =
1478+ construct_onion_packet ( onion_payloads, onion_keys, outer_onion_prng_seed, payment_hash)
1479+ . map_err ( |_| APIError :: InvalidRoute {
1480+ err : "Route size too large considering onion data" . to_owned ( ) ,
1481+ } ) ?;
13731482 Ok ( ( onion_packet, htlc_msat, htlc_cltv) )
13741483}
13751484
0 commit comments