@@ -805,11 +805,14 @@ struct ChannelLiquidity<T: Time> {
805
805
/// Upper channel liquidity bound in terms of an offset from the effective capacity.
806
806
max_liquidity_offset_msat : u64 ,
807
807
808
+ min_liquidity_offset_history : HistoricalBucketRangeTracker ,
809
+ max_liquidity_offset_history : HistoricalBucketRangeTracker ,
810
+
808
811
/// Time when the liquidity bounds were last modified.
809
812
last_updated : T ,
810
813
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 ,
813
816
}
814
817
815
818
/// 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
820
823
liquidity_history : HistoricalMinMaxBuckets < BRT > ,
821
824
capacity_msat : u64 ,
822
825
last_updated : U ,
826
+ offset_history_last_updated : U ,
823
827
now : T ,
824
828
decay_params : ProbabilisticScoringDecayParameters ,
825
829
}
@@ -858,7 +862,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
858
862
let dir_liq = liq. as_directed ( source, target, amt, self . decay_params ) ;
859
863
860
864
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 ,
862
866
self . decay_params . historical_no_updates_half_life )
863
867
. unwrap_or ( ( [ 0 ; 32 ] , [ 0 ; 32 ] ) ) ;
864
868
@@ -955,7 +959,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
955
959
956
960
let ( min_buckets, mut max_buckets) =
957
961
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 ,
959
963
self . decay_params . historical_no_updates_half_life
960
964
) ?;
961
965
@@ -988,7 +992,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
988
992
let dir_liq = liq. as_directed ( source, target, capacity_msat, self . decay_params ) ;
989
993
990
994
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 ,
992
996
self . decay_params . historical_no_updates_half_life , & params, amount_msat,
993
997
capacity_msat
994
998
) . map ( |p| p as f64 / ( 1024 * 1024 * 1024 ) as f64 ) ;
@@ -1008,6 +1012,7 @@ impl<T: Time> ChannelLiquidity<T> {
1008
1012
min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1009
1013
max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1010
1014
last_updated : T :: now ( ) ,
1015
+ offset_history_last_updated : T :: now ( ) ,
1011
1016
}
1012
1017
}
1013
1018
@@ -1034,6 +1039,7 @@ impl<T: Time> ChannelLiquidity<T> {
1034
1039
} ,
1035
1040
capacity_msat,
1036
1041
last_updated : & self . last_updated ,
1042
+ offset_history_last_updated : & self . offset_history_last_updated ,
1037
1043
now : T :: now ( ) ,
1038
1044
decay_params : decay_params,
1039
1045
}
@@ -1062,6 +1068,7 @@ impl<T: Time> ChannelLiquidity<T> {
1062
1068
} ,
1063
1069
capacity_msat,
1064
1070
last_updated : & mut self . last_updated ,
1071
+ offset_history_last_updated : & mut self . offset_history_last_updated ,
1065
1072
now : T :: now ( ) ,
1066
1073
decay_params : decay_params,
1067
1074
}
@@ -1197,7 +1204,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
1197
1204
if score_params. historical_liquidity_penalty_multiplier_msat != 0 ||
1198
1205
score_params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
1199
1206
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 ,
1201
1209
self . decay_params . historical_no_updates_half_life , score_params, amount_msat,
1202
1210
self . capacity_msat )
1203
1211
{
@@ -1316,7 +1324,7 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
1316
1324
/// state"), we allow the caller to set an offset applied to our liquidity bounds which
1317
1325
/// represents the amount of the successful payment we just made.
1318
1326
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 ( )
1320
1328
. checked_div ( self . decay_params . historical_no_updates_half_life . as_secs ( ) )
1321
1329
. map ( |v| v. try_into ( ) . unwrap_or ( u32:: max_value ( ) ) ) . unwrap_or ( u32:: max_value ( ) ) ;
1322
1330
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
1341
1349
self . decayed_offset_msat ( * self . max_liquidity_offset_msat )
1342
1350
} ;
1343
1351
* self . last_updated = self . now ;
1352
+ * self . offset_history_last_updated = self . now ;
1344
1353
}
1345
1354
1346
1355
/// 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
1352
1361
self . decayed_offset_msat ( * self . min_liquidity_offset_msat )
1353
1362
} ;
1354
1363
* self . last_updated = self . now ;
1364
+ * self . offset_history_last_updated = self . now ;
1355
1365
}
1356
1366
}
1357
1367
@@ -1983,9 +1993,9 @@ mod bucketed_history {
1983
1993
}
1984
1994
1985
1995
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 )
1987
1997
-> 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) ?;
1989
1999
1990
2000
let mut min_buckets = * self . min_liquidity_offset_history ;
1991
2001
min_buckets. time_decay_data ( required_decays) ;
@@ -1994,9 +2004,9 @@ mod bucketed_history {
1994
2004
Some ( ( min_buckets. buckets , max_buckets. buckets ) )
1995
2005
}
1996
2006
#[ 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 )
1998
2008
-> 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 ( )
2000
2010
. checked_div ( half_life. as_secs ( ) )
2001
2011
. map_or ( u32:: max_value ( ) , |decays| cmp:: min ( decays, u32:: max_value ( ) as u64 ) as u32 ) ;
2002
2012
@@ -2019,7 +2029,7 @@ mod bucketed_history {
2019
2029
2020
2030
#[ inline]
2021
2031
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 ,
2023
2033
params : & ProbabilisticScoringFeeParameters , amount_msat : u64 , capacity_msat : u64
2024
2034
) -> Option < u64 > {
2025
2035
// If historical penalties are enabled, we try to calculate a probability of success
@@ -2035,7 +2045,7 @@ mod bucketed_history {
2035
2045
// Check if all our buckets are zero, once decayed and treat it as if we had no data. We
2036
2046
// don't actually use the decayed buckets, though, as that would lose precision.
2037
2047
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) ?;
2039
2049
2040
2050
let mut cumulative_success_prob_times_billion = 0 ;
2041
2051
// 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
2128
2138
impl < T : Time > Writeable for ChannelLiquidity < T > {
2129
2139
#[ inline]
2130
2140
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 ( ) ;
2131
2143
let duration_since_epoch = T :: duration_since_epoch ( ) - self . last_updated . elapsed ( ) ;
2132
2144
write_tlv_fields ! ( w, {
2133
2145
( 0 , self . min_liquidity_offset_msat, required) ,
@@ -2137,6 +2149,7 @@ impl<T: Time> Writeable for ChannelLiquidity<T> {
2137
2149
( 4 , duration_since_epoch, required) ,
2138
2150
( 5 , Some ( self . min_liquidity_offset_history) , option) ,
2139
2151
( 7 , Some ( self . max_liquidity_offset_history) , option) ,
2152
+ ( 9 , offset_history_duration_since_epoch, required) ,
2140
2153
} ) ;
2141
2154
Ok ( ( ) )
2142
2155
}
@@ -2152,6 +2165,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
2152
2165
let mut min_liquidity_offset_history: Option < HistoricalBucketRangeTracker > = None ;
2153
2166
let mut max_liquidity_offset_history: Option < HistoricalBucketRangeTracker > = None ;
2154
2167
let mut duration_since_epoch = Duration :: from_secs ( 0 ) ;
2168
+ let mut offset_history_duration_since_epoch = None ;
2155
2169
read_tlv_fields ! ( r, {
2156
2170
( 0 , min_liquidity_offset_msat, required) ,
2157
2171
( 1 , legacy_min_liq_offset_history, option) ,
@@ -2160,6 +2174,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
2160
2174
( 4 , duration_since_epoch, required) ,
2161
2175
( 5 , min_liquidity_offset_history, option) ,
2162
2176
( 7 , max_liquidity_offset_history, option) ,
2177
+ ( 9 , offset_history_duration_since_epoch, option) ,
2163
2178
} ) ;
2164
2179
// On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
2165
2180
// 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> {
2173
2188
let last_updated = if wall_clock_now > duration_since_epoch {
2174
2189
now - ( wall_clock_now - duration_since_epoch)
2175
2190
} 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 - offset_history_duration_since_epoch)
2196
+ } else { now } ;
2197
+
2176
2198
if min_liquidity_offset_history. is_none ( ) {
2177
2199
if let Some ( legacy_buckets) = legacy_min_liq_offset_history {
2178
2200
min_liquidity_offset_history = Some ( legacy_buckets. into_current ( ) ) ;
@@ -2193,6 +2215,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
2193
2215
min_liquidity_offset_history : min_liquidity_offset_history. unwrap ( ) ,
2194
2216
max_liquidity_offset_history : max_liquidity_offset_history. unwrap ( ) ,
2195
2217
last_updated,
2218
+ offset_history_last_updated,
2196
2219
} )
2197
2220
}
2198
2221
}
@@ -2368,18 +2391,21 @@ mod tests {
2368
2391
fn liquidity_bounds_directed_from_lowest_node_id ( ) {
2369
2392
let logger = TestLogger :: new ( ) ;
2370
2393
let last_updated = SinceEpoch :: now ( ) ;
2394
+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
2371
2395
let network_graph = network_graph ( & logger) ;
2372
2396
let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
2373
2397
let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
2374
2398
. with_channel ( 42 ,
2375
2399
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,
2377
2402
min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2378
2403
max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2379
2404
} )
2380
2405
. with_channel ( 43 ,
2381
2406
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,
2383
2409
min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2384
2410
max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2385
2411
} ) ;
@@ -2446,12 +2472,14 @@ mod tests {
2446
2472
fn resets_liquidity_upper_bound_when_crossed_by_lower_bound ( ) {
2447
2473
let logger = TestLogger :: new ( ) ;
2448
2474
let last_updated = SinceEpoch :: now ( ) ;
2475
+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
2449
2476
let network_graph = network_graph ( & logger) ;
2450
2477
let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
2451
2478
let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
2452
2479
. with_channel ( 42 ,
2453
2480
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,
2455
2483
min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2456
2484
max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2457
2485
} ) ;
@@ -2505,12 +2533,14 @@ mod tests {
2505
2533
fn resets_liquidity_lower_bound_when_crossed_by_upper_bound ( ) {
2506
2534
let logger = TestLogger :: new ( ) ;
2507
2535
let last_updated = SinceEpoch :: now ( ) ;
2536
+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
2508
2537
let network_graph = network_graph ( & logger) ;
2509
2538
let decay_params = ProbabilisticScoringDecayParameters :: default ( ) ;
2510
2539
let mut scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
2511
2540
. with_channel ( 42 ,
2512
2541
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,
2514
2544
min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2515
2545
max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2516
2546
} ) ;
@@ -2616,6 +2646,7 @@ mod tests {
2616
2646
fn constant_penalty_outside_liquidity_bounds ( ) {
2617
2647
let logger = TestLogger :: new ( ) ;
2618
2648
let last_updated = SinceEpoch :: now ( ) ;
2649
+ let offset_history_last_updated = SinceEpoch :: now ( ) ;
2619
2650
let network_graph = network_graph ( & logger) ;
2620
2651
let params = ProbabilisticScoringFeeParameters {
2621
2652
liquidity_penalty_multiplier_msat : 1_000 ,
@@ -2628,7 +2659,8 @@ mod tests {
2628
2659
let scorer = ProbabilisticScorer :: new ( decay_params, & network_graph, & logger)
2629
2660
. with_channel ( 42 ,
2630
2661
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,
2632
2664
min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2633
2665
max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
2634
2666
} ) ;
0 commit comments