@@ -719,7 +719,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
719
719
min_liquidity_offset_history : & dir_liq. min_liquidity_offset_history ,
720
720
max_liquidity_offset_history : & dir_liq. max_liquidity_offset_history ,
721
721
} ;
722
- let ( min_buckets, max_buckets, _) = buckets. get_decayed_buckets ( now,
722
+ let ( min_buckets, max_buckets, _, _ ) = buckets. get_decayed_buckets ( now,
723
723
* dir_liq. last_updated , self . decay_params . historical_no_updates_half_life ) ;
724
724
725
725
log_debug ! ( self . logger, core:: concat!(
@@ -800,7 +800,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
800
800
/// in the top and bottom bucket, and roughly with similar (recent) frequency.
801
801
///
802
802
/// Because the datapoints are decayed slowly over time, values will eventually return to
803
- /// `Some(([0 ; 32], [0 ; 32]))`.
803
+ /// `Some(([1 ; 32], [1 ; 32]))` and then to `None` once no datapoints remain .
804
804
///
805
805
/// In order to convert this into a success probability, as used in the scoring model, see
806
806
/// [`Self::historical_estimated_payment_success_probability`].
@@ -818,8 +818,16 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
818
818
min_liquidity_offset_history : & dir_liq. min_liquidity_offset_history ,
819
819
max_liquidity_offset_history : & dir_liq. max_liquidity_offset_history ,
820
820
} ;
821
- let ( min_buckets, mut max_buckets, _) = buckets. get_decayed_buckets ( T :: now ( ) ,
822
- * dir_liq. last_updated , self . decay_params . historical_no_updates_half_life ) ;
821
+ let ( min_buckets, mut max_buckets, valid_points, required_decays) =
822
+ buckets. get_decayed_buckets ( T :: now ( ) , * dir_liq. last_updated ,
823
+ self . decay_params . historical_no_updates_half_life ) ;
824
+
825
+ // If the total valid points is smaller than 1.0 (i.e. 32 in our fixed-point
826
+ // scheme), treat it as if we were fully decayed.
827
+ if valid_points. checked_shr ( required_decays) . unwrap_or ( 0 ) < 32 * 32 {
828
+ return None ;
829
+ }
830
+
823
831
// Note that the liquidity buckets are an offset from the edge, so we inverse
824
832
// the max order to get the probabilities from zero.
825
833
max_buckets. reverse ( ) ;
@@ -1749,15 +1757,23 @@ mod bucketed_history {
1749
1757
impl HistoricalMinMaxBuckets < ' _ > {
1750
1758
#[ inline]
1751
1759
pub ( super ) fn get_decayed_buckets < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
1752
- -> ( [ u16 ; 32 ] , [ u16 ; 32 ] , u32 ) {
1760
+ -> ( [ u16 ; 32 ] , [ u16 ; 32 ] , u64 , u32 ) {
1753
1761
let required_decays = now. duration_since ( last_updated) . as_secs ( )
1754
1762
. checked_div ( half_life. as_secs ( ) )
1755
1763
. map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
1764
+
1765
+ let mut total_valid_points_tracked = 0 ;
1766
+ for ( min_idx, min_bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
1767
+ for max_bucket in self . max_liquidity_offset_history . buckets . iter ( ) . take ( 32 - min_idx) {
1768
+ total_valid_points_tracked += ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
1769
+ }
1770
+ }
1771
+
1756
1772
let mut min_buckets = * self . min_liquidity_offset_history ;
1757
1773
min_buckets. time_decay_data ( required_decays) ;
1758
1774
let mut max_buckets = * self . max_liquidity_offset_history ;
1759
1775
max_buckets. time_decay_data ( required_decays) ;
1760
- ( min_buckets. buckets , max_buckets. buckets , required_decays)
1776
+ ( min_buckets. buckets , max_buckets. buckets , total_valid_points_tracked , required_decays)
1761
1777
}
1762
1778
1763
1779
#[ inline]
@@ -1768,26 +1784,16 @@ mod bucketed_history {
1768
1784
// historical liquidity bucket (min, max) combinations (where min_idx < max_idx) and, for
1769
1785
// each, calculate the probability of success given our payment amount, then total the
1770
1786
// weighted average probability of success.
1771
- let mut total_valid_points_tracked = 0 ;
1772
-
1773
1787
let payment_pos = amount_to_pos ( amount_msat, capacity_msat) ;
1774
1788
#[ cfg( not( fuzzing) ) ]
1775
1789
debug_assert ! ( payment_pos <= MIN_SIZE_BUCKETS ) ; // Note that we allow the max+1 sentinel
1776
1790
if payment_pos >= MIN_SIZE_BUCKETS { return None ; }
1777
1791
1778
1792
// Check if all our buckets are zero, once decayed and treat it as if we had no data. We
1779
1793
// don't actually use the decayed buckets, though, as that would lose precision.
1780
- let ( decayed_min_buckets, decayed_max_buckets, required_decays) =
1781
- self . get_decayed_buckets ( now, last_updated, half_life) ;
1782
- if decayed_min_buckets. iter ( ) . all ( |v| * v == 0 ) || decayed_max_buckets. iter ( ) . all ( |v| * v == 0 ) {
1783
- return None ;
1784
- }
1794
+ let ( decayed_min_buckets, decayed_max_buckets, total_valid_points_tracked, required_decays)
1795
+ = self . get_decayed_buckets ( now, last_updated, half_life) ;
1785
1796
1786
- for ( min_idx, min_bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
1787
- for max_bucket in self . max_liquidity_offset_history . buckets . iter ( ) . take ( 32 - min_idx) {
1788
- total_valid_points_tracked += ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
1789
- }
1790
- }
1791
1797
// If the total valid points is smaller than 1.0 (i.e. 32 in our fixed-point scheme), treat
1792
1798
// it as if we were fully decayed.
1793
1799
if total_valid_points_tracked. checked_shr ( required_decays) . unwrap_or ( 0 ) < 32 * 32 {
@@ -3097,7 +3103,7 @@ mod tests {
3097
3103
// Once fully decayed we still have data, but its all-0s. In the future we may remove the
3098
3104
// data entirely instead.
3099
3105
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3100
- Some ( ( [ 0 ; 32 ] , [ 0 ; 32 ] ) ) ) ;
3106
+ None ) ;
3101
3107
assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 ) , None ) ;
3102
3108
3103
3109
let mut usage = ChannelUsage {
0 commit comments