+ pub(crate) fn generate_test_routes<S: Score>(graph: &NetworkGraph<&TestLogger>, scorer: &mut S,
+ score_params: &S::ScoreParams, features: InvoiceFeatures, mut seed: u64,
+ starting_amount: u64, route_count: usize,
+ ) -> Vec<(ChannelDetails, PaymentParameters, u64)> {
+ let payer = payer_pubkey();
+ let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
+ let random_seed_bytes = keys_manager.get_secure_random_bytes();
+
+ let nodes = graph.read_only().nodes().clone();
+ let mut route_endpoints = Vec::new();
+ // Fetch 1.5x more routes than we need as after we do some scorer updates we may end up
+ // with some routes we picked being un-routable.
+ for _ in 0..route_count * 3 / 2 {
+ loop {
+ seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+ let src = PublicKey::from_slice(nodes.unordered_keys()
+ .skip((seed as usize) % nodes.len()).next().unwrap().as_slice()).unwrap();
+ seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+ let dst = PublicKey::from_slice(nodes.unordered_keys()
+ .skip((seed as usize) % nodes.len()).next().unwrap().as_slice()).unwrap();
+ let params = PaymentParameters::from_node_id(dst, 42)
+ .with_bolt11_features(features.clone()).unwrap();
+ let first_hop = first_hop(src);
+ let amt = starting_amount + seed % 1_000_000;
+ let path_exists =
+ get_route(&payer, ¶ms, &graph.read_only(), Some(&[&first_hop]),
+ amt, &TestLogger::new(), &scorer, score_params, &random_seed_bytes).is_ok();
+ if path_exists {
+ // ...and seed the scorer with success and failure data...
+ seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+ let mut score_amt = seed % 1_000_000_000;
+ loop {
+ // Generate fail/success paths for a wider range of potential amounts with
+ // MPP enabled to give us a chance to apply penalties for more potential
+ // routes.
+ let mpp_features = channelmanager::provided_invoice_features(&UserConfig::default());
+ let params = PaymentParameters::from_node_id(dst, 42)
+ .with_bolt11_features(mpp_features).unwrap();
+
+ let route_res = get_route(&payer, ¶ms, &graph.read_only(),
+ Some(&[&first_hop]), score_amt, &TestLogger::new(), &scorer,
+ score_params, &random_seed_bytes);
+ if let Ok(route) = route_res {
+ for path in route.paths {
+ if seed & 0x80 == 0 {
+ scorer.payment_path_successful(&path);
+ } else {
+ let short_channel_id = path.hops[path.hops.len() / 2].short_channel_id;
+ scorer.payment_path_failed(&path, short_channel_id);
+ }
+ seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
+ }
+ break;
+ }
+ // If we couldn't find a path with a higer amount, reduce and try again.
+ score_amt /= 100;
+ }
+
+ route_endpoints.push((first_hop, params, amt));
+ break;
+ }
+ }
+ }
+
+ // Because we've changed channel scores, it's possible we'll take different routes to the
+ // selected destinations, possibly causing us to fail because, eg, the newly-selected path
+ // requires a too-high CLTV delta.
+ route_endpoints.retain(|(first_hop, params, amt)| {
+ get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt,
+ &TestLogger::new(), &scorer, score_params, &random_seed_bytes).is_ok()
+ });
+ route_endpoints.truncate(route_count);
+ assert_eq!(route_endpoints.len(), route_count);
+ route_endpoints
+ }
+}
+
+#[cfg(ldk_bench)]
+pub mod benches {
+ use super::*;
+ use crate::sign::{EntropySource, KeysManager};
+ use crate::ln::channelmanager;
+ use crate::ln::features::InvoiceFeatures;
+ use crate::routing::gossip::NetworkGraph;
+ use crate::routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
+ use crate::util::config::UserConfig;
+ use crate::util::logger::{Logger, Record};
+ use crate::util::test_utils::TestLogger;
+
+ use criterion::Criterion;
+
+ struct DummyLogger {}
+ impl Logger for DummyLogger {
+ fn log(&self, _record: &Record) {}
+ }
+
+ pub fn generate_routes_with_zero_penalty_scorer(bench: &mut Criterion) {
+ let logger = TestLogger::new();
+ let network_graph = bench_utils::read_network_graph(&logger).unwrap();