@@ -259,6 +259,80 @@ pub(super) fn build_onion_payloads(
259
259
Ok ( ( res, cur_value_msat, cur_cltv) )
260
260
}
261
261
262
+ /// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
263
+ pub ( super ) fn build_trampoline_payloads (
264
+ path : & Path , total_msat : u64 , recipient_onion : RecipientOnionFields ,
265
+ starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ,
266
+ ) -> Result < ( Vec < msgs:: OutboundTrampolinePayload > , u64 , u32 ) , APIError > {
267
+ let mut cur_value_msat = 0u64 ;
268
+ let mut cur_cltv = starting_htlc_offset;
269
+ let mut last_node_id = None ;
270
+ let mut res: Vec < msgs:: OutboundTrampolinePayload > = Vec :: with_capacity (
271
+ path. trampoline_hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) ,
272
+ ) ;
273
+
274
+ for ( idx, hop) in path. trampoline_hops . iter ( ) . rev ( ) . enumerate ( ) {
275
+ // First hop gets special values so that it can check, on receipt, that everything is
276
+ // exactly as it should be (and the next hop isn't trying to probe to find out if we're
277
+ // the intended recipient).
278
+ let value_msat = if cur_value_msat == 0 { hop. fee_msat } else { cur_value_msat } ;
279
+ let cltv = if cur_cltv == starting_htlc_offset {
280
+ hop. cltv_expiry_delta + starting_htlc_offset
281
+ } else {
282
+ cur_cltv
283
+ } ;
284
+ if idx == 0 {
285
+ let BlindedTail {
286
+ blinding_point,
287
+ hops,
288
+ final_value_msat,
289
+ excess_final_cltv_expiry_delta,
290
+ ..
291
+ } = path. blinded_tail . as_ref ( ) . ok_or ( APIError :: InvalidRoute {
292
+ err : "Trampoline payments must terminate in blinded tails." . to_owned ( ) ,
293
+ } ) ?;
294
+ let mut blinding_point = Some ( * blinding_point) ;
295
+ for ( i, blinded_hop) in hops. iter ( ) . enumerate ( ) {
296
+ if i == hops. len ( ) - 1 {
297
+ cur_value_msat += final_value_msat;
298
+ res. push ( msgs:: OutboundTrampolinePayload :: BlindedReceive {
299
+ sender_intended_htlc_amt_msat : * final_value_msat,
300
+ total_msat,
301
+ cltv_expiry_height : cur_cltv + excess_final_cltv_expiry_delta,
302
+ encrypted_tlvs : blinded_hop. encrypted_payload . clone ( ) ,
303
+ intro_node_blinding_point : blinding_point. take ( ) ,
304
+ keysend_preimage : * keysend_preimage,
305
+ custom_tlvs : recipient_onion. custom_tlvs . clone ( ) ,
306
+ } ) ;
307
+ } else {
308
+ res. push ( msgs:: OutboundTrampolinePayload :: BlindedForward {
309
+ encrypted_tlvs : blinded_hop. encrypted_payload . clone ( ) ,
310
+ intro_node_blinding_point : blinding_point. take ( ) ,
311
+ } ) ;
312
+ }
313
+ }
314
+ } else {
315
+ let payload = msgs:: OutboundTrampolinePayload :: Forward {
316
+ amt_to_forward : value_msat,
317
+ outgoing_cltv_value : cltv,
318
+ outgoing_node_id : last_node_id
319
+ . expect ( "outgoing node id cannot be None after last hop" ) ,
320
+ } ;
321
+ res. insert ( 0 , payload) ;
322
+ }
323
+ cur_value_msat += hop. fee_msat ;
324
+ if cur_value_msat >= 21000000 * 100000000 * 1000 {
325
+ return Err ( APIError :: InvalidRoute { err : "Channel fees overflowed?" . to_owned ( ) } ) ;
326
+ }
327
+ cur_cltv += hop. cltv_expiry_delta as u32 ;
328
+ if cur_cltv >= 500000000 {
329
+ return Err ( APIError :: InvalidRoute { err : "Channel CLTV overflowed?" . to_owned ( ) } ) ;
330
+ }
331
+ last_node_id = Some ( hop. pubkey ) ;
332
+ }
333
+ Ok ( ( res, cur_value_msat, cur_cltv) )
334
+ }
335
+
262
336
/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now
263
337
/// the hops can be of variable length.
264
338
pub ( crate ) const ONION_DATA_LEN : usize = 20 * 65 ;
0 commit comments