@@ -806,11 +806,14 @@ struct ChannelLiquidity<T: Time> {
806806 /// Upper channel liquidity bound in terms of an offset from the effective capacity.
807807 max_liquidity_offset_msat : u64 ,
808808
809+ min_liquidity_offset_history : HistoricalBucketRangeTracker ,
810+ max_liquidity_offset_history : HistoricalBucketRangeTracker ,
811+
809812 /// Time when the liquidity bounds were last modified.
810813 last_updated : T ,
811814
812- min_liquidity_offset_history : HistoricalBucketRangeTracker ,
813- max_liquidity_offset_history : HistoricalBucketRangeTracker ,
815+ /// Time when the historical liquidity bounds were last modified.
816+ offset_history_last_updated : T ,
814817}
815818
816819/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
@@ -821,6 +824,7 @@ struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = Hist
821824 liquidity_history : HistoricalMinMaxBuckets < BRT > ,
822825 capacity_msat : u64 ,
823826 last_updated : U ,
827+ offset_history_last_updated : U ,
824828 now : T ,
825829 decay_params : ProbabilisticScoringDecayParameters ,
826830}
@@ -859,7 +863,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
859863 let dir_liq = liq. as_directed ( source, target, amt, self . decay_params ) ;
860864
861865 let ( min_buckets, max_buckets) = dir_liq. liquidity_history
862- . get_decayed_buckets ( now, * dir_liq. last_updated ,
866+ . get_decayed_buckets ( now, * dir_liq. offset_history_last_updated ,
863867 self . decay_params . historical_no_updates_half_life )
864868 . unwrap_or ( ( [ 0 ; 32 ] , [ 0 ; 32 ] ) ) ;
865869
@@ -956,7 +960,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
956960
957961 let ( min_buckets, mut max_buckets) =
958962 dir_liq. liquidity_history . get_decayed_buckets (
959- dir_liq. now , * dir_liq. last_updated ,
963+ dir_liq. now , * dir_liq. offset_history_last_updated ,
960964 self . decay_params . historical_no_updates_half_life
961965 ) ?;
962966
@@ -989,7 +993,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
989993 let dir_liq = liq. as_directed ( source, target, capacity_msat, self . decay_params ) ;
990994
991995 return dir_liq. liquidity_history . calculate_success_probability_times_billion (
992- dir_liq. now , * dir_liq. last_updated ,
996+ dir_liq. now , * dir_liq. offset_history_last_updated ,
993997 self . decay_params . historical_no_updates_half_life , & params, amount_msat,
994998 capacity_msat
995999 ) . map ( |p| p as f64 / ( 1024 * 1024 * 1024 ) as f64 ) ;
@@ -1009,6 +1013,7 @@ impl<T: Time> ChannelLiquidity<T> {
10091013 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
10101014 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
10111015 last_updated : T :: now ( ) ,
1016+ offset_history_last_updated : T :: now ( ) ,
10121017 }
10131018 }
10141019
@@ -1035,6 +1040,7 @@ impl<T: Time> ChannelLiquidity<T> {
10351040 } ,
10361041 capacity_msat,
10371042 last_updated : & self . last_updated ,
1043+ offset_history_last_updated : & self . offset_history_last_updated ,
10381044 now : T :: now ( ) ,
10391045 decay_params : decay_params,
10401046 }
@@ -1063,6 +1069,7 @@ impl<T: Time> ChannelLiquidity<T> {
10631069 } ,
10641070 capacity_msat,
10651071 last_updated : & mut self . last_updated ,
1072+ offset_history_last_updated : & mut self . offset_history_last_updated ,
10661073 now : T :: now ( ) ,
10671074 decay_params : decay_params,
10681075 }
@@ -1198,7 +1205,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
11981205 if score_params. historical_liquidity_penalty_multiplier_msat != 0 ||
11991206 score_params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
12001207 if let Some ( cumulative_success_prob_times_billion) = self . liquidity_history
1201- . calculate_success_probability_times_billion ( self . now , * self . last_updated ,
1208+ . calculate_success_probability_times_billion (
1209+ self . now , * self . offset_history_last_updated ,
12021210 self . decay_params . historical_no_updates_half_life , score_params, amount_msat,
12031211 self . capacity_msat )
12041212 {
@@ -1317,7 +1325,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13171325 /// state"), we allow the caller to set an offset applied to our liquidity bounds which
13181326 /// represents the amount of the successful payment we just made.
13191327 fn update_history_buckets ( & mut self , bucket_offset_msat : u64 ) {
1320- let half_lives = self . now . duration_since ( * self . last_updated ) . as_secs ( )
1328+ let half_lives = self . now . duration_since ( * self . offset_history_last_updated ) . as_secs ( )
13211329 . checked_div ( self . decay_params . historical_no_updates_half_life . as_secs ( ) )
13221330 . map ( |v| v. try_into ( ) . unwrap_or ( u32:: max_value ( ) ) ) . unwrap_or ( u32:: max_value ( ) ) ;
13231331 self . liquidity_history . min_liquidity_offset_history . time_decay_data ( half_lives) ;
@@ -1342,6 +1350,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13421350 self . decayed_offset_msat ( * self . max_liquidity_offset_msat )
13431351 } ;
13441352 * self . last_updated = self . now ;
1353+ * self . offset_history_last_updated = self . now ;
13451354 }
13461355
13471356 /// Adjusts the upper bound of the channel liquidity balance in this direction.
@@ -1353,6 +1362,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13531362 self . decayed_offset_msat ( * self . min_liquidity_offset_msat )
13541363 } ;
13551364 * self . last_updated = self . now ;
1365+ * self . offset_history_last_updated = self . now ;
13561366 }
13571367}
13581368
@@ -1977,9 +1987,9 @@ mod bucketed_history {
19771987 }
19781988
19791989 impl < D : Deref < Target = HistoricalBucketRangeTracker > > HistoricalMinMaxBuckets < D > {
1980- pub ( super ) fn get_decayed_buckets < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
1990+ pub ( super ) fn get_decayed_buckets < T : Time > ( & self , now : T , offset_history_last_updated : T , half_life : Duration )
19811991 -> Option < ( [ u16 ; 32 ] , [ u16 ; 32 ] ) > {
1982- let ( _, required_decays) = self . get_total_valid_points ( now, last_updated , half_life) ?;
1992+ let ( _, required_decays) = self . get_total_valid_points ( now, offset_history_last_updated , half_life) ?;
19831993
19841994 let mut min_buckets = * self . min_liquidity_offset_history ;
19851995 min_buckets. time_decay_data ( required_decays) ;
@@ -1988,9 +1998,9 @@ mod bucketed_history {
19881998 Some ( ( min_buckets. buckets , max_buckets. buckets ) )
19891999 }
19902000 #[ inline]
1991- pub ( super ) fn get_total_valid_points < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
2001+ pub ( super ) fn get_total_valid_points < T : Time > ( & self , now : T , offset_history_last_updated : T , half_life : Duration )
19922002 -> Option < ( u64 , u32 ) > {
1993- let required_decays = now. duration_since ( last_updated ) . as_secs ( )
2003+ let required_decays = now. duration_since ( offset_history_last_updated ) . as_secs ( )
19942004 . checked_div ( half_life. as_secs ( ) )
19952005 . map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
19962006
@@ -2013,7 +2023,7 @@ mod bucketed_history {
20132023
20142024 #[ inline]
20152025 pub ( super ) fn calculate_success_probability_times_billion < T : Time > (
2016- & self , now : T , last_updated : T , half_life : Duration ,
2026+ & self , now : T , offset_history_last_updated : T , half_life : Duration ,
20172027 params : & ProbabilisticScoringFeeParameters , amount_msat : u64 , capacity_msat : u64
20182028 ) -> Option < u64 > {
20192029 // If historical penalties are enabled, we try to calculate a probability of success
@@ -2029,7 +2039,7 @@ mod bucketed_history {
20292039 // Check if all our buckets are zero, once decayed and treat it as if we had no data. We
20302040 // don't actually use the decayed buckets, though, as that would lose precision.
20312041 let ( total_valid_points_tracked, _)
2032- = self . get_total_valid_points ( now, last_updated , half_life) ?;
2042+ = self . get_total_valid_points ( now, offset_history_last_updated , half_life) ?;
20332043
20342044 let mut cumulative_success_prob_times_billion = 0 ;
20352045 // Special-case the 0th min bucket - it generally means we failed a payment, so only
@@ -2122,6 +2132,8 @@ ReadableArgs<(ProbabilisticScoringDecayParameters, G, L)> for ProbabilisticScore
21222132impl < T : Time > Writeable for ChannelLiquidity < T > {
21232133 #[ inline]
21242134 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
2135+ let offset_history_duration_since_epoch =
2136+ T :: duration_since_epoch ( ) - self . offset_history_last_updated . elapsed ( ) ;
21252137 let duration_since_epoch = T :: duration_since_epoch ( ) - self . last_updated . elapsed ( ) ;
21262138 write_tlv_fields ! ( w, {
21272139 ( 0 , self . min_liquidity_offset_msat, required) ,
@@ -2131,6 +2143,7 @@ impl<T: Time> Writeable for ChannelLiquidity<T> {
21312143 ( 4 , duration_since_epoch, required) ,
21322144 ( 5 , Some ( self . min_liquidity_offset_history) , option) ,
21332145 ( 7 , Some ( self . max_liquidity_offset_history) , option) ,
2146+ ( 9 , offset_history_duration_since_epoch, required) ,
21342147 } ) ;
21352148 Ok ( ( ) )
21362149 }
@@ -2146,6 +2159,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21462159 let mut min_liquidity_offset_history: Option < HistoricalBucketRangeTracker > = None ;
21472160 let mut max_liquidity_offset_history: Option < HistoricalBucketRangeTracker > = None ;
21482161 let mut duration_since_epoch = Duration :: from_secs ( 0 ) ;
2162+ let mut offset_history_duration_since_epoch = None ;
21492163 read_tlv_fields ! ( r, {
21502164 ( 0 , min_liquidity_offset_msat, required) ,
21512165 ( 1 , legacy_min_liq_offset_history, option) ,
@@ -2154,6 +2168,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21542168 ( 4 , duration_since_epoch, required) ,
21552169 ( 5 , min_liquidity_offset_history, option) ,
21562170 ( 7 , max_liquidity_offset_history, option) ,
2171+ ( 9 , offset_history_duration_since_epoch, option) ,
21572172 } ) ;
21582173 // On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
21592174 // We write `last_updated` as wallclock time even though its ultimately an `Instant` (which
@@ -2167,6 +2182,13 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21672182 let last_updated = if wall_clock_now > duration_since_epoch {
21682183 now - ( wall_clock_now - duration_since_epoch)
21692184 } else { now } ;
2185+
2186+ let offset_history_duration_since_epoch =
2187+ offset_history_duration_since_epoch. unwrap_or ( duration_since_epoch) ;
2188+ let offset_history_last_updated = if wall_clock_now > offset_history_duration_since_epoch {
2189+ now - ( wall_clock_now - duration_since_epoch)
2190+ } else { now } ;
2191+
21702192 if min_liquidity_offset_history. is_none ( ) {
21712193 if let Some ( legacy_buckets) = legacy_min_liq_offset_history {
21722194 min_liquidity_offset_history = Some ( legacy_buckets. into_current ( ) ) ;
@@ -2187,6 +2209,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21872209 min_liquidity_offset_history : min_liquidity_offset_history. unwrap ( ) ,
21882210 max_liquidity_offset_history : max_liquidity_offset_history. unwrap ( ) ,
21892211 last_updated,
2212+ offset_history_last_updated,
21902213 } )
21912214 }
21922215}
@@ -2366,18 +2389,21 @@ mod tests {
23662389 fn liquidity_bounds_directed_from_lowest_node_id ( ) {
23672390 let logger = TestLogger :: new ( ) ;
23682391 let last_updated = SinceEpoch :: now ( ) ;
2392+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
23692393 let network_graph = network_graph ( & logger) ;
23702394 let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
23712395 let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
23722396 . with_channel ( 42 ,
23732397 ChannelLiquidity {
2374- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
2398+ min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 ,
2399+ last_updated, offset_history_last_updated,
23752400 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23762401 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23772402 } )
23782403 . with_channel ( 43 ,
23792404 ChannelLiquidity {
2380- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
2405+ min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 ,
2406+ last_updated, offset_history_last_updated,
23812407 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23822408 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23832409 } ) ;
@@ -2444,12 +2470,14 @@ mod tests {
24442470 fn resets_liquidity_upper_bound_when_crossed_by_lower_bound ( ) {
24452471 let logger = TestLogger :: new ( ) ;
24462472 let last_updated = SinceEpoch :: now ( ) ;
2473+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
24472474 let network_graph = network_graph ( & logger) ;
24482475 let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
24492476 let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
24502477 . with_channel ( 42 ,
24512478 ChannelLiquidity {
2452- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
2479+ min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 ,
2480+ last_updated, offset_history_last_updated,
24532481 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
24542482 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
24552483 } ) ;
@@ -2503,12 +2531,14 @@ mod tests {
25032531 fn resets_liquidity_lower_bound_when_crossed_by_upper_bound ( ) {
25042532 let logger = TestLogger :: new ( ) ;
25052533 let last_updated = SinceEpoch :: now ( ) ;
2534+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
25062535 let network_graph = network_graph ( & logger) ;
25072536 let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
25082537 let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
25092538 . with_channel ( 42 ,
25102539 ChannelLiquidity {
2511- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
2540+ min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 ,
2541+ last_updated, offset_history_last_updated,
25122542 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
25132543 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
25142544 } ) ;
@@ -2608,6 +2638,7 @@ mod tests {
26082638 fn constant_penalty_outside_liquidity_bounds ( ) {
26092639 let logger = TestLogger :: new ( ) ;
26102640 let last_updated = SinceEpoch :: now ( ) ;
2641+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
26112642 let network_graph = network_graph ( & logger) ;
26122643 let params = ProbabilisticScoringFeeParameters {
26132644 liquidity_penalty_multiplier_msat : 1_000 ,
@@ -2620,7 +2651,8 @@ mod tests {
26202651 let scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
26212652 . with_channel ( 42 ,
26222653 ChannelLiquidity {
2623- min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 , last_updated,
2654+ min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 ,
2655+ last_updated, offset_history_last_updated,
26242656 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
26252657 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
26262658 } ) ;
0 commit comments