@@ -11,9 +11,12 @@ use bitcoin::blockdata::script::Builder;
11
11
use bitcoin:: blockdata:: transaction:: TxOut ;
12
12
use bitcoin:: hash_types:: BlockHash ;
13
13
14
+ use lightning:: blinded_path:: { BlindedHop , BlindedPath } ;
14
15
use lightning:: chain:: transaction:: OutPoint ;
15
16
use lightning:: ln:: channelmanager:: { self , ChannelDetails , ChannelCounterparty } ;
17
+ use lightning:: ln:: features:: { BlindedHopFeatures , Bolt12InvoiceFeatures } ;
16
18
use lightning:: ln:: msgs;
19
+ use lightning:: offers:: invoice:: BlindedPayInfo ;
17
20
use lightning:: routing:: gossip:: { NetworkGraph , RoutingFees } ;
18
21
use lightning:: routing:: utxo:: { UtxoFuture , UtxoLookup , UtxoLookupError , UtxoResult } ;
19
22
use lightning:: routing:: router:: { find_route, PaymentParameters , RouteHint , RouteHintHop , RouteParameters } ;
@@ -197,6 +200,91 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
197
200
let mut node_pks = HashSet :: new ( ) ;
198
201
let mut scid = 42 ;
199
202
203
+ macro_rules! first_hops {
204
+ ( $first_hops_vec: expr) => {
205
+ match get_slice!( 1 ) [ 0 ] {
206
+ 0 => None ,
207
+ count => {
208
+ for _ in 0 ..count {
209
+ scid += 1 ;
210
+ let rnid = node_pks. iter( ) . skip( u16 :: from_be_bytes( get_slice!( 2 ) . try_into( ) . unwrap( ) ) as usize % node_pks. len( ) ) . next( ) . unwrap( ) ;
211
+ let capacity = u64 :: from_be_bytes( get_slice!( 8 ) . try_into( ) . unwrap( ) ) ;
212
+ $first_hops_vec. push( ChannelDetails {
213
+ channel_id: [ 0 ; 32 ] ,
214
+ counterparty: ChannelCounterparty {
215
+ node_id: * rnid,
216
+ features: channelmanager:: provided_init_features( & UserConfig :: default ( ) ) ,
217
+ unspendable_punishment_reserve: 0 ,
218
+ forwarding_info: None ,
219
+ outbound_htlc_minimum_msat: None ,
220
+ outbound_htlc_maximum_msat: None ,
221
+ } ,
222
+ funding_txo: Some ( OutPoint { txid: bitcoin:: Txid :: from_slice( & [ 0 ; 32 ] ) . unwrap( ) , index: 0 } ) ,
223
+ channel_type: None ,
224
+ short_channel_id: Some ( scid) ,
225
+ inbound_scid_alias: None ,
226
+ outbound_scid_alias: None ,
227
+ channel_value_satoshis: capacity,
228
+ user_channel_id: 0 , inbound_capacity_msat: 0 ,
229
+ unspendable_punishment_reserve: None ,
230
+ confirmations_required: None ,
231
+ confirmations: None ,
232
+ force_close_spend_delay: None ,
233
+ is_outbound: true , is_channel_ready: true ,
234
+ is_usable: true , is_public: true ,
235
+ balance_msat: 0 ,
236
+ outbound_capacity_msat: capacity. saturating_mul( 1000 ) ,
237
+ next_outbound_htlc_limit_msat: capacity. saturating_mul( 1000 ) ,
238
+ next_outbound_htlc_minimum_msat: 0 ,
239
+ inbound_htlc_minimum_msat: None ,
240
+ inbound_htlc_maximum_msat: None ,
241
+ config: None ,
242
+ feerate_sat_per_1000_weight: None ,
243
+ channel_shutdown_state: Some ( channelmanager:: ChannelShutdownState :: NotShuttingDown ) ,
244
+ } ) ;
245
+ }
246
+ Some ( & $first_hops_vec[ ..] )
247
+ } ,
248
+ }
249
+ }
250
+ }
251
+
252
+ macro_rules! last_hops {
253
+ ( $last_hops: expr) => {
254
+ let count = get_slice!( 1 ) [ 0 ] ;
255
+ for _ in 0 ..count {
256
+ scid += 1 ;
257
+ let rnid = node_pks. iter( ) . skip( slice_to_be16( get_slice!( 2 ) ) as usize % node_pks. len( ) ) . next( ) . unwrap( ) ;
258
+ $last_hops. push( RouteHint ( vec![ RouteHintHop {
259
+ src_node_id: * rnid,
260
+ short_channel_id: scid,
261
+ fees: RoutingFees {
262
+ base_msat: slice_to_be32( get_slice!( 4 ) ) ,
263
+ proportional_millionths: slice_to_be32( get_slice!( 4 ) ) ,
264
+ } ,
265
+ cltv_expiry_delta: slice_to_be16( get_slice!( 2 ) ) ,
266
+ htlc_minimum_msat: Some ( slice_to_be64( get_slice!( 8 ) ) ) ,
267
+ htlc_maximum_msat: None ,
268
+ } ] ) ) ;
269
+ }
270
+ }
271
+ }
272
+
273
+ macro_rules! find_routes {
274
+ ( $first_hops: expr, $node_pks: expr, $route_params: expr) => {
275
+ let scorer = ProbabilisticScorer :: new( ProbabilisticScoringDecayParameters :: default ( ) , & net_graph, & logger) ;
276
+ let random_seed_bytes: [ u8 ; 32 ] = [ get_slice!( 1 ) [ 0 ] ; 32 ] ;
277
+ for target in $node_pks {
278
+ let final_value_msat = slice_to_be64( get_slice!( 8 ) ) ;
279
+ let final_cltv_expiry_delta = slice_to_be32( get_slice!( 4 ) ) ;
280
+ let route_params = $route_params( final_value_msat, final_cltv_expiry_delta, target) ;
281
+ let _ = find_route( & our_pubkey, & route_params, & net_graph,
282
+ $first_hops. map( |c| c. iter( ) . collect:: <Vec <_>>( ) ) . as_ref( ) . map( |a| a. as_slice( ) ) ,
283
+ & logger, & scorer, & ProbabilisticScoringFeeParameters :: default ( ) , & random_seed_bytes) ;
284
+ }
285
+ }
286
+ }
287
+
200
288
loop {
201
289
match get_slice ! ( 1 ) [ 0 ] {
202
290
0 => {
@@ -230,86 +318,61 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
230
318
net_graph. channel_failed_permanent ( short_channel_id) ;
231
319
} ,
232
320
_ if node_pks. is_empty ( ) => { } ,
233
- _ => {
321
+ x if x < 250 => {
234
322
let mut first_hops_vec = Vec :: new ( ) ;
235
- let first_hops = match get_slice ! ( 1 ) [ 0 ] {
236
- 0 => None ,
237
- count => {
238
- for _ in 0 ..count {
239
- scid += 1 ;
240
- let rnid = node_pks. iter ( ) . skip ( u16:: from_be_bytes ( get_slice ! ( 2 ) . try_into ( ) . unwrap ( ) ) as usize % node_pks. len ( ) ) . next ( ) . unwrap ( ) ;
241
- let capacity = u64:: from_be_bytes ( get_slice ! ( 8 ) . try_into ( ) . unwrap ( ) ) ;
242
- first_hops_vec. push ( ChannelDetails {
243
- channel_id : [ 0 ; 32 ] ,
244
- counterparty : ChannelCounterparty {
245
- node_id : * rnid,
246
- features : channelmanager:: provided_init_features ( & UserConfig :: default ( ) ) ,
247
- unspendable_punishment_reserve : 0 ,
248
- forwarding_info : None ,
249
- outbound_htlc_minimum_msat : None ,
250
- outbound_htlc_maximum_msat : None ,
251
- } ,
252
- funding_txo : Some ( OutPoint { txid : bitcoin:: Txid :: from_slice ( & [ 0 ; 32 ] ) . unwrap ( ) , index : 0 } ) ,
253
- channel_type : None ,
254
- short_channel_id : Some ( scid) ,
255
- inbound_scid_alias : None ,
256
- outbound_scid_alias : None ,
257
- channel_value_satoshis : capacity,
258
- user_channel_id : 0 , inbound_capacity_msat : 0 ,
259
- unspendable_punishment_reserve : None ,
260
- confirmations_required : None ,
261
- confirmations : None ,
262
- force_close_spend_delay : None ,
263
- is_outbound : true , is_channel_ready : true ,
264
- is_usable : true , is_public : true ,
265
- balance_msat : 0 ,
266
- outbound_capacity_msat : capacity. saturating_mul ( 1000 ) ,
267
- next_outbound_htlc_limit_msat : capacity. saturating_mul ( 1000 ) ,
268
- next_outbound_htlc_minimum_msat : 0 ,
269
- inbound_htlc_minimum_msat : None ,
270
- inbound_htlc_maximum_msat : None ,
271
- config : None ,
272
- feerate_sat_per_1000_weight : None ,
273
- channel_shutdown_state : Some ( channelmanager:: ChannelShutdownState :: NotShuttingDown ) ,
274
- } ) ;
275
- }
276
- Some ( & first_hops_vec[ ..] )
277
- } ,
278
- } ;
323
+ // Use macros here and in the blinded match arm to ensure values are fetched from the fuzz
324
+ // input in the same order, for better coverage.
325
+ let first_hops = first_hops ! ( first_hops_vec) ;
279
326
let mut last_hops = Vec :: new ( ) ;
280
- {
281
- let count = get_slice ! ( 1 ) [ 0 ] ;
282
- for _ in 0 ..count {
283
- scid += 1 ;
284
- let rnid = node_pks. iter ( ) . skip ( slice_to_be16 ( get_slice ! ( 2 ) ) as usize % node_pks. len ( ) ) . next ( ) . unwrap ( ) ;
285
- last_hops. push ( RouteHint ( vec ! [ RouteHintHop {
286
- src_node_id: * rnid,
287
- short_channel_id: scid,
288
- fees: RoutingFees {
289
- base_msat: slice_to_be32( get_slice!( 4 ) ) ,
290
- proportional_millionths: slice_to_be32( get_slice!( 4 ) ) ,
291
- } ,
292
- cltv_expiry_delta: slice_to_be16( get_slice!( 2 ) ) ,
293
- htlc_minimum_msat: Some ( slice_to_be64( get_slice!( 8 ) ) ) ,
294
- htlc_maximum_msat: None ,
295
- } ] ) ) ;
296
- }
297
- }
298
- let scorer = ProbabilisticScorer :: new ( ProbabilisticScoringDecayParameters :: default ( ) , & net_graph, & logger) ;
299
- let random_seed_bytes: [ u8 ; 32 ] = [ get_slice ! ( 1 ) [ 0 ] ; 32 ] ;
300
- for target in node_pks. iter ( ) {
301
- let final_value_msat = slice_to_be64 ( get_slice ! ( 8 ) ) ;
302
- let final_cltv_expiry_delta = slice_to_be32 ( get_slice ! ( 4 ) ) ;
303
- let route_params = RouteParameters {
304
- payment_params : PaymentParameters :: from_node_id ( * target, final_cltv_expiry_delta)
327
+ last_hops ! ( last_hops) ;
328
+ find_routes ! ( first_hops, node_pks. iter( ) , |final_amt, final_delta, target: & PublicKey | {
329
+ RouteParameters {
330
+ payment_params: PaymentParameters :: from_node_id( * target, final_delta)
305
331
. with_route_hints( last_hops. clone( ) ) . unwrap( ) ,
306
- final_value_msat,
307
- } ;
308
- let _ = find_route ( & our_pubkey, & route_params, & net_graph,
309
- first_hops. map ( |c| c. iter ( ) . collect :: < Vec < _ > > ( ) ) . as_ref ( ) . map ( |a| a. as_slice ( ) ) ,
310
- & logger, & scorer, & ProbabilisticScoringFeeParameters :: default ( ) , & random_seed_bytes) ;
311
- }
332
+ final_value_msat: final_amt,
333
+ }
334
+ } ) ;
312
335
} ,
336
+ x => {
337
+ let mut first_hops_vec = Vec :: new ( ) ;
338
+ let first_hops = first_hops ! ( first_hops_vec) ;
339
+ let mut last_hops_unblinded = Vec :: new ( ) ;
340
+ last_hops ! ( last_hops_unblinded) ;
341
+ let dummy_pk = PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ;
342
+ let last_hops: Vec < ( BlindedPayInfo , BlindedPath ) > = last_hops_unblinded. into_iter ( ) . map ( |hint| {
343
+ let hop = & hint. 0 [ 0 ] ;
344
+ let payinfo = BlindedPayInfo {
345
+ fee_base_msat : hop. fees . base_msat ,
346
+ fee_proportional_millionths : hop. fees . proportional_millionths ,
347
+ htlc_minimum_msat : hop. htlc_minimum_msat . unwrap ( ) ,
348
+ htlc_maximum_msat : hop. htlc_minimum_msat . unwrap ( ) . saturating_mul ( 100 ) ,
349
+ cltv_expiry_delta : hop. cltv_expiry_delta ,
350
+ features : BlindedHopFeatures :: empty ( ) ,
351
+ } ;
352
+ let num_blinded_hops = x % 250 ;
353
+ let mut blinded_hops = Vec :: new ( ) ;
354
+ for _ in 0 ..num_blinded_hops {
355
+ blinded_hops. push ( BlindedHop {
356
+ blinded_node_id : dummy_pk,
357
+ encrypted_payload : Vec :: new ( )
358
+ } ) ;
359
+ }
360
+ ( payinfo, BlindedPath {
361
+ introduction_node_id : hop. src_node_id ,
362
+ blinding_point : dummy_pk,
363
+ blinded_hops,
364
+ } )
365
+ } ) . collect ( ) ;
366
+ let mut features = Bolt12InvoiceFeatures :: empty ( ) ;
367
+ features. set_basic_mpp_optional ( ) ;
368
+ find_routes ! ( first_hops, vec![ dummy_pk] . iter( ) , |final_amt, _, _| {
369
+ RouteParameters {
370
+ payment_params: PaymentParameters :: blinded( last_hops. clone( ) )
371
+ . with_bolt12_features( features. clone( ) ) . unwrap( ) ,
372
+ final_value_msat: final_amt,
373
+ }
374
+ } ) ;
375
+ }
313
376
}
314
377
}
315
378
}
0 commit comments