@@ -706,10 +706,17 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
706
706
let amt = directed_info. effective_capacity ( ) . as_msat ( ) ;
707
707
let dir_liq = liq. as_directed ( source, target, 0 , amt, self . decay_params ) ;
708
708
709
- let ( min_buckets , max_buckets , _ ) = dir_liq. liquidity_history
709
+ let decayed_buckets = dir_liq. liquidity_history
710
710
. get_decayed_buckets ( now, * dir_liq. last_updated ,
711
711
self . decay_params . historical_no_updates_half_life ) ;
712
712
713
+ let ( min_buckets, max_buckets, _, _) =
714
+ if let Some ( buckets) = decayed_buckets { buckets } else {
715
+ // If the buckets, once decayed, end up being zero, print them out
716
+ // as zeros.
717
+ ( [ 0 ; 32 ] , [ 0 ; 32 ] , 0 , 0 )
718
+ } ;
719
+
713
720
log_debug ! ( self . logger, core:: concat!(
714
721
"Liquidity from {} to {} via {} is in the range ({}, {}).\n " ,
715
722
"\t Historical min liquidity bucket relative probabilities:\n " ,
@@ -787,7 +794,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
787
794
/// in the top and bottom bucket, and roughly with similar (recent) frequency.
788
795
///
789
796
/// Because the datapoints are decayed slowly over time, values will eventually return to
790
- /// `Some(([0 ; 32], [0 ; 32]))`.
797
+ /// `Some(([1 ; 32], [1 ; 32]))` and then to `None` once no datapoints remain .
791
798
///
792
799
/// In order to fetch a single success probability from the buckets provided here, as used in
793
800
/// the scoring model, see [`Self::historical_estimated_payment_success_probability`].
@@ -801,9 +808,12 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
801
808
let amt = directed_info. effective_capacity ( ) . as_msat ( ) ;
802
809
let dir_liq = liq. as_directed ( source, target, 0 , amt, self . decay_params ) ;
803
810
804
- let ( min_buckets, mut max_buckets, _) = dir_liq. liquidity_history
805
- . get_decayed_buckets ( dir_liq. now , * dir_liq. last_updated ,
806
- self . decay_params . historical_no_updates_half_life ) ;
811
+ let ( min_buckets, mut max_buckets, valid_points, required_decays) =
812
+ dir_liq. liquidity_history . get_decayed_buckets (
813
+ dir_liq. now , * dir_liq. last_updated ,
814
+ self . decay_params . historical_no_updates_half_life
815
+ ) ?;
816
+
807
817
// Note that the liquidity buckets are an offset from the edge, so we inverse
808
818
// the max order to get the probabilities from zero.
809
819
max_buckets. reverse ( ) ;
@@ -1740,15 +1750,29 @@ mod bucketed_history {
1740
1750
impl < D : Deref < Target = HistoricalBucketRangeTracker > > HistoricalMinMaxBuckets < D > {
1741
1751
#[ inline]
1742
1752
pub ( super ) fn get_decayed_buckets < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
1743
- -> ( [ u16 ; 32 ] , [ u16 ; 32 ] , u32 ) {
1753
+ -> Option < ( [ u16 ; 32 ] , [ u16 ; 32 ] , u64 , u32 ) > {
1744
1754
let required_decays = now. duration_since ( last_updated) . as_secs ( )
1745
1755
. checked_div ( half_life. as_secs ( ) )
1746
1756
. map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
1757
+
1758
+ let mut total_valid_points_tracked = 0 ;
1759
+ for ( min_idx, min_bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
1760
+ for max_bucket in self . max_liquidity_offset_history . buckets . iter ( ) . take ( 32 - min_idx) {
1761
+ total_valid_points_tracked += ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
1762
+ }
1763
+ }
1764
+
1765
+ // If the total valid points is smaller than 1.0 (i.e. 32 in our fixed-point scheme),
1766
+ // treat it as if we were fully decayed.
1767
+ if total_valid_points_tracked. checked_shr ( required_decays) . unwrap_or ( 0 ) < 32 * 32 {
1768
+ return None ;
1769
+ }
1770
+
1747
1771
let mut min_buckets = * self . min_liquidity_offset_history ;
1748
1772
min_buckets. time_decay_data ( required_decays) ;
1749
1773
let mut max_buckets = * self . max_liquidity_offset_history ;
1750
1774
max_buckets. time_decay_data ( required_decays) ;
1751
- ( min_buckets. buckets , max_buckets. buckets , required_decays)
1775
+ Some ( ( min_buckets. buckets , max_buckets. buckets , total_valid_points_tracked , required_decays) )
1752
1776
}
1753
1777
1754
1778
#[ inline]
@@ -1762,29 +1786,13 @@ mod bucketed_history {
1762
1786
// state). For each pair, we calculate the probability as if the bucket's corresponding
1763
1787
// min- and max- liquidity bounds were our current liquidity bounds and then multiply
1764
1788
// that probability by the weight of the selected buckets.
1765
- let mut total_valid_points_tracked = 0 ;
1766
-
1767
1789
let payment_pos = amount_to_pos ( amount_msat, capacity_msat) ;
1768
1790
if payment_pos >= POSITION_TICKS { return None ; }
1769
1791
1770
1792
// Check if all our buckets are zero, once decayed and treat it as if we had no data. We
1771
1793
// don't actually use the decayed buckets, though, as that would lose precision.
1772
- let ( decayed_min_buckets, decayed_max_buckets, required_decays) =
1773
- self . get_decayed_buckets ( now, last_updated, half_life) ;
1774
- if decayed_min_buckets. iter ( ) . all ( |v| * v == 0 ) || decayed_max_buckets. iter ( ) . all ( |v| * v == 0 ) {
1775
- return None ;
1776
- }
1777
-
1778
- for ( min_idx, min_bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
1779
- for max_bucket in self . max_liquidity_offset_history . buckets . iter ( ) . take ( 32 - min_idx) {
1780
- total_valid_points_tracked += ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
1781
- }
1782
- }
1783
- // If the total valid points is smaller than 1.0 (i.e. 32 in our fixed-point scheme), treat
1784
- // it as if we were fully decayed.
1785
- if total_valid_points_tracked. checked_shr ( required_decays) . unwrap_or ( 0 ) < 32 * 32 {
1786
- return None ;
1787
- }
1794
+ let ( decayed_min_buckets, decayed_max_buckets, total_valid_points_tracked, required_decays)
1795
+ = self . get_decayed_buckets ( now, last_updated, half_life) ?;
1788
1796
1789
1797
let mut cumulative_success_prob_times_billion = 0 ;
1790
1798
// Special-case the 0th min bucket - it generally means we failed a payment, so only
@@ -3107,7 +3115,7 @@ mod tests {
3107
3115
// Once fully decayed we still have data, but its all-0s. In the future we may remove the
3108
3116
// data entirely instead.
3109
3117
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3110
- Some ( ( [ 0 ; 32 ] , [ 0 ; 32 ] ) ) ) ;
3118
+ None ) ;
3111
3119
assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 ) , None ) ;
3112
3120
3113
3121
let mut usage = ChannelUsage {
0 commit comments