Skip to content

Commit 2775902

Browse files
committed
Add an additional test/bench for routing larger amounts, score more
When benchmarking our router, we previously only ever tested with amounts under 1,000 sats, which is an incredibly small amount. While this ensures we have the maximal number of available channels to consider, it prevents our scorer from getting exercise across its range. Further, we only score the immediate path we are expecting to to send over, and not randomly but rather based on the amount sent. Here we try to make the benchmarks a bit more realistic by adding a new benchmark which attempts to send around 100K sats, which is a reasonable amount to send over a channel today. We also convert the scoring data to be randomized based on the seed as well as attempt to (possibly) find a new route for a much larger value and score based on that. This potentially allows us to score multiple potential paths between the source and destination as the large route-find may return an MPP result.
1 parent fbaa3c4 commit 2775902

File tree

1 file changed

+91
-42
lines changed

1 file changed

+91
-42
lines changed

lightning/src/routing/router.rs

Lines changed: 91 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5810,7 +5810,7 @@ mod tests {
58105810
let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
58115811
let features = super::InvoiceFeatures::empty();
58125812

5813-
super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed() as usize, 2);
5813+
super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 0, 2);
58145814
}
58155815

58165816
#[test]
@@ -5831,7 +5831,28 @@ mod tests {
58315831
let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
58325832
let features = channelmanager::provided_invoice_features(&UserConfig::default());
58335833

5834-
super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed() as usize, 2);
5834+
super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 0, 2);
5835+
}
5836+
5837+
#[test]
5838+
#[cfg(not(feature = "no-std"))]
5839+
fn generate_large_mpp_routes() {
5840+
use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
5841+
5842+
let logger = ln_test_utils::TestLogger::new();
5843+
let graph = match super::bench_utils::read_network_graph(&logger) {
5844+
Ok(f) => f,
5845+
Err(e) => {
5846+
eprintln!("{}", e);
5847+
return;
5848+
},
5849+
};
5850+
5851+
let params = ProbabilisticScoringFeeParameters::default();
5852+
let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
5853+
let features = channelmanager::provided_invoice_features(&UserConfig::default());
5854+
5855+
super::bench_utils::generate_test_routes(&graph, &mut scorer, &params, features, random_init_seed(), 1_000_000, 2);
58355856
}
58365857

58375858
#[test]
@@ -6085,11 +6106,11 @@ pub(crate) mod bench_utils {
60856106
short_channel_id: Some(1),
60866107
inbound_scid_alias: None,
60876108
outbound_scid_alias: None,
6088-
channel_value_satoshis: 10_000_000,
6109+
channel_value_satoshis: 10_000_000_000,
60896110
user_channel_id: 0,
6090-
balance_msat: 10_000_000,
6091-
outbound_capacity_msat: 10_000_000,
6092-
next_outbound_htlc_limit_msat: 10_000_000,
6111+
balance_msat: 10_000_000_000,
6112+
outbound_capacity_msat: 10_000_000_000,
6113+
next_outbound_htlc_limit_msat: 10_000_000_000,
60936114
inbound_capacity_msat: 0,
60946115
unspendable_punishment_reserve: None,
60956116
confirmations_required: None,
@@ -6107,46 +6128,65 @@ pub(crate) mod bench_utils {
61076128
}
61086129

61096130
pub(crate) fn generate_test_routes<S: Score>(graph: &NetworkGraph<&TestLogger>, scorer: &mut S,
6110-
score_params: &S::ScoreParams, features: InvoiceFeatures, mut seed: usize, route_count: usize,
6131+
score_params: &S::ScoreParams, features: InvoiceFeatures, mut seed: u64,
6132+
starting_amount: u64, route_count: usize,
61116133
) -> Vec<(ChannelDetails, PaymentParameters, u64)> {
61126134
let payer = payer_pubkey();
61136135
let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
61146136
let random_seed_bytes = keys_manager.get_secure_random_bytes();
61156137

61166138
let nodes = graph.read_only().nodes().clone();
61176139
let mut route_endpoints = Vec::new();
6118-
let mut routes = Vec::new();
6119-
6120-
'load_endpoints: for _ in 0..route_count * 3 /2 {
6140+
// Fetch 1.5x more routes than we need as after we do some scorer updates we may end up
6141+
// with some routes we picked being un-routable.
6142+
for _ in 0..route_count * 3 / 2 {
61216143
loop {
6122-
seed = seed.overflowing_mul(0xdeadbeef).0;
6123-
let src = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
6124-
seed = seed.overflowing_mul(0xdeadbeef).0;
6125-
let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
6126-
let params = PaymentParameters::from_node_id(dst, 42).with_bolt11_features(features.clone()).unwrap();
6144+
seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
6145+
let src = PublicKey::from_slice(nodes.unordered_keys()
6146+
.skip((seed as usize) % nodes.len()).next().unwrap().as_slice()).unwrap();
6147+
seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
6148+
let dst = PublicKey::from_slice(nodes.unordered_keys()
6149+
.skip((seed as usize) % nodes.len()).next().unwrap().as_slice()).unwrap();
6150+
let params = PaymentParameters::from_node_id(dst, 42)
6151+
.with_bolt11_features(features.clone()).unwrap();
61276152
let first_hop = first_hop(src);
6128-
let amt = seed as u64 % 1_000_000;
6129-
if let Ok(route) = get_route(&payer, &params, &graph.read_only(), Some(&[&first_hop]),
6130-
amt, &TestLogger::new(), &scorer, score_params, &random_seed_bytes,
6131-
) {
6132-
routes.push(route);
6133-
route_endpoints.push((first_hop, params, amt));
6134-
continue 'load_endpoints;
6135-
}
6136-
}
6137-
}
6153+
let amt = starting_amount + seed % 1_000_000;
6154+
let path_exists =
6155+
get_route(&payer, &params, &graph.read_only(), Some(&[&first_hop]),
6156+
amt, &TestLogger::new(), &scorer, score_params, &random_seed_bytes).is_ok();
6157+
if path_exists {
6158+
// ...and seed the scorer with success and failure data...
6159+
seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
6160+
let mut score_amt = seed % 1_000_000_000;
6161+
loop {
6162+
// Generate fail/success paths for a wider range of potential amounts with
6163+
// MPP enabled to give us a chance to apply penalties for more potential
6164+
// routes.
6165+
let mpp_features = channelmanager::provided_invoice_features(&UserConfig::default());
6166+
let params = PaymentParameters::from_node_id(dst, 42)
6167+
.with_bolt11_features(mpp_features).unwrap();
6168+
6169+
let route_res = get_route(&payer, &params, &graph.read_only(),
6170+
Some(&[&first_hop]), score_amt, &TestLogger::new(), &scorer,
6171+
score_params, &random_seed_bytes);
6172+
if let Ok(route) = route_res {
6173+
for path in route.paths {
6174+
if seed & 0x80 == 0 {
6175+
scorer.payment_path_successful(&path);
6176+
} else {
6177+
let short_channel_id = path.hops[path.hops.len() / 2].short_channel_id;
6178+
scorer.payment_path_failed(&path, short_channel_id);
6179+
}
6180+
seed = seed.overflowing_mul(6364136223846793005).0.overflowing_add(1).0;
6181+
}
6182+
break;
6183+
}
6184+
// If we couldn't find a path with a higer amount, reduce and try again.
6185+
score_amt /= 100;
6186+
}
61386187

6139-
// ...and seed the scorer with success and failure data...
6140-
for route in routes {
6141-
let amount = route.get_total_amount();
6142-
if amount < 250_000 {
6143-
for path in route.paths {
6144-
scorer.payment_path_successful(&path);
6145-
}
6146-
} else if amount > 750_000 {
6147-
for path in route.paths {
6148-
let short_channel_id = path.hops[path.hops.len() / 2].short_channel_id;
6149-
scorer.payment_path_failed(&path, short_channel_id);
6188+
route_endpoints.push((first_hop, params, amt));
6189+
break;
61506190
}
61516191
}
61526192
}
@@ -6189,15 +6229,15 @@ mod benches {
61896229
let logger = TestLogger::new();
61906230
let network_graph = bench_utils::read_network_graph(&logger).unwrap();
61916231
let scorer = FixedPenaltyScorer::with_penalty(0);
6192-
generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty());
6232+
generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty(), 0);
61936233
}
61946234

61956235
#[bench]
61966236
fn generate_mpp_routes_with_zero_penalty_scorer(bench: &mut Bencher) {
61976237
let logger = TestLogger::new();
61986238
let network_graph = bench_utils::read_network_graph(&logger).unwrap();
61996239
let scorer = FixedPenaltyScorer::with_penalty(0);
6200-
generate_routes(bench, &network_graph, scorer, &(), channelmanager::provided_invoice_features(&UserConfig::default()));
6240+
generate_routes(bench, &network_graph, scorer, &(), channelmanager::provided_invoice_features(&UserConfig::default()), 0);
62016241
}
62026242

62036243
#[bench]
@@ -6206,7 +6246,7 @@ mod benches {
62066246
let network_graph = bench_utils::read_network_graph(&logger).unwrap();
62076247
let params = ProbabilisticScoringFeeParameters::default();
62086248
let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
6209-
generate_routes(bench, &network_graph, scorer, &params, InvoiceFeatures::empty());
6249+
generate_routes(bench, &network_graph, scorer, &params, InvoiceFeatures::empty(), 0);
62106250
}
62116251

62126252
#[bench]
@@ -6215,19 +6255,28 @@ mod benches {
62156255
let network_graph = bench_utils::read_network_graph(&logger).unwrap();
62166256
let params = ProbabilisticScoringFeeParameters::default();
62176257
let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
6218-
generate_routes(bench, &network_graph, scorer, &params, channelmanager::provided_invoice_features(&UserConfig::default()));
6258+
generate_routes(bench, &network_graph, scorer, &params, channelmanager::provided_invoice_features(&UserConfig::default()), 0);
6259+
}
6260+
6261+
#[bench]
6262+
fn generate_large_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) {
6263+
let logger = TestLogger::new();
6264+
let network_graph = bench_utils::read_network_graph(&logger).unwrap();
6265+
let params = ProbabilisticScoringFeeParameters::default();
6266+
let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
6267+
generate_routes(bench, &network_graph, scorer, &params, channelmanager::provided_invoice_features(&UserConfig::default()), 100_000_000);
62196268
}
62206269

62216270
fn generate_routes<S: Score>(
62226271
bench: &mut Bencher, graph: &NetworkGraph<&TestLogger>, mut scorer: S,
6223-
score_params: &S::ScoreParams, features: InvoiceFeatures,
6272+
score_params: &S::ScoreParams, features: InvoiceFeatures, starting_amount: u64,
62246273
) {
62256274
let payer = bench_utils::payer_pubkey();
62266275
let keys_manager = KeysManager::new(&[0u8; 32], 42, 42);
62276276
let random_seed_bytes = keys_manager.get_secure_random_bytes();
62286277

62296278
// First, get 100 (source, destination) pairs for which route-getting actually succeeds...
6230-
let route_endpoints = bench_utils::generate_test_routes(graph, &mut scorer, score_params, features, 0xdeadbeef, 100);
6279+
let route_endpoints = bench_utils::generate_test_routes(graph, &mut scorer, score_params, features, 0xdeadbeef, starting_amount, 50);
62316280

62326281
// ...then benchmark finding paths between the nodes we learned.
62336282
let mut idx = 0;

0 commit comments

Comments
 (0)