@@ -597,7 +597,26 @@ struct HistoricalMinMaxBuckets<'a> {
597
597
598
598
impl HistoricalMinMaxBuckets < ' _ > {
599
599
#[ inline]
600
- fn calculate_success_probability_times_billion ( & self , required_decays : u32 , payment_amt_64th_bucket : u8 ) -> Option < u64 > {
600
+ fn get_decayed_buckets < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
601
+ -> ( [ u16 ; 8 ] , [ u16 ; 8 ] , u32 ) {
602
+ let required_decays = now. duration_since ( last_updated) . as_secs ( )
603
+ . checked_div ( half_life. as_secs ( ) )
604
+ . map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
605
+ let mut min_buckets = [ 0 ; 8 ] ;
606
+ for ( idx, bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
607
+ min_buckets[ idx] = ( * bucket) . checked_shr ( required_decays) . unwrap_or ( 0 ) ;
608
+ }
609
+ let mut max_buckets = [ 0 ; 8 ] ;
610
+ for ( idx, bucket) in self . max_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
611
+ max_buckets[ idx] = ( * bucket) . checked_shr ( required_decays) . unwrap_or ( 0 ) ;
612
+ }
613
+ ( min_buckets, max_buckets, required_decays)
614
+ }
615
+
616
+ #[ inline]
617
+ fn calculate_success_probability_times_billion < T : Time > (
618
+ & self , now : T , last_updated : T , half_life : Duration , payment_amt_64th_bucket : u8 )
619
+ -> Option < u64 > {
601
620
// If historical penalties are enabled, calculate the penalty by walking the set of
602
621
// historical liquidity bucket (min, max) combinations (where min_idx < max_idx) and, for
603
622
// each, calculate the probability of success given our payment amount, then total the
@@ -619,23 +638,22 @@ impl HistoricalMinMaxBuckets<'_> {
619
638
// less than 1/16th of a channel's capacity, or 1/8th if we used the top of the bucket.
620
639
let mut total_valid_points_tracked = 0 ;
621
640
622
- // Rather than actually decaying the individual buckets, which would lose precision, we
623
- // simply track whether all buckets would be decayed to zero, in which case we treat it as
624
- // if we had no data.
625
- let mut is_fully_decayed = true ;
626
- let mut check_track_bucket_contains_undecayed_points =
627
- |bucket_val : u16 | if bucket_val. checked_shr ( required_decays) . unwrap_or ( 0 ) > 0 { is_fully_decayed = false ; } ;
641
+ // Check if all our buckets are zero, once decayed and treat it as if we had no data. We
642
+ // don't actually use the decayed buckets, though, as that would lose precision.
643
+ let ( decayed_min_buckets, decayed_max_buckets, required_decays) =
644
+ self . get_decayed_buckets ( now, last_updated, half_life) ;
645
+ if decayed_min_buckets. iter ( ) . all ( |v| * v == 0 ) || decayed_max_buckets. iter ( ) . all ( |v| * v == 0 ) {
646
+ return None ;
647
+ }
628
648
629
649
for ( min_idx, min_bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
630
- check_track_bucket_contains_undecayed_points ( * min_bucket) ;
631
650
for max_bucket in self . max_liquidity_offset_history . buckets . iter ( ) . take ( 8 - min_idx) {
632
651
total_valid_points_tracked += ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
633
- check_track_bucket_contains_undecayed_points ( * max_bucket) ;
634
652
}
635
653
}
636
654
// If the total valid points is smaller than 1.0 (i.e. 32 in our fixed-point scheme), treat
637
655
// it as if we were fully decayed.
638
- if total_valid_points_tracked. checked_shr ( required_decays) . unwrap_or ( 0 ) < 32 * 32 || is_fully_decayed {
656
+ if total_valid_points_tracked. checked_shr ( required_decays) . unwrap_or ( 0 ) < 32 * 32 {
639
657
return None ;
640
658
}
641
659
@@ -942,9 +960,6 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
942
960
943
961
if params. historical_liquidity_penalty_multiplier_msat != 0 ||
944
962
params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
945
- let required_decays = self . now . duration_since ( * self . last_updated ) . as_secs ( )
946
- . checked_div ( params. historical_no_updates_half_life . as_secs ( ) )
947
- . map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
948
963
let payment_amt_64th_bucket = amount_msat * 64 / self . capacity_msat ;
949
964
debug_assert ! ( payment_amt_64th_bucket <= 64 ) ;
950
965
if payment_amt_64th_bucket > 64 { return res; }
@@ -954,7 +969,9 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
954
969
max_liquidity_offset_history : & self . max_liquidity_offset_history ,
955
970
} ;
956
971
if let Some ( cumulative_success_prob_times_billion) = buckets
957
- . calculate_success_probability_times_billion ( required_decays, payment_amt_64th_bucket as u8 ) {
972
+ . calculate_success_probability_times_billion ( self . now , * self . last_updated ,
973
+ params. historical_no_updates_half_life , payment_amt_64th_bucket as u8 )
974
+ {
958
975
let historical_negative_log10_times_2048 = approx:: negative_log10_times_2048 ( cumulative_success_prob_times_billion + 1 , 1024 * 1024 * 1024 ) ;
959
976
res = res. saturating_add ( Self :: combined_penalty_msat ( amount_msat,
960
977
historical_negative_log10_times_2048, params. historical_liquidity_penalty_multiplier_msat ,
0 commit comments