@@ -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 } ;
@@ -698,7 +698,6 @@ pub(super) fn construct_onion_packet(
698698 )
699699}
700700
701- #[ allow( unused) ]
702701pub ( super ) fn construct_trampoline_onion_packet (
703702 payloads : Vec < msgs:: OutboundTrampolinePayload > , onion_keys : Vec < OnionKeys > ,
704703 prng_seed : [ u8 ; 32 ] , associated_data : & PaymentHash , length : Option < u16 > ,
@@ -1467,21 +1466,125 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
14671466 keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
14681467 prng_seed : [ u8 ; 32 ] ,
14691468) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1470- let onion_keys = construct_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1471- APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1472- } ) ?;
1473- let ( onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1474- & path,
1469+ create_payment_onion_internal (
1470+ secp_ctx,
1471+ path,
1472+ session_priv,
14751473 total_msat,
14761474 recipient_onion,
14771475 cur_block_height,
1476+ payment_hash,
14781477 keysend_preimage,
14791478 invoice_request,
1480- ) ?;
1481- let onion_packet = construct_onion_packet ( onion_payloads, onion_keys, prng_seed, payment_hash)
1479+ prng_seed,
1480+ None ,
1481+ None ,
1482+ None ,
1483+ )
1484+ }
1485+
1486+ /// Build a payment onion, returning the first hop msat and cltv values as well.
1487+ /// `cur_block_height` should be set to the best known block height + 1.
1488+ pub ( crate ) fn create_payment_onion_internal < T : secp256k1:: Signing > (
1489+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
1490+ recipient_onion : & RecipientOnionFields , cur_block_height : u32 , payment_hash : & PaymentHash ,
1491+ keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
1492+ prng_seed : [ u8 ; 32 ] , secondary_payment_secret : Option < PaymentSecret > ,
1493+ secondary_session_priv : Option < SecretKey > , secondary_prng_seed : Option < [ u8 ; 32 ] > ,
1494+ ) -> Result < ( msgs:: OnionPacket , u64 , u32 ) , APIError > {
1495+ let mut outer_total_msat = total_msat;
1496+ let mut outer_starting_htlc_offset = cur_block_height;
1497+ let mut outer_session_priv_override = None ;
1498+ let mut trampoline_packet_option = None ;
1499+
1500+ if !path. trampoline_hops . is_empty ( ) {
1501+ let trampoline_payloads;
1502+ ( trampoline_payloads, outer_total_msat, outer_starting_htlc_offset) =
1503+ build_trampoline_onion_payloads (
1504+ path,
1505+ total_msat,
1506+ recipient_onion,
1507+ cur_block_height,
1508+ keysend_preimage,
1509+ ) ?;
1510+
1511+ let onion_keys =
1512+ construct_trampoline_onion_keys ( & secp_ctx, & path, & session_priv) . map_err ( |_| {
1513+ APIError :: InvalidRoute {
1514+ err : "Pubkey along hop was maliciously selected" . to_owned ( ) ,
1515+ }
1516+ } ) ?;
1517+ let trampoline_packet = construct_trampoline_onion_packet (
1518+ trampoline_payloads,
1519+ onion_keys,
1520+ prng_seed,
1521+ payment_hash,
1522+ // TODO: specify a fixed size for privacy in future spec upgrade
1523+ None ,
1524+ )
14821525 . map_err ( |_| APIError :: InvalidRoute {
14831526 err : "Route size too large considering onion data" . to_owned ( ) ,
14841527 } ) ?;
1528+
1529+ trampoline_packet_option = Some ( trampoline_packet) ;
1530+ }
1531+
1532+ let ( mut onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1533+ & path,
1534+ outer_total_msat,
1535+ recipient_onion,
1536+ outer_starting_htlc_offset,
1537+ keysend_preimage,
1538+ invoice_request,
1539+ ) ?;
1540+
1541+ if !path. trampoline_hops . is_empty ( ) {
1542+ let last_payload = onion_payloads. pop ( ) . ok_or ( APIError :: InvalidRoute {
1543+ err : "Non-Trampoline path needs at least one hop" . to_owned ( ) ,
1544+ } ) ?;
1545+
1546+ match last_payload {
1547+ OutboundOnionPayload :: Receive { payment_data, .. } => {
1548+ let fee_delta = path. hops . last ( ) . map_or ( 0 , |h| h. fee_msat ) ;
1549+ let cltv_delta = path. hops . last ( ) . map_or ( 0 , |h| h. cltv_expiry_delta ) ;
1550+ let multipath_trampoline_data = payment_data. map ( |d| {
1551+ let trampoline_payment_secret = secondary_payment_secret. unwrap_or_else ( || {
1552+ PaymentSecret ( Sha256 :: hash ( & d. payment_secret . 0 ) . to_byte_array ( ) )
1553+ } ) ;
1554+ let total_msat = fee_delta;
1555+ FinalOnionHopData { payment_secret : trampoline_payment_secret, total_msat }
1556+ } ) ;
1557+ onion_payloads. push ( OutboundOnionPayload :: TrampolineEntrypoint {
1558+ amt_to_forward : fee_delta,
1559+ outgoing_cltv_value : outer_starting_htlc_offset + cltv_delta,
1560+ multipath_trampoline_data,
1561+ trampoline_packet : trampoline_packet_option. unwrap ( ) ,
1562+ } ) ;
1563+ } ,
1564+ _ => {
1565+ return Err ( APIError :: InvalidRoute {
1566+ err : "Last non-Trampoline hop must be of type OutboundOnionPayload::Receive"
1567+ . to_owned ( ) ,
1568+ } ) ;
1569+ } ,
1570+ } ;
1571+
1572+ outer_session_priv_override = Some ( secondary_session_priv. unwrap_or_else ( || {
1573+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1574+ SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1575+ } ) ) ;
1576+ }
1577+
1578+ let outer_session_priv = outer_session_priv_override. as_ref ( ) . unwrap_or ( session_priv) ;
1579+ let onion_keys = construct_onion_keys ( & secp_ctx, & path, outer_session_priv) . map_err ( |_| {
1580+ APIError :: InvalidRoute { err : "Pubkey along hop was maliciously selected" . to_owned ( ) }
1581+ } ) ?;
1582+ let outer_onion_prng_seed = secondary_prng_seed. unwrap_or ( prng_seed) ;
1583+ let onion_packet =
1584+ construct_onion_packet ( onion_payloads, onion_keys, outer_onion_prng_seed, payment_hash)
1585+ . map_err ( |_| APIError :: InvalidRoute {
1586+ err : "Route size too large considering onion data" . to_owned ( ) ,
1587+ } ) ?;
14851588 Ok ( ( onion_packet, htlc_msat, htlc_cltv) )
14861589}
14871590
0 commit comments