Skip to content

Commit 8ff586e

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 a14fcf3 commit 8ff586e

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

lightning/src/routing/scoring.rs

Lines changed: 53 additions & 0 deletions
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 convert this into a success probability, as used in the scoring model, see
944+
/// [`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();
@@ -964,6 +967,38 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
964967
}
965968
None
966969
}
970+
971+
/// Query the probability of payment success (times 2^30) sending the given `amount_msat` over
972+
/// the channel with `scid` towards the given `target` node, based on the historical estimated
973+
/// liquidity 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<u64> {
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 cap = directed_info.effective_capacity().as_msat();
987+
let dir_liq = liq.as_directed(source, target, 0, cap, 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(T::now(),
995+
*dir_liq.last_updated, self.decay_params.historical_no_updates_half_life,
996+
amount_msat, directed_info.effective_capacity().as_msat());
997+
}
998+
}
999+
}
1000+
None
1001+
}
9671002
}
9681003

9691004
impl<T: Time> ChannelLiquidity<T> {
@@ -2847,13 +2882,19 @@ mod tests {
28472882
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 47);
28482883
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28492884
None);
2885+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 42),
2886+
None);
28502887

28512888
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
28522889
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2048);
28532890
// The "it failed" increment is 32, where the probability should lie fully in the first
28542891
// octile.
28552892
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28562893
Some(([32, 0, 0, 0, 0, 0, 0, 0], [32, 0, 0, 0, 0, 0, 0, 0])));
2894+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1),
2895+
Some(1024 * 1024 * 1024));
2896+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 500),
2897+
Some(0));
28572898

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

2907+
// The exact success probability is a bit complicated and involves integer rounding, so we
2908+
// simply check bounds here.
2909+
let five_hundred_prob =
2910+
scorer.historical_estimated_payment_success_probability(42, &target, 500).unwrap();
2911+
assert!(five_hundred_prob > 512 * 1024 * 1024); // 0.5
2912+
assert!(five_hundred_prob < 532 * 1024 * 1024); // ~ 0.52
2913+
let one_prob =
2914+
scorer.historical_estimated_payment_success_probability(42, &target, 1).unwrap();
2915+
assert!(one_prob < 1024 * 1024 * 1024);
2916+
assert!(one_prob > 1023 * 1024 * 1024);
2917+
28662918
// Advance the time forward 16 half-lives (which the docs claim will ensure all data is
28672919
// gone), and check that we're back to where we started.
28682920
SinceEpoch::advance(Duration::from_secs(10 * 16));
@@ -2871,6 +2923,7 @@ mod tests {
28712923
// data entirely instead.
28722924
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28732925
Some(([0; 8], [0; 8])));
2926+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1), None);
28742927

28752928
let mut usage = ChannelUsage {
28762929
amount_msat: 100,

0 commit comments

Comments
 (0)