@@ -805,11 +805,14 @@ struct ChannelLiquidity<T: Time> {
805805 /// Upper channel liquidity bound in terms of an offset from the effective capacity.
806806 max_liquidity_offset_msat : u64 ,
807807
808+ min_liquidity_offset_history : HistoricalBucketRangeTracker ,
809+ max_liquidity_offset_history : HistoricalBucketRangeTracker ,
810+
808811 /// Time when the liquidity bounds were last modified.
809812 last_updated : T ,
810813
811- min_liquidity_offset_history : HistoricalBucketRangeTracker ,
812- max_liquidity_offset_history : HistoricalBucketRangeTracker ,
814+ /// Time when the historical liquidity bounds were last modified.
815+ offset_history_last_updated : T ,
813816}
814817
815818/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
@@ -820,6 +823,7 @@ struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = Hist
820823 liquidity_history : HistoricalMinMaxBuckets < BRT > ,
821824 capacity_msat : u64 ,
822825 last_updated : U ,
826+ offset_history_last_updated : U ,
823827 now : T ,
824828 decay_params : ProbabilisticScoringDecayParameters ,
825829}
@@ -858,7 +862,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
858862 let dir_liq = liq. as_directed ( source, target, amt, self . decay_params ) ;
859863
860864 let ( min_buckets, max_buckets) = dir_liq. liquidity_history
861- . get_decayed_buckets ( now, * dir_liq. last_updated ,
865+ . get_decayed_buckets ( now, * dir_liq. offset_history_last_updated ,
862866 self . decay_params . historical_no_updates_half_life )
863867 . unwrap_or ( ( [ 0 ; 32 ] , [ 0 ; 32 ] ) ) ;
864868
@@ -955,7 +959,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
955959
956960 let ( min_buckets, mut max_buckets) =
957961 dir_liq. liquidity_history . get_decayed_buckets (
958- dir_liq. now , * dir_liq. last_updated ,
962+ dir_liq. now , * dir_liq. offset_history_last_updated ,
959963 self . decay_params . historical_no_updates_half_life
960964 ) ?;
961965
@@ -988,7 +992,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
988992 let dir_liq = liq. as_directed ( source, target, capacity_msat, self . decay_params ) ;
989993
990994 return dir_liq. liquidity_history . calculate_success_probability_times_billion (
991- dir_liq. now , * dir_liq. last_updated ,
995+ dir_liq. now , * dir_liq. offset_history_last_updated ,
992996 self . decay_params . historical_no_updates_half_life , & params, amount_msat,
993997 capacity_msat
994998 ) . map ( |p| p as f64 / ( 1024 * 1024 * 1024 ) as f64 ) ;
@@ -1008,6 +1012,7 @@ impl<T: Time> ChannelLiquidity<T> {
10081012 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
10091013 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
10101014 last_updated : T :: now ( ) ,
1015+ offset_history_last_updated : T :: now ( ) ,
10111016 }
10121017 }
10131018
@@ -1034,6 +1039,7 @@ impl<T: Time> ChannelLiquidity<T> {
10341039 } ,
10351040 capacity_msat,
10361041 last_updated : & self . last_updated ,
1042+ offset_history_last_updated : & self . offset_history_last_updated ,
10371043 now : T :: now ( ) ,
10381044 decay_params : decay_params,
10391045 }
@@ -1062,6 +1068,7 @@ impl<T: Time> ChannelLiquidity<T> {
10621068 } ,
10631069 capacity_msat,
10641070 last_updated : & mut self . last_updated ,
1071+ offset_history_last_updated : & mut self . offset_history_last_updated ,
10651072 now : T :: now ( ) ,
10661073 decay_params : decay_params,
10671074 }
@@ -1197,7 +1204,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
11971204 if score_params. historical_liquidity_penalty_multiplier_msat != 0 ||
11981205 score_params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
11991206 if let Some ( cumulative_success_prob_times_billion) = self . liquidity_history
1200- . calculate_success_probability_times_billion ( self . now , * self . last_updated ,
1207+ . calculate_success_probability_times_billion (
1208+ self . now , * self . offset_history_last_updated ,
12011209 self . decay_params . historical_no_updates_half_life , score_params, amount_msat,
12021210 self . capacity_msat )
12031211 {
@@ -1316,7 +1324,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13161324 /// state"), we allow the caller to set an offset applied to our liquidity bounds which
13171325 /// represents the amount of the successful payment we just made.
13181326 fn update_history_buckets ( & mut self , bucket_offset_msat : u64 ) {
1319- let half_lives = self . now . duration_since ( * self . last_updated ) . as_secs ( )
1327+ let half_lives = self . now . duration_since ( * self . offset_history_last_updated ) . as_secs ( )
13201328 . checked_div ( self . decay_params . historical_no_updates_half_life . as_secs ( ) )
13211329 . map ( |v| v. try_into ( ) . unwrap_or ( u32:: max_value ( ) ) ) . unwrap_or ( u32:: max_value ( ) ) ;
13221330 self . liquidity_history . min_liquidity_offset_history . time_decay_data ( half_lives) ;
@@ -1341,6 +1349,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13411349 self . decayed_offset_msat ( * self . max_liquidity_offset_msat )
13421350 } ;
13431351 * self . last_updated = self . now ;
1352+ * self . offset_history_last_updated = self . now ;
13441353 }
13451354
13461355 /// Adjusts the upper bound of the channel liquidity balance in this direction.
@@ -1352,6 +1361,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13521361 self . decayed_offset_msat ( * self . min_liquidity_offset_msat )
13531362 } ;
13541363 * self . last_updated = self . now ;
1364+ * self . offset_history_last_updated = self . now ;
13551365 }
13561366}
13571367
@@ -1983,9 +1993,9 @@ mod bucketed_history {
19831993 }
19841994
19851995 impl < D : Deref < Target = HistoricalBucketRangeTracker > > HistoricalMinMaxBuckets < D > {
1986- pub ( super ) fn get_decayed_buckets < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
1996+ pub ( super ) fn get_decayed_buckets < T : Time > ( & self , now : T , offset_history_last_updated : T , half_life : Duration )
19871997 -> Option < ( [ u16 ; 32 ] , [ u16 ; 32 ] ) > {
1988- let ( _, required_decays) = self . get_total_valid_points ( now, last_updated , half_life) ?;
1998+ let ( _, required_decays) = self . get_total_valid_points ( now, offset_history_last_updated , half_life) ?;
19891999
19902000 let mut min_buckets = * self . min_liquidity_offset_history ;
19912001 min_buckets. time_decay_data ( required_decays) ;
@@ -1994,9 +2004,9 @@ mod bucketed_history {
19942004 Some ( ( min_buckets. buckets , max_buckets. buckets ) )
19952005 }
19962006 #[ inline]
1997- pub ( super ) fn get_total_valid_points < T : Time > ( & self , now : T , last_updated : T , half_life : Duration )
2007+ pub ( super ) fn get_total_valid_points < T : Time > ( & self , now : T , offset_history_last_updated : T , half_life : Duration )
19982008 -> Option < ( u64 , u32 ) > {
1999- let required_decays = now. duration_since ( last_updated ) . as_secs ( )
2009+ let required_decays = now. duration_since ( offset_history_last_updated ) . as_secs ( )
20002010 . checked_div ( half_life. as_secs ( ) )
20012011 . map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
20022012
@@ -2019,7 +2029,7 @@ mod bucketed_history {
20192029
20202030 #[ inline]
20212031 pub ( super ) fn calculate_success_probability_times_billion < T : Time > (
2022- & self , now : T , last_updated : T , half_life : Duration ,
2032+ & self , now : T , offset_history_last_updated : T , half_life : Duration ,
20232033 params : & ProbabilisticScoringFeeParameters , amount_msat : u64 , capacity_msat : u64
20242034 ) -> Option < u64 > {
20252035 // If historical penalties are enabled, we try to calculate a probability of success
@@ -2035,7 +2045,7 @@ mod bucketed_history {
20352045 // Check if all our buckets are zero, once decayed and treat it as if we had no data. We
20362046 // don't actually use the decayed buckets, though, as that would lose precision.
20372047 let ( total_valid_points_tracked, _)
2038- = self . get_total_valid_points ( now, last_updated , half_life) ?;
2048+ = self . get_total_valid_points ( now, offset_history_last_updated , half_life) ?;
20392049
20402050 let mut cumulative_success_prob_times_billion = 0 ;
20412051 // Special-case the 0th min bucket - it generally means we failed a payment, so only
@@ -2128,6 +2138,8 @@ ReadableArgs<(ProbabilisticScoringDecayParameters, G, L)> for ProbabilisticScore
21282138impl < T : Time > Writeable for ChannelLiquidity < T > {
21292139 #[ inline]
21302140 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
2141+ let offset_history_duration_since_epoch =
2142+ T :: duration_since_epoch ( ) - self . offset_history_last_updated . elapsed ( ) ;
21312143 let duration_since_epoch = T :: duration_since_epoch ( ) - self . last_updated . elapsed ( ) ;
21322144 write_tlv_fields ! ( w, {
21332145 ( 0 , self . min_liquidity_offset_msat, required) ,
@@ -2137,6 +2149,7 @@ impl<T: Time> Writeable for ChannelLiquidity<T> {
21372149 ( 4 , duration_since_epoch, required) ,
21382150 ( 5 , Some ( self . min_liquidity_offset_history) , option) ,
21392151 ( 7 , Some ( self . max_liquidity_offset_history) , option) ,
2152+ ( 9 , offset_history_duration_since_epoch, required) ,
21402153 } ) ;
21412154 Ok ( ( ) )
21422155 }
@@ -2152,6 +2165,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21522165 let mut min_liquidity_offset_history: Option < HistoricalBucketRangeTracker > = None ;
21532166 let mut max_liquidity_offset_history: Option < HistoricalBucketRangeTracker > = None ;
21542167 let mut duration_since_epoch = Duration :: from_secs ( 0 ) ;
2168+ let mut offset_history_duration_since_epoch = None ;
21552169 read_tlv_fields ! ( r, {
21562170 ( 0 , min_liquidity_offset_msat, required) ,
21572171 ( 1 , legacy_min_liq_offset_history, option) ,
@@ -2160,6 +2174,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21602174 ( 4 , duration_since_epoch, required) ,
21612175 ( 5 , min_liquidity_offset_history, option) ,
21622176 ( 7 , max_liquidity_offset_history, option) ,
2177+ ( 9 , offset_history_duration_since_epoch, option) ,
21632178 } ) ;
21642179 // On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
21652180 // We write `last_updated` as wallclock time even though its ultimately an `Instant` (which
@@ -2173,6 +2188,13 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21732188 let last_updated = if wall_clock_now > duration_since_epoch {
21742189 now - ( wall_clock_now - duration_since_epoch)
21752190 } else { now } ;
2191+
2192+ let offset_history_duration_since_epoch =
2193+ offset_history_duration_since_epoch. unwrap_or ( duration_since_epoch) ;
2194+ let offset_history_last_updated = if wall_clock_now > offset_history_duration_since_epoch {
2195+ now - ( wall_clock_now - duration_since_epoch)
2196+ } else { now } ;
2197+
21762198 if min_liquidity_offset_history. is_none ( ) {
21772199 if let Some ( legacy_buckets) = legacy_min_liq_offset_history {
21782200 min_liquidity_offset_history = Some ( legacy_buckets. into_current ( ) ) ;
@@ -2193,6 +2215,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21932215 min_liquidity_offset_history : min_liquidity_offset_history. unwrap ( ) ,
21942216 max_liquidity_offset_history : max_liquidity_offset_history. unwrap ( ) ,
21952217 last_updated,
2218+ offset_history_last_updated,
21962219 } )
21972220 }
21982221}
@@ -2368,18 +2391,21 @@ mod tests {
23682391 fn liquidity_bounds_directed_from_lowest_node_id ( ) {
23692392 let logger = TestLogger :: new ( ) ;
23702393 let last_updated = SinceEpoch :: now ( ) ;
2394+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
23712395 let network_graph = network_graph ( & logger) ;
23722396 let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
23732397 let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
23742398 . with_channel ( 42 ,
23752399 ChannelLiquidity {
2376- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
2400+ min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 ,
2401+ last_updated, offset_history_last_updated,
23772402 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23782403 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23792404 } )
23802405 . with_channel ( 43 ,
23812406 ChannelLiquidity {
2382- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
2407+ min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 ,
2408+ last_updated, offset_history_last_updated,
23832409 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23842410 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
23852411 } ) ;
@@ -2446,12 +2472,14 @@ mod tests {
24462472 fn resets_liquidity_upper_bound_when_crossed_by_lower_bound ( ) {
24472473 let logger = TestLogger :: new ( ) ;
24482474 let last_updated = SinceEpoch :: now ( ) ;
2475+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
24492476 let network_graph = network_graph ( & logger) ;
24502477 let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
24512478 let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
24522479 . with_channel ( 42 ,
24532480 ChannelLiquidity {
2454- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
2481+ min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 ,
2482+ last_updated, offset_history_last_updated,
24552483 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
24562484 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
24572485 } ) ;
@@ -2505,12 +2533,14 @@ mod tests {
25052533 fn resets_liquidity_lower_bound_when_crossed_by_upper_bound ( ) {
25062534 let logger = TestLogger :: new ( ) ;
25072535 let last_updated = SinceEpoch :: now ( ) ;
2536+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
25082537 let network_graph = network_graph ( & logger) ;
25092538 let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
25102539 let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
25112540 . with_channel ( 42 ,
25122541 ChannelLiquidity {
2513- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
2542+ min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 ,
2543+ last_updated, offset_history_last_updated,
25142544 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
25152545 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
25162546 } ) ;
@@ -2616,6 +2646,7 @@ mod tests {
26162646 fn constant_penalty_outside_liquidity_bounds ( ) {
26172647 let logger = TestLogger :: new ( ) ;
26182648 let last_updated = SinceEpoch :: now ( ) ;
2649+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
26192650 let network_graph = network_graph ( & logger) ;
26202651 let params = ProbabilisticScoringFeeParameters {
26212652 liquidity_penalty_multiplier_msat : 1_000 ,
@@ -2628,7 +2659,8 @@ mod tests {
26282659 let scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
26292660 . with_channel ( 42 ,
26302661 ChannelLiquidity {
2631- min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 , last_updated,
2662+ min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 ,
2663+ last_updated, offset_history_last_updated,
26322664 min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
26332665 max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
26342666 } ) ;
0 commit comments