Skip to content

Commit 841181e

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 61b0ab5 commit 841181e

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) {
@@ -2788,13 +2823,19 @@ mod tests {
27882823
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
27892824
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
27902825
None);
2826+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 42),
2827+
None);
27912828

27922829
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
27932830
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2048);
27942831
// The "it failed" increment is 32, where the probability should lie fully in the first
27952832
// octile.
27962833
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
27972834
Some(([32, 0, 0, 0, 0, 0, 0, 0], [32, 0, 0, 0, 0, 0, 0, 0])));
2835+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 1),
2836+
Some(1024 * 1024 * 1024));
2837+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, 500),
2838+
Some(0));
27982839

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

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

28162869
let usage = ChannelUsage {
28172870
amount_msat: 100,

0 commit comments

Comments
 (0)