7
7
// You may not use this file except in accordance with one or both of these
8
8
// licenses.
9
9
10
+ use crate :: blinded_path:: BlindedHop ;
10
11
use crate :: crypto:: chacha20:: ChaCha20 ;
11
12
use crate :: crypto:: streams:: ChaChaReader ;
12
13
use crate :: ln:: channelmanager:: { HTLCSource , RecipientOnionFields } ;
13
14
use crate :: ln:: msgs;
14
15
use crate :: ln:: types:: { PaymentHash , PaymentPreimage } ;
15
16
use crate :: ln:: wire:: Encode ;
16
17
use crate :: routing:: gossip:: NetworkUpdate ;
17
- use crate :: routing:: router:: { BlindedTail , Path , RouteHop } ;
18
+ use crate :: routing:: router:: { Path , RouteHop } ;
18
19
use crate :: sign:: NodeSigner ;
19
20
use crate :: util:: errors:: { self , APIError } ;
20
21
use crate :: util:: logger:: Logger ;
@@ -178,14 +179,56 @@ pub(super) fn build_onion_payloads<'a>(
178
179
path : & ' a Path , total_msat : u64 , recipient_onion : & ' a RecipientOnionFields ,
179
180
starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ,
180
181
) -> Result < ( Vec < msgs:: OutboundOnionPayload < ' a > > , u64 , u32 ) , APIError > {
181
- let mut cur_value_msat = 0u64 ;
182
- let mut cur_cltv = starting_htlc_offset;
183
- let mut last_short_channel_id = 0 ;
184
182
let mut res: Vec < msgs:: OutboundOnionPayload > = Vec :: with_capacity (
185
183
path. hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) ,
186
184
) ;
185
+ let blinded_tail_with_hop_iter = path. blinded_tail . as_ref ( ) . map ( |bt| BlindedTailHopIter {
186
+ hops : bt. hops . iter ( ) ,
187
+ blinding_point : bt. blinding_point ,
188
+ final_value_msat : bt. final_value_msat ,
189
+ excess_final_cltv_expiry_delta : bt. excess_final_cltv_expiry_delta ,
190
+ } ) ;
191
+
192
+ let ( value_msat, cltv) = build_onion_payloads_callback (
193
+ path. hops . iter ( ) ,
194
+ blinded_tail_with_hop_iter,
195
+ total_msat,
196
+ recipient_onion,
197
+ starting_htlc_offset,
198
+ keysend_preimage,
199
+ |action, payload| match action {
200
+ PayloadCallbackAction :: PushBack => res. push ( payload) ,
201
+ PayloadCallbackAction :: PushFront => res. insert ( 0 , payload) ,
202
+ } ,
203
+ ) ?;
204
+ Ok ( ( res, value_msat, cltv) )
205
+ }
187
206
188
- for ( idx, hop) in path. hops . iter ( ) . rev ( ) . enumerate ( ) {
207
+ struct BlindedTailHopIter < ' a , I : Iterator < Item = & ' a BlindedHop > > {
208
+ hops : I ,
209
+ blinding_point : PublicKey ,
210
+ final_value_msat : u64 ,
211
+ excess_final_cltv_expiry_delta : u32 ,
212
+ }
213
+ enum PayloadCallbackAction {
214
+ PushBack ,
215
+ PushFront ,
216
+ }
217
+ fn build_onion_payloads_callback < ' a , H , B , F > (
218
+ hops : H , mut blinded_tail : Option < BlindedTailHopIter < ' a , B > > , total_msat : u64 ,
219
+ recipient_onion : & ' a RecipientOnionFields , starting_htlc_offset : u32 ,
220
+ keysend_preimage : & Option < PaymentPreimage > , mut callback : F ,
221
+ ) -> Result < ( u64 , u32 ) , APIError >
222
+ where
223
+ H : DoubleEndedIterator < Item = & ' a RouteHop > ,
224
+ B : ExactSizeIterator < Item = & ' a BlindedHop > ,
225
+ F : FnMut ( PayloadCallbackAction , msgs:: OutboundOnionPayload < ' a > ) ,
226
+ {
227
+ let mut cur_value_msat = 0u64 ;
228
+ let mut cur_cltv = starting_htlc_offset;
229
+ let mut last_short_channel_id = 0 ;
230
+
231
+ for ( idx, hop) in hops. rev ( ) . enumerate ( ) {
189
232
// First hop gets special values so that it can check, on receipt, that everything is
190
233
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
191
234
// the intended recipient).
@@ -196,53 +239,63 @@ pub(super) fn build_onion_payloads<'a>(
196
239
cur_cltv
197
240
} ;
198
241
if idx == 0 {
199
- if let Some ( BlindedTail {
242
+ if let Some ( BlindedTailHopIter {
200
243
blinding_point,
201
244
hops,
202
245
final_value_msat,
203
246
excess_final_cltv_expiry_delta,
204
247
..
205
- } ) = & path . blinded_tail
248
+ } ) = blinded_tail. take ( )
206
249
{
207
- let mut blinding_point = Some ( * blinding_point) ;
208
- for ( i, blinded_hop) in hops. iter ( ) . enumerate ( ) {
209
- if i == hops. len ( ) - 1 {
250
+ let mut blinding_point = Some ( blinding_point) ;
251
+ let hops_len = hops. len ( ) ;
252
+ for ( i, blinded_hop) in hops. enumerate ( ) {
253
+ if i == hops_len - 1 {
210
254
cur_value_msat += final_value_msat;
211
- res. push ( msgs:: OutboundOnionPayload :: BlindedReceive {
212
- sender_intended_htlc_amt_msat : * final_value_msat,
213
- total_msat,
214
- cltv_expiry_height : cur_cltv + excess_final_cltv_expiry_delta,
215
- encrypted_tlvs : & blinded_hop. encrypted_payload ,
216
- intro_node_blinding_point : blinding_point. take ( ) ,
217
- keysend_preimage : * keysend_preimage,
218
- custom_tlvs : & recipient_onion. custom_tlvs ,
219
- } ) ;
255
+ callback (
256
+ PayloadCallbackAction :: PushBack ,
257
+ msgs:: OutboundOnionPayload :: BlindedReceive {
258
+ sender_intended_htlc_amt_msat : final_value_msat,
259
+ total_msat,
260
+ cltv_expiry_height : cur_cltv + excess_final_cltv_expiry_delta,
261
+ encrypted_tlvs : & blinded_hop. encrypted_payload ,
262
+ intro_node_blinding_point : blinding_point. take ( ) ,
263
+ keysend_preimage : * keysend_preimage,
264
+ custom_tlvs : & recipient_onion. custom_tlvs ,
265
+ } ,
266
+ ) ;
220
267
} else {
221
- res. push ( msgs:: OutboundOnionPayload :: BlindedForward {
222
- encrypted_tlvs : & blinded_hop. encrypted_payload ,
223
- intro_node_blinding_point : blinding_point. take ( ) ,
224
- } ) ;
268
+ callback (
269
+ PayloadCallbackAction :: PushBack ,
270
+ msgs:: OutboundOnionPayload :: BlindedForward {
271
+ encrypted_tlvs : & blinded_hop. encrypted_payload ,
272
+ intro_node_blinding_point : blinding_point. take ( ) ,
273
+ } ,
274
+ ) ;
225
275
}
226
276
}
227
277
} else {
228
- res. push ( msgs:: OutboundOnionPayload :: Receive {
229
- payment_data : recipient_onion. payment_secret . map ( |payment_secret| {
230
- msgs:: FinalOnionHopData { payment_secret, total_msat }
231
- } ) ,
232
- payment_metadata : recipient_onion. payment_metadata . as_ref ( ) ,
233
- keysend_preimage : * keysend_preimage,
234
- custom_tlvs : & recipient_onion. custom_tlvs ,
235
- sender_intended_htlc_amt_msat : value_msat,
236
- cltv_expiry_height : cltv,
237
- } ) ;
278
+ callback (
279
+ PayloadCallbackAction :: PushBack ,
280
+ msgs:: OutboundOnionPayload :: Receive {
281
+ payment_data : recipient_onion. payment_secret . map ( |payment_secret| {
282
+ msgs:: FinalOnionHopData { payment_secret, total_msat }
283
+ } ) ,
284
+ payment_metadata : recipient_onion. payment_metadata . as_ref ( ) ,
285
+ keysend_preimage : * keysend_preimage,
286
+ custom_tlvs : & recipient_onion. custom_tlvs ,
287
+ sender_intended_htlc_amt_msat : value_msat,
288
+ cltv_expiry_height : cltv,
289
+ } ,
290
+ ) ;
238
291
}
239
292
} else {
240
293
let payload = msgs:: OutboundOnionPayload :: Forward {
241
294
short_channel_id : last_short_channel_id,
242
295
amt_to_forward : value_msat,
243
296
outgoing_cltv_value : cltv,
244
297
} ;
245
- res . insert ( 0 , payload) ;
298
+ callback ( PayloadCallbackAction :: PushFront , payload) ;
246
299
}
247
300
cur_value_msat += hop. fee_msat ;
248
301
if cur_value_msat >= 21000000 * 100000000 * 1000 {
@@ -254,7 +307,7 @@ pub(super) fn build_onion_payloads<'a>(
254
307
}
255
308
last_short_channel_id = hop. short_channel_id ;
256
309
}
257
- Ok ( ( res , cur_value_msat, cur_cltv) )
310
+ Ok ( ( cur_value_msat, cur_cltv) )
258
311
}
259
312
260
313
/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now
0 commit comments