Skip to content

Commit 534d731

Browse files
committed
Expose the historical success probability calculation itself
In 3f32f60 we exposed the historical success probability buckets directly, with a long method doc explaining how to use it. While this is great for logging exactly what the internal model thinks, its also helpful to let users know what the internal model thinks the success probability is directly, allowing them to compare route success probabilities. Here we do so but only for the historical tracking buckets.
1 parent 5687310 commit 534d731

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

lightning/src/routing/scoring.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,9 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
939939
///
940940
/// Because the datapoints are decayed slowly over time, values will eventually return to
941941
/// `Some(([0; 8], [0; 8]))`.
942+
///
943+
/// In order to fetch a single success probability from the buckets provided here, as used in
944+
/// the scoring model, see [`Self::historical_estimated_payment_success_probability`].
942945
pub fn historical_estimated_channel_liquidity_probabilities(&self, scid: u64, target: &NodeId)
943946
-> Option<([u16; 8], [u16; 8])> {
944947
let graph = self.network_graph.read_only();
@@ -953,7 +956,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
953956
min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
954957
max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
955958
};
956-
let (min_buckets, mut max_buckets, _) = buckets.get_decayed_buckets(T::now(),
959+
let (min_buckets, mut max_buckets, _) = buckets.get_decayed_buckets(dir_liq.now,
957960
*dir_liq.last_updated, self.decay_params.historical_no_updates_half_life);
958961
// Note that the liquidity buckets are an offset from the edge, so we inverse
959962
// the max order to get the probabilities from zero.
@@ -964,6 +967,39 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
964967
}
965968
None
966969
}
970+
971+
/// Query the probability of payment success sending the given `amount_msat` over the channel
972+
/// with `scid` towards the given `target` node, based on the historical estimated liquidity
973+
/// bounds.
974+
///
975+
/// These are the same bounds as returned by
976+
/// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by
977+
/// [`Self::estimated_channel_liquidity_range`]).
978+
pub fn historical_estimated_payment_success_probability(
979+
&self, scid: u64, target: &NodeId, amount_msat: u64)
980+
-> Option<f64> {
981+
let graph = self.network_graph.read_only();
982+
983+
if let Some(chan) = graph.channels().get(&scid) {
984+
if let Some(liq) = self.channel_liquidities.get(&scid) {
985+
if let Some((directed_info, source)) = chan.as_directed_to(target) {
986+
let capacity_msat = directed_info.effective_capacity().as_msat();
987+
let dir_liq = liq.as_directed(source, target, 0, capacity_msat, self.decay_params);
988+
989+
let buckets = HistoricalMinMaxBuckets {
990+
min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
991+
max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
992+
};
993+
994+
return buckets.calculate_success_probability_times_billion(dir_liq.now,
995+
*dir_liq.last_updated, self.decay_params.historical_no_updates_half_life,
996+
amount_msat, capacity_msat
997+
).map(|p| p as f64 / (1024 * 1024 * 1024) as f64);
998+
}
999+
}
1000+
}
1001+
None
1002+
}
9671003
}
9681004

9691005
impl<T: Time> ChannelLiquidity<T> {
@@ -2847,13 +2883,19 @@ mod tests {
28472883
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 47);
28482884
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28492885
None);
2886+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 42),
2887+
None);
28502888

28512889
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
28522890
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2048);
28532891
// The "it failed" increment is 32, where the probability should lie fully in the first
28542892
// octile.
28552893
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28562894
Some(([32, 0, 0, 0, 0, 0, 0, 0], [32, 0, 0, 0, 0, 0, 0, 0])));
2895+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1),
2896+
Some(1.0));
2897+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 500),
2898+
Some(0.0));
28572899

28582900
// Even after we tell the scorer we definitely have enough available liquidity, it will
28592901
// still remember that there was some failure in the past, and assign a non-0 penalty.
@@ -2863,6 +2905,17 @@ mod tests {
28632905
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28642906
Some(([31, 0, 0, 0, 0, 0, 0, 32], [31, 0, 0, 0, 0, 0, 0, 32])));
28652907

2908+
// The exact success probability is a bit complicated and involves integer rounding, so we
2909+
// simply check bounds here.
2910+
let five_hundred_prob =
2911+
scorer.historical_estimated_payment_success_probability(42, &target, 500).unwrap();
2912+
assert!(five_hundred_prob > 0.5);
2913+
assert!(five_hundred_prob < 0.52);
2914+
let one_prob =
2915+
scorer.historical_estimated_payment_success_probability(42, &target, 1).unwrap();
2916+
assert!(one_prob < 1.0);
2917+
assert!(one_prob > 0.99);
2918+
28662919
// Advance the time forward 16 half-lives (which the docs claim will ensure all data is
28672920
// gone), and check that we're back to where we started.
28682921
SinceEpoch::advance(Duration::from_secs(10 * 16));
@@ -2871,6 +2924,7 @@ mod tests {
28712924
// data entirely instead.
28722925
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28732926
Some(([0; 8], [0; 8])));
2927+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1), None);
28742928

28752929
let mut usage = ChannelUsage {
28762930
amount_msat: 100,

0 commit comments

Comments
 (0)