X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=f7ed173b901a90a9dbe0d81166dfb188b77ccec9;hb=60706d6338854ef3a6d41ec8e500826ca0ee1f9e;hp=420fc3d202d282f41c71f265d6dafb1e4f314df5;hpb=2775902f3ab0fd8a25a2ec83303fb959d7468abb;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 420fc3d2..f7ed173b 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -621,8 +621,17 @@ impl PaymentParameters { /// /// The `final_cltv_expiry_delta` should match the expected final CLTV delta the recipient has /// provided. - pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32) -> Self { - Self::from_node_id(payee_pubkey, final_cltv_expiry_delta).with_bolt11_features(InvoiceFeatures::for_keysend()).expect("PaymentParameters::from_node_id should always initialize the payee as unblinded") + /// + /// Note that MPP keysend is not widely supported yet. The `allow_mpp` lets you choose + /// whether your router will be allowed to find a multi-part route for this payment. If you + /// set `allow_mpp` to true, you should ensure a payment secret is set on send, likely via + /// [`RecipientOnionFields::secret_only`]. + /// + /// [`RecipientOnionFields::secret_only`]: crate::ln::channelmanager::RecipientOnionFields::secret_only + pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32, allow_mpp: bool) -> Self { + Self::from_node_id(payee_pubkey, final_cltv_expiry_delta) + .with_bolt11_features(InvoiceFeatures::for_keysend(allow_mpp)) + .expect("PaymentParameters::from_node_id should always initialize the payee as unblinded") } /// Includes the payee's features. Errors if the parameters were initialized with blinded payment @@ -929,7 +938,7 @@ impl<'a> CandidateRouteHop<'a> { fn htlc_minimum_msat(&self) -> u64 { match self { - CandidateRouteHop::FirstHop { .. } => 0, + CandidateRouteHop::FirstHop { details } => details.next_outbound_htlc_minimum_msat, CandidateRouteHop::PublicHop { info, .. } => info.direction().htlc_minimum_msat, CandidateRouteHop::PrivateHop { hint } => hint.htlc_minimum_msat.unwrap_or(0), } @@ -951,7 +960,10 @@ impl<'a> CandidateRouteHop<'a> { liquidity_msat: details.next_outbound_htlc_limit_msat, }, CandidateRouteHop::PublicHop { info, .. } => info.effective_capacity(), - CandidateRouteHop::PrivateHop { .. } => EffectiveCapacity::Infinite, + CandidateRouteHop::PrivateHop { hint: RouteHintHop { htlc_maximum_msat: Some(max), .. }} => + EffectiveCapacity::HintMaxHTLC { amount_msat: *max }, + CandidateRouteHop::PrivateHop { hint: RouteHintHop { htlc_maximum_msat: None, .. }} => + EffectiveCapacity::Infinite, } } } @@ -963,8 +975,11 @@ fn max_htlc_from_capacity(capacity: EffectiveCapacity, max_channel_saturation_po EffectiveCapacity::ExactLiquidity { liquidity_msat } => liquidity_msat, EffectiveCapacity::Infinite => u64::max_value(), EffectiveCapacity::Unknown => EffectiveCapacity::Unknown.as_msat(), - EffectiveCapacity::MaximumHTLC { amount_msat } => + EffectiveCapacity::AdvertisedMaxHTLC { amount_msat } => amount_msat.checked_shr(saturation_shift).unwrap_or(0), + // Treat htlc_maximum_msat from a route hint as an exact liquidity amount, since the invoice is + // expected to have been generated from up-to-date capacity information. + EffectiveCapacity::HintMaxHTLC { amount_msat } => amount_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat } => cmp::min(capacity_msat.checked_shr(saturation_shift).unwrap_or(0), htlc_maximum_msat), } @@ -1015,7 +1030,7 @@ struct PathBuildingHop<'a> { /// decrease as well. Thus, we have to explicitly track which nodes have been processed and /// avoid processing them again. was_processed: bool, - #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))] + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] // In tests, we apply further sanity checks on cases where we skip nodes we already processed // to ensure it is specifically in cases where the fee has gone down because of a decrease in // value_contribution_msat, which requires tracking it here. See comments below where it is @@ -1036,7 +1051,7 @@ impl<'a> core::fmt::Debug for PathBuildingHop<'a> { .field("path_penalty_msat", &self.path_penalty_msat) .field("path_htlc_minimum_msat", &self.path_htlc_minimum_msat) .field("cltv_expiry_delta", &self.candidate.cltv_expiry_delta()); - #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))] + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] let debug_struct = debug_struct .field("value_contribution_msat", &self.value_contribution_msat); debug_struct.finish() @@ -1192,6 +1207,41 @@ impl fmt::Display for LoggedPayeePubkey { } } +#[inline] +fn sort_first_hop_channels( + channels: &mut Vec<&ChannelDetails>, used_channel_liquidities: &HashMap<(u64, bool), u64>, + recommended_value_msat: u64, our_node_pubkey: &PublicKey +) { + // Sort the first_hops channels to the same node(s) in priority order of which channel we'd + // most like to use. + // + // First, if channels are below `recommended_value_msat`, sort them in descending order, + // preferring larger channels to avoid splitting the payment into more MPP parts than is + // required. + // + // Second, because simply always sorting in descending order would always use our largest + // available outbound capacity, needlessly fragmenting our available channel capacities, + // sort channels above `recommended_value_msat` in ascending order, preferring channels + // which have enough, but not too much, capacity for the payment. + // + // Available outbound balances factor in liquidity already reserved for previously found paths. + channels.sort_unstable_by(|chan_a, chan_b| { + let chan_a_outbound_limit_msat = chan_a.next_outbound_htlc_limit_msat + .saturating_sub(*used_channel_liquidities.get(&(chan_a.get_outbound_payment_scid().unwrap(), + our_node_pubkey < &chan_a.counterparty.node_id)).unwrap_or(&0)); + let chan_b_outbound_limit_msat = chan_b.next_outbound_htlc_limit_msat + .saturating_sub(*used_channel_liquidities.get(&(chan_b.get_outbound_payment_scid().unwrap(), + our_node_pubkey < &chan_b.counterparty.node_id)).unwrap_or(&0)); + if chan_b_outbound_limit_msat < recommended_value_msat || chan_a_outbound_limit_msat < recommended_value_msat { + // Sort in descending order + chan_b_outbound_limit_msat.cmp(&chan_a_outbound_limit_msat) + } else { + // Sort in ascending order + chan_a_outbound_limit_msat.cmp(&chan_b_outbound_limit_msat) + } + }); +} + /// Finds a route from us (payer) to the given target node (payee). /// /// If the payee provided features in their invoice, they should be provided via `params.payee`. @@ -1437,26 +1487,8 @@ where L::Target: Logger { let mut already_collected_value_msat = 0; for (_, channels) in first_hop_targets.iter_mut() { - // Sort the first_hops channels to the same node(s) in priority order of which channel we'd - // most like to use. - // - // First, if channels are below `recommended_value_msat`, sort them in descending order, - // preferring larger channels to avoid splitting the payment into more MPP parts than is - // required. - // - // Second, because simply always sorting in descending order would always use our largest - // available outbound capacity, needlessly fragmenting our available channel capacities, - // sort channels above `recommended_value_msat` in ascending order, preferring channels - // which have enough, but not too much, capacity for the payment. - channels.sort_unstable_by(|chan_a, chan_b| { - if chan_b.next_outbound_htlc_limit_msat < recommended_value_msat || chan_a.next_outbound_htlc_limit_msat < recommended_value_msat { - // Sort in descending order - chan_b.next_outbound_htlc_limit_msat.cmp(&chan_a.next_outbound_htlc_limit_msat) - } else { - // Sort in ascending order - chan_a.next_outbound_htlc_limit_msat.cmp(&chan_b.next_outbound_htlc_limit_msat) - } - }); + sort_first_hop_channels(channels, &used_channel_liquidities, recommended_value_msat, + our_node_pubkey); } log_trace!(logger, "Building path from {} to payer {} for value {} msat.", @@ -1470,8 +1502,9 @@ where L::Target: Logger { ( $candidate: expr, $src_node_id: expr, $dest_node_id: expr, $next_hops_fee_msat: expr, $next_hops_value_contribution: expr, $next_hops_path_htlc_minimum_msat: expr, $next_hops_path_penalty_msat: expr, $next_hops_cltv_delta: expr, $next_hops_path_length: expr ) => { { - // We "return" whether we updated the path at the end, via this: - let mut did_add_update_path_to_src_node = false; + // We "return" whether we updated the path at the end, and how much we can route via + // this channel, via this: + let mut did_add_update_path_to_src_node = None; // Channels to self should not be used. This is more of belt-and-suspenders, because in // practice these cases should be caught earlier: // - for regular channels at channel announcement (TODO) @@ -1570,14 +1603,14 @@ where L::Target: Logger { path_htlc_minimum_msat, path_penalty_msat: u64::max_value(), was_processed: false, - #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))] + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] value_contribution_msat, } }); #[allow(unused_mut)] // We only use the mut in cfg(test) let mut should_process = !old_entry.was_processed; - #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))] + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] { // In test/fuzzing builds, we do extra checks to make sure the skipping // of already-seen nodes only happens in cases we expect (see below). @@ -1648,13 +1681,13 @@ where L::Target: Logger { old_entry.fee_msat = 0; // This value will be later filled with hop_use_fee_msat of the following channel old_entry.path_htlc_minimum_msat = path_htlc_minimum_msat; old_entry.path_penalty_msat = path_penalty_msat; - #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))] + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] { old_entry.value_contribution_msat = value_contribution_msat; } - did_add_update_path_to_src_node = true; + did_add_update_path_to_src_node = Some(value_contribution_msat); } else if old_entry.was_processed && new_cost < old_cost { - #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))] + #[cfg(all(not(ldk_bench), any(test, fuzzing)))] { // If we're skipping processing a node which was previously // processed even though we found another path to it with a @@ -1773,7 +1806,7 @@ where L::Target: Logger { for details in first_channels { let candidate = CandidateRouteHop::FirstHop { details }; let added = add_entry!(candidate, our_node_id, payee, 0, path_value_msat, - 0, 0u64, 0, 0); + 0, 0u64, 0, 0).is_some(); log_trace!(logger, "{} direct route to payee via SCID {}", if added { "Added" } else { "Skipped" }, candidate.short_channel_id()); } @@ -1820,6 +1853,7 @@ where L::Target: Logger { let mut aggregate_next_hops_path_penalty_msat: u64 = 0; let mut aggregate_next_hops_cltv_delta: u32 = 0; let mut aggregate_next_hops_path_length: u8 = 0; + let mut aggregate_path_contribution_msat = path_value_msat; for (idx, (hop, prev_hop_id)) in hop_iter.zip(prev_hop_iter).enumerate() { let source = NodeId::from_pubkey(&hop.src_node_id); @@ -1833,10 +1867,13 @@ where L::Target: Logger { }) .unwrap_or_else(|| CandidateRouteHop::PrivateHop { hint: hop }); - if !add_entry!(candidate, source, target, aggregate_next_hops_fee_msat, - path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, - aggregate_next_hops_path_penalty_msat, - aggregate_next_hops_cltv_delta, aggregate_next_hops_path_length) { + if let Some(hop_used_msat) = add_entry!(candidate, source, target, + aggregate_next_hops_fee_msat, aggregate_path_contribution_msat, + aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, + aggregate_next_hops_cltv_delta, aggregate_next_hops_path_length) + { + aggregate_path_contribution_msat = hop_used_msat; + } else { // If this hop was not used then there is no use checking the preceding // hops in the RouteHint. We can break by just searching for a direct // channel between last checked hop and first_hop_targets. @@ -1863,14 +1900,15 @@ where L::Target: Logger { .saturating_add(1); // Searching for a direct channel between last checked hop and first_hop_targets - if let Some(first_channels) = first_hop_targets.get(&NodeId::from_pubkey(&prev_hop_id)) { + if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&prev_hop_id)) { + sort_first_hop_channels(first_channels, &used_channel_liquidities, + recommended_value_msat, our_node_pubkey); for details in first_channels { - let candidate = CandidateRouteHop::FirstHop { details }; - add_entry!(candidate, our_node_id, NodeId::from_pubkey(&prev_hop_id), - aggregate_next_hops_fee_msat, path_value_msat, - aggregate_next_hops_path_htlc_minimum_msat, - aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta, - aggregate_next_hops_path_length); + let first_hop_candidate = CandidateRouteHop::FirstHop { details }; + add_entry!(first_hop_candidate, our_node_id, NodeId::from_pubkey(&prev_hop_id), + aggregate_next_hops_fee_msat, aggregate_path_contribution_msat, + aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, + aggregate_next_hops_cltv_delta, aggregate_next_hops_path_length); } } @@ -1903,12 +1941,15 @@ where L::Target: Logger { // Note that we *must* check if the last hop was added as `add_entry` // always assumes that the third argument is a node to which we have a // path. - if let Some(first_channels) = first_hop_targets.get(&NodeId::from_pubkey(&hop.src_node_id)) { + if let Some(first_channels) = first_hop_targets.get_mut(&NodeId::from_pubkey(&hop.src_node_id)) { + sort_first_hop_channels(first_channels, &used_channel_liquidities, + recommended_value_msat, our_node_pubkey); for details in first_channels { - let candidate = CandidateRouteHop::FirstHop { details }; - add_entry!(candidate, our_node_id, + let first_hop_candidate = CandidateRouteHop::FirstHop { details }; + add_entry!(first_hop_candidate, our_node_id, NodeId::from_pubkey(&hop.src_node_id), - aggregate_next_hops_fee_msat, path_value_msat, + aggregate_next_hops_fee_msat, + aggregate_path_contribution_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta, @@ -2460,6 +2501,7 @@ mod tests { balance_msat: 0, outbound_capacity_msat, next_outbound_htlc_limit_msat: outbound_capacity_msat, + next_outbound_htlc_minimum_msat: 0, inbound_capacity_msat: 42, unspendable_punishment_reserve: None, confirmations_required: None, @@ -5892,6 +5934,127 @@ mod tests { assert!(route.is_ok()); } + #[test] + fn abide_by_route_hint_max_htlc() { + // Check that we abide by any htlc_maximum_msat provided in the route hints of the payment + // params in the final route. + let (secp_ctx, network_graph, _, _, logger) = build_graph(); + let netgraph = network_graph.read_only(); + let (_, our_id, _, nodes) = get_nodes(&secp_ctx); + let scorer = ln_test_utils::TestScorer::new(); + let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); + let random_seed_bytes = keys_manager.get_secure_random_bytes(); + let config = UserConfig::default(); + + let max_htlc_msat = 50_000; + let route_hint_1 = RouteHint(vec![RouteHintHop { + src_node_id: nodes[2], + short_channel_id: 42, + fees: RoutingFees { + base_msat: 100, + proportional_millionths: 0, + }, + cltv_expiry_delta: 10, + htlc_minimum_msat: None, + htlc_maximum_msat: Some(max_htlc_msat), + }]); + let dest_node_id = ln_test_utils::pubkey(42); + let payment_params = PaymentParameters::from_node_id(dest_node_id, 42) + .with_route_hints(vec![route_hint_1.clone()]).unwrap() + .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap(); + + // Make sure we'll error if our route hints don't have enough liquidity according to their + // htlc_maximum_msat. + if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, + &payment_params, &netgraph, None, max_htlc_msat + 1, Arc::clone(&logger), &scorer, &(), + &random_seed_bytes) + { + assert_eq!(err, "Failed to find a sufficient route to the given destination"); + } else { panic!(); } + + // Make sure we'll split an MPP payment across route hints if their htlc_maximum_msat warrants. + let mut route_hint_2 = route_hint_1.clone(); + route_hint_2.0[0].short_channel_id = 43; + let payment_params = PaymentParameters::from_node_id(dest_node_id, 42) + .with_route_hints(vec![route_hint_1, route_hint_2]).unwrap() + .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap(); + let route = get_route(&our_id, &payment_params, &netgraph, None, max_htlc_msat + 1, + Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap(); + assert_eq!(route.paths.len(), 2); + assert!(route.paths[0].hops.last().unwrap().fee_msat <= max_htlc_msat); + assert!(route.paths[1].hops.last().unwrap().fee_msat <= max_htlc_msat); + } + + #[test] + fn direct_channel_to_hints_with_max_htlc() { + // Check that if we have a first hop channel peer that's connected to multiple provided route + // hints, that we properly split the payment between the route hints if needed. + let logger = Arc::new(ln_test_utils::TestLogger::new()); + let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, Arc::clone(&logger))); + let scorer = ln_test_utils::TestScorer::new(); + let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); + let random_seed_bytes = keys_manager.get_secure_random_bytes(); + let config = UserConfig::default(); + + let our_node_id = ln_test_utils::pubkey(42); + let intermed_node_id = ln_test_utils::pubkey(43); + let first_hop = vec![get_channel_details(Some(42), intermed_node_id, InitFeatures::from_le_bytes(vec![0b11]), 10_000_000)]; + + let amt_msat = 900_000; + let max_htlc_msat = 500_000; + let route_hint_1 = RouteHint(vec![RouteHintHop { + src_node_id: intermed_node_id, + short_channel_id: 44, + fees: RoutingFees { + base_msat: 100, + proportional_millionths: 0, + }, + cltv_expiry_delta: 10, + htlc_minimum_msat: None, + htlc_maximum_msat: Some(max_htlc_msat), + }, RouteHintHop { + src_node_id: intermed_node_id, + short_channel_id: 45, + fees: RoutingFees { + base_msat: 100, + proportional_millionths: 0, + }, + cltv_expiry_delta: 10, + htlc_minimum_msat: None, + // Check that later route hint max htlcs don't override earlier ones + htlc_maximum_msat: Some(max_htlc_msat - 50), + }]); + let mut route_hint_2 = route_hint_1.clone(); + route_hint_2.0[0].short_channel_id = 46; + route_hint_2.0[1].short_channel_id = 47; + let dest_node_id = ln_test_utils::pubkey(44); + let payment_params = PaymentParameters::from_node_id(dest_node_id, 42) + .with_route_hints(vec![route_hint_1, route_hint_2]).unwrap() + .with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap(); + + let route = get_route(&our_node_id, &payment_params, &network_graph.read_only(), + Some(&first_hop.iter().collect::>()), amt_msat, Arc::clone(&logger), &scorer, &(), + &random_seed_bytes).unwrap(); + assert_eq!(route.paths.len(), 2); + assert!(route.paths[0].hops.last().unwrap().fee_msat <= max_htlc_msat); + assert!(route.paths[1].hops.last().unwrap().fee_msat <= max_htlc_msat); + assert_eq!(route.get_total_amount(), amt_msat); + + // Re-run but with two first hop channels connected to the same route hint peers that must be + // split between. + let first_hops = vec![ + get_channel_details(Some(42), intermed_node_id, InitFeatures::from_le_bytes(vec![0b11]), amt_msat - 10), + get_channel_details(Some(43), intermed_node_id, InitFeatures::from_le_bytes(vec![0b11]), amt_msat - 10), + ]; + let route = get_route(&our_node_id, &payment_params, &network_graph.read_only(), + Some(&first_hops.iter().collect::>()), amt_msat, Arc::clone(&logger), &scorer, &(), + &random_seed_bytes).unwrap(); + assert_eq!(route.paths.len(), 2); + assert!(route.paths[0].hops.last().unwrap().fee_msat <= max_htlc_msat); + assert!(route.paths[1].hops.last().unwrap().fee_msat <= max_htlc_msat); + assert_eq!(route.get_total_amount(), amt_msat); + } + #[test] fn blinded_route_ser() { let blinded_path_1 = BlindedPath { @@ -6038,7 +6201,7 @@ mod tests { } } -#[cfg(all(test, not(feature = "no-std")))] +#[cfg(all(any(test, ldk_bench), not(feature = "no-std")))] pub(crate) mod bench_utils { use super::*; use std::fs::File; @@ -6068,7 +6231,18 @@ pub(crate) mod bench_utils { path.pop(); // target path.push("lightning"); path.push("net_graph-2023-01-18.bin"); - eprintln!("{}", path.to_str().unwrap()); + File::open(path) + }) + .or_else(|_| { // Fall back to guessing based on the binary location for a subcrate + // path is likely something like .../rust-lightning/bench/target/debug/deps/bench.. + let mut path = std::env::current_exe().unwrap(); + path.pop(); // bench... + path.pop(); // deps + path.pop(); // debug + path.pop(); // target + path.pop(); // bench + path.push("lightning"); + path.push("net_graph-2023-01-18.bin"); File::open(path) }) .map_err(|_| "Please fetch https://bitcoin.ninja/ldk-net_graph-v0.0.113-2023-01-18.bin and place it at lightning/net_graph-2023-01-18.bin"); @@ -6110,6 +6284,7 @@ pub(crate) mod bench_utils { user_channel_id: 0, balance_msat: 10_000_000_000, outbound_capacity_msat: 10_000_000_000, + next_outbound_htlc_minimum_msat: 0, next_outbound_htlc_limit_msat: 10_000_000_000, inbound_capacity_msat: 0, unspendable_punishment_reserve: None, @@ -6204,8 +6379,8 @@ pub(crate) mod bench_utils { } } -#[cfg(all(test, feature = "_bench_unstable", not(feature = "no-std")))] -mod benches { +#[cfg(ldk_bench)] +pub mod benches { use super::*; use crate::sign::{EntropySource, KeysManager}; use crate::ln::channelmanager; @@ -6216,60 +6391,63 @@ mod benches { use crate::util::logger::{Logger, Record}; use crate::util::test_utils::TestLogger; - use test::Bencher; + use criterion::Criterion; struct DummyLogger {} impl Logger for DummyLogger { fn log(&self, _record: &Record) {} } - - #[bench] - fn generate_routes_with_zero_penalty_scorer(bench: &mut Bencher) { + 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(); let scorer = FixedPenaltyScorer::with_penalty(0); - generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty(), 0); + generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty(), 0, + "generate_routes_with_zero_penalty_scorer"); } - #[bench] - fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Bencher) { + pub fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Criterion) { let logger = TestLogger::new(); let network_graph = bench_utils::read_network_graph(&logger).unwrap(); let scorer = FixedPenaltyScorer::with_penalty(0); - generate_routes(bench, &network_graph, scorer, &(), channelmanager::provided_invoice_features(&UserConfig::default()), 0); + generate_routes(bench, &network_graph, scorer, &(), + channelmanager::provided_invoice_features(&UserConfig::default()), 0, + "generate_mpp_routes_with_zero_penalty_scorer"); } - #[bench] - fn generate_routes_with_probabilistic_scorer(bench: &mut Bencher) { + pub fn generate_routes_with_probabilistic_scorer(bench: &mut Criterion) { let logger = TestLogger::new(); let network_graph = bench_utils::read_network_graph(&logger).unwrap(); let params = ProbabilisticScoringFeeParameters::default(); let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger); - generate_routes(bench, &network_graph, scorer, ¶ms, InvoiceFeatures::empty(), 0); + generate_routes(bench, &network_graph, scorer, ¶ms, InvoiceFeatures::empty(), 0, + "generate_routes_with_probabilistic_scorer"); } - #[bench] - fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) { + pub fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Criterion) { let logger = TestLogger::new(); let network_graph = bench_utils::read_network_graph(&logger).unwrap(); let params = ProbabilisticScoringFeeParameters::default(); let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger); - generate_routes(bench, &network_graph, scorer, ¶ms, channelmanager::provided_invoice_features(&UserConfig::default()), 0); + generate_routes(bench, &network_graph, scorer, ¶ms, + channelmanager::provided_invoice_features(&UserConfig::default()), 0, + "generate_mpp_routes_with_probabilistic_scorer"); } - #[bench] - fn generate_large_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) { + pub fn generate_large_mpp_routes_with_probabilistic_scorer(bench: &mut Criterion) { let logger = TestLogger::new(); let network_graph = bench_utils::read_network_graph(&logger).unwrap(); let params = ProbabilisticScoringFeeParameters::default(); let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger); - generate_routes(bench, &network_graph, scorer, ¶ms, channelmanager::provided_invoice_features(&UserConfig::default()), 100_000_000); + generate_routes(bench, &network_graph, scorer, ¶ms, + channelmanager::provided_invoice_features(&UserConfig::default()), 100_000_000, + "generate_large_mpp_routes_with_probabilistic_scorer"); } fn generate_routes( - bench: &mut Bencher, graph: &NetworkGraph<&TestLogger>, mut scorer: S, + bench: &mut Criterion, graph: &NetworkGraph<&TestLogger>, mut scorer: S, score_params: &S::ScoreParams, features: InvoiceFeatures, starting_amount: u64, + bench_name: &'static str, ) { let payer = bench_utils::payer_pubkey(); let keys_manager = KeysManager::new(&[0u8; 32], 42, 42); @@ -6280,11 +6458,11 @@ mod benches { // ...then benchmark finding paths between the nodes we learned. let mut idx = 0; - bench.iter(|| { + bench.bench_function(bench_name, |b| b.iter(|| { let (first_hop, params, amt) = &route_endpoints[idx % route_endpoints.len()]; assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, score_params, &random_seed_bytes).is_ok()); idx += 1; - }); + })); } }