@@ -18,7 +18,7 @@ use crate::routing::gossip::NetworkUpdate;
18
18
use crate :: routing:: router:: { BlindedTail , Path , RouteHop , RouteParameters , TrampolineHop } ;
19
19
use crate :: sign:: NodeSigner ;
20
20
use crate :: types:: features:: { ChannelFeatures , NodeFeatures } ;
21
- use crate :: types:: payment:: { PaymentHash , PaymentPreimage } ;
21
+ use crate :: types:: payment:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
22
22
use crate :: util:: errors:: { self , APIError } ;
23
23
use crate :: util:: logger:: Logger ;
24
24
use crate :: util:: ser:: { LengthCalculatingWriter , Readable , ReadableArgs , Writeable , Writer } ;
@@ -698,7 +698,6 @@ pub(super) fn construct_onion_packet(
698
698
)
699
699
}
700
700
701
- #[ allow( unused) ]
702
701
pub ( super ) fn construct_trampoline_onion_packet (
703
702
payloads : Vec < msgs:: OutboundTrampolinePayload > , onion_keys : Vec < OnionKeys > ,
704
703
prng_seed : [ u8 ; 32 ] , associated_data : & PaymentHash , length : Option < u16 > ,
@@ -1467,21 +1466,125 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
1467
1466
keysend_preimage : & Option < PaymentPreimage > , invoice_request : Option < & InvoiceRequest > ,
1468
1467
prng_seed : [ u8 ; 32 ] ,
1469
1468
) -> 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,
1475
1473
total_msat,
1476
1474
recipient_onion,
1477
1475
cur_block_height,
1476
+ payment_hash,
1478
1477
keysend_preimage,
1479
1478
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
+ )
1482
1525
. map_err ( |_| APIError :: InvalidRoute {
1483
1526
err : "Route size too large considering onion data" . to_owned ( ) ,
1484
1527
} ) ?;
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
+ } ) ?;
1485
1588
Ok ( ( onion_packet, htlc_msat, htlc_cltv) )
1486
1589
}
1487
1590
0 commit comments