Skip to content

Commit 9bf4b6e

Browse files
Router fuzz: macroize first/last hops construction and pathfinding call
For reuse in fuzzing blinded payment pathfinding, and to ensure fuzz input values are fetched in the same order in both match arms.
1 parent 685f266 commit 9bf4b6e

File tree

1 file changed

+95
-75
lines changed

1 file changed

+95
-75
lines changed

fuzz/src/router.rs

+95-75
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,91 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
197197
let mut node_pks = HashSet::new();
198198
let mut scid = 42;
199199

200+
macro_rules! first_hops {
201+
($first_hops_vec: expr) => {
202+
match get_slice!(1)[0] {
203+
0 => None,
204+
count => {
205+
for _ in 0..count {
206+
scid += 1;
207+
let rnid = node_pks.iter().skip(u16::from_be_bytes(get_slice!(2).try_into().unwrap()) as usize % node_pks.len()).next().unwrap();
208+
let capacity = u64::from_be_bytes(get_slice!(8).try_into().unwrap());
209+
$first_hops_vec.push(ChannelDetails {
210+
channel_id: [0; 32],
211+
counterparty: ChannelCounterparty {
212+
node_id: *rnid,
213+
features: channelmanager::provided_init_features(&UserConfig::default()),
214+
unspendable_punishment_reserve: 0,
215+
forwarding_info: None,
216+
outbound_htlc_minimum_msat: None,
217+
outbound_htlc_maximum_msat: None,
218+
},
219+
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
220+
channel_type: None,
221+
short_channel_id: Some(scid),
222+
inbound_scid_alias: None,
223+
outbound_scid_alias: None,
224+
channel_value_satoshis: capacity,
225+
user_channel_id: 0, inbound_capacity_msat: 0,
226+
unspendable_punishment_reserve: None,
227+
confirmations_required: None,
228+
confirmations: None,
229+
force_close_spend_delay: None,
230+
is_outbound: true, is_channel_ready: true,
231+
is_usable: true, is_public: true,
232+
balance_msat: 0,
233+
outbound_capacity_msat: capacity.saturating_mul(1000),
234+
next_outbound_htlc_limit_msat: capacity.saturating_mul(1000),
235+
next_outbound_htlc_minimum_msat: 0,
236+
inbound_htlc_minimum_msat: None,
237+
inbound_htlc_maximum_msat: None,
238+
config: None,
239+
feerate_sat_per_1000_weight: None,
240+
channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
241+
});
242+
}
243+
Some(&$first_hops_vec[..])
244+
},
245+
}
246+
}
247+
}
248+
249+
macro_rules! last_hops {
250+
($last_hops: expr) => {
251+
let count = get_slice!(1)[0];
252+
for _ in 0..count {
253+
scid += 1;
254+
let rnid = node_pks.iter().skip(slice_to_be16(get_slice!(2))as usize % node_pks.len()).next().unwrap();
255+
$last_hops.push(RouteHint(vec![RouteHintHop {
256+
src_node_id: *rnid,
257+
short_channel_id: scid,
258+
fees: RoutingFees {
259+
base_msat: slice_to_be32(get_slice!(4)),
260+
proportional_millionths: slice_to_be32(get_slice!(4)),
261+
},
262+
cltv_expiry_delta: slice_to_be16(get_slice!(2)),
263+
htlc_minimum_msat: Some(slice_to_be64(get_slice!(8))),
264+
htlc_maximum_msat: None,
265+
}]));
266+
}
267+
}
268+
}
269+
270+
macro_rules! find_routes {
271+
($first_hops: expr, $node_pks: expr, $route_params: expr) => {
272+
let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &net_graph, &logger);
273+
let random_seed_bytes: [u8; 32] = [get_slice!(1)[0]; 32];
274+
for target in $node_pks {
275+
let final_value_msat = slice_to_be64(get_slice!(8));
276+
let final_cltv_expiry_delta = slice_to_be32(get_slice!(4));
277+
let route_params = $route_params(final_value_msat, final_cltv_expiry_delta, target);
278+
let _ = find_route(&our_pubkey, &route_params, &net_graph,
279+
$first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
280+
&logger, &scorer, &ProbabilisticScoringFeeParameters::default(), &random_seed_bytes);
281+
}
282+
}
283+
}
284+
200285
loop {
201286
match get_slice!(1)[0] {
202287
0 => {
@@ -232,83 +317,18 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
232317
_ if node_pks.is_empty() => {},
233318
_ => {
234319
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-
};
320+
// Use macros here and in the blinded match arm to ensure values are fetched from the fuzz
321+
// input in the same order, for better coverage.
322+
let first_hops = first_hops!(first_hops_vec);
279323
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)
324+
last_hops!(last_hops);
325+
find_routes!(first_hops, node_pks.iter(), |final_amt, final_delta, target: &PublicKey| {
326+
RouteParameters {
327+
payment_params: PaymentParameters::from_node_id(*target, final_delta)
305328
.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-
}
329+
final_value_msat: final_amt,
330+
}
331+
});
312332
},
313333
}
314334
}

0 commit comments

Comments
 (0)