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 ;
@@ -173,19 +174,31 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(
173
174
Ok ( res)
174
175
}
175
176
176
- /// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
177
- pub ( super ) fn build_onion_payloads < ' a > (
178
- path : & ' a Path , total_msat : u64 , recipient_onion : & ' a RecipientOnionFields ,
179
- starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ,
180
- ) -> Result < ( Vec < msgs:: OutboundOnionPayload < ' a > > , u64 , u32 ) , APIError > {
177
+ struct BlindedTailHopIter < ' a , I : Iterator < Item = & ' a BlindedHop > > {
178
+ hops : I ,
179
+ blinding_point : PublicKey ,
180
+ final_value_msat : u64 ,
181
+ excess_final_cltv_expiry_delta : u32 ,
182
+ }
183
+ enum PayloadCallbackAction {
184
+ PushBack ,
185
+ Insert { idx : usize } ,
186
+ }
187
+ fn build_onion_payloads_callback < ' a , H , B , F > (
188
+ hops : H , mut blinded_tail : Option < BlindedTailHopIter < ' a , B > > , total_msat : u64 ,
189
+ recipient_onion : & ' a RecipientOnionFields , starting_htlc_offset : u32 ,
190
+ keysend_preimage : & Option < PaymentPreimage > , mut callback : F ,
191
+ ) -> Result < ( u64 , u32 ) , APIError >
192
+ where
193
+ H : DoubleEndedIterator < Item = & ' a RouteHop > ,
194
+ B : ExactSizeIterator < Item = & ' a BlindedHop > ,
195
+ F : FnMut ( PayloadCallbackAction , msgs:: OutboundOnionPayload < ' a > ) ,
196
+ {
181
197
let mut cur_value_msat = 0u64 ;
182
198
let mut cur_cltv = starting_htlc_offset;
183
199
let mut last_short_channel_id = 0 ;
184
- let mut res: Vec < msgs:: OutboundOnionPayload > = Vec :: with_capacity (
185
- path. hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) ,
186
- ) ;
187
200
188
- for ( idx, hop) in path . hops . iter ( ) . rev ( ) . enumerate ( ) {
201
+ for ( idx, hop) in hops. rev ( ) . enumerate ( ) {
189
202
// First hop gets special values so that it can check, on receipt, that everything is
190
203
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
191
204
// the intended recipient).
@@ -196,53 +209,63 @@ pub(super) fn build_onion_payloads<'a>(
196
209
cur_cltv
197
210
} ;
198
211
if idx == 0 {
199
- if let Some ( BlindedTail {
212
+ if let Some ( BlindedTailHopIter {
200
213
blinding_point,
201
214
hops,
202
215
final_value_msat,
203
216
excess_final_cltv_expiry_delta,
204
217
..
205
- } ) = & path . blinded_tail
218
+ } ) = blinded_tail. take ( )
206
219
{
207
- let mut blinding_point = Some ( * blinding_point) ;
208
- for ( i, blinded_hop) in hops. iter ( ) . enumerate ( ) {
209
- if i == hops. len ( ) - 1 {
220
+ let mut blinding_point = Some ( blinding_point) ;
221
+ let hops_len = hops. len ( ) ;
222
+ for ( i, blinded_hop) in hops. enumerate ( ) {
223
+ if i == hops_len - 1 {
210
224
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
- } ) ;
225
+ callback (
226
+ PayloadCallbackAction :: PushBack ,
227
+ msgs:: OutboundOnionPayload :: BlindedReceive {
228
+ sender_intended_htlc_amt_msat : final_value_msat,
229
+ total_msat,
230
+ cltv_expiry_height : cur_cltv + excess_final_cltv_expiry_delta,
231
+ encrypted_tlvs : & blinded_hop. encrypted_payload ,
232
+ intro_node_blinding_point : blinding_point. take ( ) ,
233
+ keysend_preimage : * keysend_preimage,
234
+ custom_tlvs : & recipient_onion. custom_tlvs ,
235
+ } ,
236
+ ) ;
220
237
} else {
221
- res. push ( msgs:: OutboundOnionPayload :: BlindedForward {
222
- encrypted_tlvs : & blinded_hop. encrypted_payload ,
223
- intro_node_blinding_point : blinding_point. take ( ) ,
224
- } ) ;
238
+ callback (
239
+ PayloadCallbackAction :: PushBack ,
240
+ msgs:: OutboundOnionPayload :: BlindedForward {
241
+ encrypted_tlvs : & blinded_hop. encrypted_payload ,
242
+ intro_node_blinding_point : blinding_point. take ( ) ,
243
+ } ,
244
+ ) ;
225
245
}
226
246
}
227
247
} 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
- } ) ;
248
+ callback (
249
+ PayloadCallbackAction :: PushBack ,
250
+ msgs:: OutboundOnionPayload :: Receive {
251
+ payment_data : recipient_onion. payment_secret . map ( |payment_secret| {
252
+ msgs:: FinalOnionHopData { payment_secret, total_msat }
253
+ } ) ,
254
+ payment_metadata : recipient_onion. payment_metadata . as_ref ( ) ,
255
+ keysend_preimage : * keysend_preimage,
256
+ custom_tlvs : & recipient_onion. custom_tlvs ,
257
+ sender_intended_htlc_amt_msat : value_msat,
258
+ cltv_expiry_height : cltv,
259
+ } ,
260
+ ) ;
238
261
}
239
262
} else {
240
263
let payload = msgs:: OutboundOnionPayload :: Forward {
241
264
short_channel_id : last_short_channel_id,
242
265
amt_to_forward : value_msat,
243
266
outgoing_cltv_value : cltv,
244
267
} ;
245
- res . insert ( 0 , payload) ;
268
+ callback ( PayloadCallbackAction :: Insert { idx : 0 } , payload) ;
246
269
}
247
270
cur_value_msat += hop. fee_msat ;
248
271
if cur_value_msat >= 21000000 * 100000000 * 1000 {
@@ -254,7 +277,37 @@ pub(super) fn build_onion_payloads<'a>(
254
277
}
255
278
last_short_channel_id = hop. short_channel_id ;
256
279
}
257
- Ok ( ( res, cur_value_msat, cur_cltv) )
280
+ Ok ( ( cur_value_msat, cur_cltv) )
281
+ }
282
+
283
+ /// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
284
+ pub ( super ) fn build_onion_payloads < ' a > (
285
+ path : & ' a Path , total_msat : u64 , recipient_onion : & ' a RecipientOnionFields ,
286
+ starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ,
287
+ ) -> Result < ( Vec < msgs:: OutboundOnionPayload < ' a > > , u64 , u32 ) , APIError > {
288
+ let mut res: Vec < msgs:: OutboundOnionPayload > = Vec :: with_capacity (
289
+ path. hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) ,
290
+ ) ;
291
+ let blinded_tail_with_hop_iter = path. blinded_tail . as_ref ( ) . map ( |bt| BlindedTailHopIter {
292
+ hops : bt. hops . iter ( ) ,
293
+ blinding_point : bt. blinding_point ,
294
+ final_value_msat : bt. final_value_msat ,
295
+ excess_final_cltv_expiry_delta : bt. excess_final_cltv_expiry_delta ,
296
+ } ) ;
297
+
298
+ let ( value_msat, cltv) = build_onion_payloads_callback (
299
+ path. hops . iter ( ) ,
300
+ blinded_tail_with_hop_iter,
301
+ total_msat,
302
+ recipient_onion,
303
+ starting_htlc_offset,
304
+ keysend_preimage,
305
+ |action, payload| match action {
306
+ PayloadCallbackAction :: PushBack => res. push ( payload) ,
307
+ PayloadCallbackAction :: Insert { idx } => res. insert ( idx, payload) ,
308
+ } ,
309
+ ) ?;
310
+ Ok ( ( res, value_msat, 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