@@ -269,17 +269,24 @@ pub(super) fn construct_trampoline_keys<T: secp256k1::Signing>(
269
269
270
270
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
271
271
pub ( super ) fn build_onion_payloads (
272
- path : & Path , total_msat : u64 , mut recipient_onion : RecipientOnionFields ,
273
- starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ,
272
+ path : & Path , total_msat : u64 , mut recipient_onion : RecipientOnion , starting_htlc_offset : u32 ,
273
+ keysend_preimage : & Option < PaymentPreimage > ,
274
274
) -> Result < ( Vec < msgs:: OutboundOnionPayload > , u64 , u32 ) , APIError > {
275
275
let mut cur_value_msat = 0u64 ;
276
276
let mut cur_cltv = starting_htlc_offset;
277
277
let mut last_short_channel_id = 0 ;
278
- let mut res: Vec < msgs:: OutboundOnionPayload > = Vec :: with_capacity (
279
- path. hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) ,
280
- ) ;
281
278
282
- for ( idx, hop) in path. hops . iter ( ) . rev ( ) . enumerate ( ) {
279
+ let blinded_path_length =
280
+ if let ( RecipientOnion :: Final ( _) , Some ( tail) ) = ( & recipient_onion, & path. blinded_tail ) {
281
+ // the blinded path is only applicable if the outer onion isn't wrapping a Trampoline onion
282
+ tail. hops . len ( )
283
+ } else {
284
+ 0
285
+ } ;
286
+ let mut res: Vec < msgs:: OutboundOnionPayload > =
287
+ Vec :: with_capacity ( path. hops . len ( ) + blinded_path_length) ;
288
+
289
+ if let Some ( hop) = path. hops . last ( ) {
283
290
// First hop gets special values so that it can check, on receipt, that everything is
284
291
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
285
292
// the intended recipient).
@@ -289,55 +296,89 @@ pub(super) fn build_onion_payloads(
289
296
} else {
290
297
cur_cltv
291
298
} ;
292
- if idx == 0 {
293
- if let Some ( BlindedTail {
294
- blinding_point,
295
- hops,
296
- final_value_msat,
297
- excess_final_cltv_expiry_delta,
298
- ..
299
- } ) = & path. blinded_tail
300
- {
301
- let mut blinding_point = Some ( * blinding_point) ;
302
- for ( i, blinded_hop) in hops. iter ( ) . enumerate ( ) {
303
- if i == hops. len ( ) - 1 {
304
- cur_value_msat += final_value_msat;
305
- res. push ( msgs:: OutboundOnionPayload :: BlindedReceive {
306
- sender_intended_htlc_amt_msat : * final_value_msat,
307
- total_msat,
308
- cltv_expiry_height : cur_cltv + excess_final_cltv_expiry_delta,
309
- encrypted_tlvs : blinded_hop. encrypted_payload . clone ( ) ,
310
- intro_node_blinding_point : blinding_point. take ( ) ,
311
- } ) ;
312
- } else {
313
- res. push ( msgs:: OutboundOnionPayload :: BlindedForward {
314
- encrypted_tlvs : blinded_hop. encrypted_payload . clone ( ) ,
315
- intro_node_blinding_point : blinding_point. take ( ) ,
316
- } ) ;
299
+
300
+ match recipient_onion {
301
+ RecipientOnion :: TrampolineEntry ( mut trampoline_entry_fields) => {
302
+ res. push ( msgs:: OutboundOnionPayload :: TrampolineEntrypoint {
303
+ amt_to_forward : value_msat,
304
+ outgoing_cltv_value : cltv,
305
+ multipath_trampoline_data : None ,
306
+ trampoline_packet : trampoline_entry_fields. trampoline_packet ,
307
+ } ) ;
308
+ } ,
309
+ RecipientOnion :: Final ( mut recipient_onion_fields) => {
310
+ if let Some ( BlindedTail {
311
+ blinding_point,
312
+ hops,
313
+ final_value_msat,
314
+ excess_final_cltv_expiry_delta,
315
+ ..
316
+ } ) = & path. blinded_tail
317
+ {
318
+ let mut blinding_point = Some ( * blinding_point) ;
319
+ for ( i, blinded_hop) in hops. iter ( ) . enumerate ( ) {
320
+ if i == hops. len ( ) - 1 {
321
+ cur_value_msat += final_value_msat;
322
+ res. push ( msgs:: OutboundOnionPayload :: BlindedReceive {
323
+ sender_intended_htlc_amt_msat : * final_value_msat,
324
+ total_msat,
325
+ cltv_expiry_height : cur_cltv + excess_final_cltv_expiry_delta,
326
+ encrypted_tlvs : blinded_hop. encrypted_payload . clone ( ) ,
327
+ intro_node_blinding_point : blinding_point. take ( ) ,
328
+ } ) ;
329
+ } else {
330
+ res. push ( msgs:: OutboundOnionPayload :: BlindedForward {
331
+ encrypted_tlvs : blinded_hop. encrypted_payload . clone ( ) ,
332
+ intro_node_blinding_point : blinding_point. take ( ) ,
333
+ } ) ;
334
+ }
317
335
}
336
+ } else {
337
+ res. push ( msgs:: OutboundOnionPayload :: Receive {
338
+ payment_data : if let Some ( secret) =
339
+ recipient_onion_fields. payment_secret . take ( )
340
+ {
341
+ Some ( msgs:: FinalOnionHopData { payment_secret : secret, total_msat } )
342
+ } else {
343
+ None
344
+ } ,
345
+ payment_metadata : recipient_onion_fields. payment_metadata . take ( ) ,
346
+ keysend_preimage : * keysend_preimage,
347
+ custom_tlvs : recipient_onion_fields. custom_tlvs . clone ( ) ,
348
+ sender_intended_htlc_amt_msat : value_msat,
349
+ cltv_expiry_height : cltv,
350
+ } ) ;
318
351
}
319
- } else {
320
- res. push ( msgs:: OutboundOnionPayload :: Receive {
321
- payment_data : if let Some ( secret) = recipient_onion. payment_secret . take ( ) {
322
- Some ( msgs:: FinalOnionHopData { payment_secret : secret, total_msat } )
323
- } else {
324
- None
325
- } ,
326
- payment_metadata : recipient_onion. payment_metadata . take ( ) ,
327
- keysend_preimage : * keysend_preimage,
328
- custom_tlvs : recipient_onion. custom_tlvs . clone ( ) ,
329
- sender_intended_htlc_amt_msat : value_msat,
330
- cltv_expiry_height : cltv,
331
- } ) ;
332
- }
333
- } else {
334
- let payload = msgs:: OutboundOnionPayload :: Forward {
335
- short_channel_id : last_short_channel_id,
336
- amt_to_forward : value_msat,
337
- outgoing_cltv_value : cltv,
338
- } ;
339
- res. insert ( 0 , payload) ;
352
+ } ,
353
+ }
354
+
355
+ cur_value_msat += hop. fee_msat ;
356
+ if cur_value_msat >= 21000000 * 100000000 * 1000 {
357
+ return Err ( APIError :: InvalidRoute { err : "Channel fees overflowed?" . to_owned ( ) } ) ;
358
+ }
359
+ cur_cltv += hop. cltv_expiry_delta as u32 ;
360
+ if cur_cltv >= 500000000 {
361
+ return Err ( APIError :: InvalidRoute { err : "Channel CLTV overflowed?" . to_owned ( ) } ) ;
340
362
}
363
+ last_short_channel_id = hop. short_channel_id ;
364
+ }
365
+
366
+ for hop in path. hops . iter ( ) . rev ( ) . skip ( 1 ) {
367
+ // First hop gets special values so that it can check, on receipt, that everything is
368
+ // exactly as it should be (and the next hop isn't trying to probe to find out if we're
369
+ // the intended recipient).
370
+ let value_msat = if cur_value_msat == 0 { hop. fee_msat } else { cur_value_msat } ;
371
+ let cltv = if cur_cltv == starting_htlc_offset {
372
+ hop. cltv_expiry_delta + starting_htlc_offset
373
+ } else {
374
+ cur_cltv
375
+ } ;
376
+ let payload = msgs:: OutboundOnionPayload :: Forward {
377
+ short_channel_id : last_short_channel_id,
378
+ amt_to_forward : value_msat,
379
+ outgoing_cltv_value : cltv,
380
+ } ;
381
+ res. insert ( 0 , payload) ;
341
382
cur_value_msat += hop. fee_msat ;
342
383
if cur_value_msat >= 21000000 * 100000000 * 1000 {
343
384
return Err ( APIError :: InvalidRoute { err : "Channel fees overflowed?" . to_owned ( ) } ) ;
@@ -1265,7 +1306,7 @@ pub fn create_payment_onion<T: secp256k1::Signing>(
1265
1306
let ( onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads (
1266
1307
& path,
1267
1308
total_msat,
1268
- recipient_onion,
1309
+ recipient_onion. into ( ) ,
1269
1310
cur_block_height,
1270
1311
keysend_preimage,
1271
1312
) ?;
0 commit comments