@@ -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 } ;
@@ -658,7 +658,6 @@ pub(super) fn construct_onion_packet(
658658 )
659659}
660660
661- #[ allow( unused) ]
662661pub ( super ) fn construct_trampoline_onion_packet (
663662 payloads : Vec < msgs:: OutboundTrampolinePayload > , onion_keys : Vec < OnionKeys > ,
664663 prng_seed : [ u8 ; 32 ] , associated_data : & PaymentHash , length : Option < u16 > ,
@@ -1427,21 +1426,124 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
14271426 keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
14281427 prng_seed : [ u8 ; 32 ] ,
14291428) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1430- let onion_keys = construct_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1431- APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1432- } ) ?;
1433- let ( onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1434- & path,
1429+ create_payment_onion_internal (
1430+ secp_ctx,
1431+ path,
1432+ session_priv,
14351433 total_msat,
14361434 recipient_onion,
14371435 cur_block_height,
1436+ payment_hash,
14381437 keysend_preimage,
14391438 invoice_request,
1440- ) ?;
1441- let onion_packet = construct_onion_packet ( onion_payloads, onion_keys, prng_seed, payment_hash)
1439+ prng_seed,
1440+ None ,
1441+ None ,
1442+ None ,
1443+ )
1444+ }
1445+
1446+ /// Build a payment onion, returning the first hop msat and cltv values as well.
1447+ /// `cur_block_height` should be set to the best known block height + 1.
1448+ pub ( crate ) fn create_payment_onion_internal < T : secp256k1:: Signing > (
1449+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
1450+ recipient_onion : & RecipientOnionFields , cur_block_height : u32 , payment_hash : & PaymentHash ,
1451+ keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
1452+ prng_seed : [ u8 ; 32 ] , secondary_payment_secret : Option < PaymentSecret > ,
1453+ secondary_session_priv : Option < SecretKey > , secondary_prng_seed : Option < [ u8 ; 32 ] > ,
1454+ ) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1455+ let mut outer_total_msat = total_msat;
1456+ let mut outer_starting_htlc_offset = cur_block_height;
1457+ let mut outer_session_priv_override = None ;
1458+ let mut trampoline_packet_option = None ;
1459+
1460+ if !path. trampoline_hops . is_empty ( ) {
1461+ let trampoline_payloads;
1462+ ( trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1463+ build_trampoline_onion_payloads (
1464+ path,
1465+ total_msat,
1466+ recipient_onion,
1467+ cur_block_height,
1468+ keysend_preimage,
1469+ ) ?;
1470+
1471+ let onion_keys =
1472+ construct_trampoline_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1473+ APIError :: InvalidRoute {
1474+ err : "Pubkey along hop was maliciously selected" . to_owned ( ) ,
1475+ }
1476+ } ) ?;
1477+ let trampoline_packet = construct_trampoline_onion_packet (
1478+ trampoline_payloads,
1479+ onion_keys,
1480+ prng_seed,
1481+ payment_hash,
1482+ None ,
1483+ )
14421484 . map_err ( |_| APIError :: InvalidRoute {
14431485 err : "Route size too large considering onion data" . to_owned ( ) ,
14441486 } ) ?;
1487+
1488+ trampoline_packet_option = Some ( trampoline_packet) ;
1489+ }
1490+
1491+ let ( mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1492+ & path,
1493+ outer_total_msat,
1494+ recipient_onion,
1495+ outer_starting_htlc_offset,
1496+ keysend_preimage,
1497+ invoice_request,
1498+ ) ?;
1499+
1500+ if !path. trampoline_hops . is_empty ( ) {
1501+ let last_payload = onion_payloads. pop ( ) . ok_or ( APIError :: InvalidRoute {
1502+ err : "Non-Trampoline path needs at least one hop" . to_owned ( ) ,
1503+ } ) ?;
1504+
1505+ match last_payload {
1506+ OutboundOnionPayload :: Receive { payment_data, .. } => {
1507+ let fee_delta = path. hops . last ( ) . map_or ( 0 , |h| h. fee_msat ) ;
1508+ let cltv_delta = path. hops . last ( ) . map_or ( 0 , |h| h. cltv_expiry_delta ) ;
1509+ let multipath_trampoline_data = payment_data. map ( |d| {
1510+ let trampoline_payment_secret = secondary_payment_secret. unwrap_or_else ( || {
1511+ PaymentSecret ( Sha256 :: hash ( & d. payment_secret . 0 ) . to_byte_array ( ) )
1512+ } ) ;
1513+ let total_msat = fee_delta;
1514+ FinalOnionHopData { payment_secret : trampoline_payment_secret, total_msat }
1515+ } ) ;
1516+ onion_payloads. push ( OutboundOnionPayload :: TrampolineEntrypoint {
1517+ amt_to_forward : fee_delta,
1518+ outgoing_cltv_value : outer_starting_htlc_offset + cltv_delta,
1519+ multipath_trampoline_data,
1520+ trampoline_packet : trampoline_packet_option. unwrap ( ) ,
1521+ } ) ;
1522+ } ,
1523+ _ => {
1524+ return Err ( APIError :: InvalidRoute {
1525+ err : "Last non-Trampoline hop must be of type OutboundOnionPayload::Receive"
1526+ . to_owned ( ) ,
1527+ } ) ;
1528+ } ,
1529+ } ;
1530+
1531+ outer_session_priv_override = Some ( secondary_session_priv. unwrap_or_else ( || {
1532+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1533+ SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1534+ } ) ) ;
1535+ }
1536+
1537+ let outer_session_priv = outer_session_priv_override. as_ref ( ) . unwrap_or ( session_priv) ;
1538+ let onion_keys = construct_onion_keys ( & secp_ctx, & path, outer_session_priv) . map_err ( |_| {
1539+ APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1540+ } ) ?;
1541+ let outer_onion_prng_seed = secondary_prng_seed. unwrap_or ( prng_seed) ;
1542+ let onion_packet =
1543+ construct_onion_packet ( onion_payloads, onion_keys, outer_onion_prng_seed, payment_hash)
1544+ . map_err ( |_| APIError :: InvalidRoute {
1545+ err : "Route size too large considering onion data" . to_owned ( ) ,
1546+ } ) ?;
14451547 Ok ( ( onion_packet, htlc_msat, htlc_cltv) )
14461548}
14471549
0 commit comments