Skip to content

Commit eb73332

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 b2936c4 commit eb73332

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
@@ -830,6 +830,9 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
830830
///
831831
/// Because the datapoints are decayed slowly over time, values will eventually return to
832832
/// `Some(([0; 8], [0; 8]))`.
833+
///
834+
/// In order to convert this into a success probability, as used in the scoring model, see
835+
/// [`Self::historical_estimated_payment_success_probability`].
833836
pub fn historical_estimated_channel_liquidity_probabilities(&self, scid: u64, target: &NodeId)
834837
-> Option<([u16; 8], [u16; 8])> {
835838
let graph = self.network_graph.read_only();
@@ -856,6 +859,38 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
856859
None
857860
}
858861

862+
/// Query the probability of payment success (times 2^30) sending the given `amount_msat` over
863+
/// the channel with `scid` towards the given `target` node, based on the historical estimated
864+
/// liquidity bounds.
865+
///
866+
/// These are the same bounds as returned by
867+
/// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by
868+
/// [`Self::estimated_channel_liquidity_range`]).
869+
pub fn historical_estimated_payment_success_probability(
870+
&self, scid: u64, target: &NodeId, amount_msat: u64)
871+
-> Option<u64> {
872+
let graph = self.network_graph.read_only();
873+
874+
if let Some(chan) = graph.channels().get(&scid) {
875+
if let Some(liq) = self.channel_liquidities.get(&scid) {
876+
if let Some((directed_info, source)) = chan.as_directed_to(target) {
877+
let amt = directed_info.effective_capacity().as_msat();
878+
let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
879+
880+
let buckets = HistoricalMinMaxBuckets {
881+
min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
882+
max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
883+
};
884+
885+
return buckets.calculate_success_probability_times_billion(T::now(),
886+
*dir_liq.last_updated, self.params.historical_no_updates_half_life,
887+
amount_msat, directed_info.effective_capacity().as_msat());
888+
}
889+
}
890+
}
891+
None
892+
}
893+
859894
/// Marks the node with the given `node_id` as banned, i.e.,
860895
/// it will be avoided during path finding.
861896
pub fn add_banned(&mut self, node_id: &NodeId) {
@@ -2786,13 +2821,19 @@ mod tests {
27862821
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
27872822
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
27882823
None);
2824+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 42),
2825+
None);
27892826

27902827
scorer.payment_path_failed(&payment_path_for_amount(1).iter().collect::<Vec<_>>(), 42);
27912828
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2048);
27922829
// The "it failed" increment is 32, where the probability should lie fully in the first
27932830
// octile.
27942831
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
27952832
Some(([32, 0, 0, 0, 0, 0, 0, 0], [32, 0, 0, 0, 0, 0, 0, 0])));
2833+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1),
2834+
Some(1024 * 1024 * 1024));
2835+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 500),
2836+
Some(0));
27962837

27972838
// Even after we tell the scorer we definitely have enough available liquidity, it will
27982839
// still remember that there was some failure in the past, and assign a non-0 penalty.
@@ -2802,6 +2843,17 @@ mod tests {
28022843
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28032844
Some(([31, 0, 0, 0, 0, 0, 0, 32], [31, 0, 0, 0, 0, 0, 0, 32])));
28042845

2846+
// The exact success probability is a bit complicated and involves integer rounding, so we
2847+
// simply check bounds here.
2848+
let five_hundred_prob =
2849+
scorer.historical_estimated_payment_success_probability(42, &target, 500).unwrap();
2850+
assert!(five_hundred_prob > 512 * 1024 * 1024); // 0.5
2851+
assert!(five_hundred_prob < 532 * 1024 * 1024); // ~ 0.52
2852+
let one_prob =
2853+
scorer.historical_estimated_payment_success_probability(42, &target, 1).unwrap();
2854+
assert!(one_prob < 1024 * 1024 * 1024);
2855+
assert!(one_prob > 1023 * 1024 * 1024);
2856+
28052857
// Advance the time forward 16 half-lives (which the docs claim will ensure all data is
28062858
// gone), and check that we're back to where we started.
28072859
SinceEpoch::advance(Duration::from_secs(10 * 16));
@@ -2810,6 +2862,7 @@ mod tests {
28102862
// data entirely instead.
28112863
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
28122864
Some(([0; 8], [0; 8])));
2865+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1), None);
28132866

28142867
let usage = ChannelUsage {
28152868
amount_msat: 100,

0 commit comments

Comments
 (0)