@@ -2060,15 +2060,17 @@ mod bucketed_history {
2060
2060
}
2061
2061
2062
2062
fn recalculate_valid_point_count ( & mut self ) {
2063
- let mut total_valid_points_tracked = 0 ;
2063
+ let mut total_valid_points_tracked = 0u128 ;
2064
2064
for ( min_idx, min_bucket) in self . min_liquidity_offset_history . buckets . iter ( ) . enumerate ( ) {
2065
2065
for max_bucket in self . max_liquidity_offset_history . buckets . iter ( ) . take ( 32 - min_idx) {
2066
2066
// In testing, raising the weights of buckets to a high power led to better
2067
2067
// scoring results. Thus, we raise the bucket weights to the 4th power here (by
2068
- // squaring the result of multiplying the weights).
2068
+ // squaring the result of multiplying the weights). This results in
2069
+ // bucket_weight having at max 64 bits, which means we have to do our summation
2070
+ // in 128-bit math.
2069
2071
let mut bucket_weight = ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
2070
2072
bucket_weight *= bucket_weight;
2071
- total_valid_points_tracked += bucket_weight;
2073
+ total_valid_points_tracked += bucket_weight as u128 ;
2072
2074
}
2073
2075
}
2074
2076
self . total_valid_points_tracked = total_valid_points_tracked as f64 ;
@@ -2161,12 +2163,12 @@ mod bucketed_history {
2161
2163
2162
2164
let total_valid_points_tracked = self . tracker . total_valid_points_tracked ;
2163
2165
#[ cfg( debug_assertions) ] {
2164
- let mut actual_valid_points_tracked = 0 ;
2166
+ let mut actual_valid_points_tracked = 0u128 ;
2165
2167
for ( min_idx, min_bucket) in min_liquidity_offset_history_buckets. iter ( ) . enumerate ( ) {
2166
2168
for max_bucket in max_liquidity_offset_history_buckets. iter ( ) . take ( 32 - min_idx) {
2167
2169
let mut bucket_weight = ( * min_bucket as u64 ) * ( * max_bucket as u64 ) ;
2168
2170
bucket_weight *= bucket_weight;
2169
- actual_valid_points_tracked += bucket_weight;
2171
+ actual_valid_points_tracked += bucket_weight as u128 ;
2170
2172
}
2171
2173
}
2172
2174
assert_eq ! ( total_valid_points_tracked, actual_valid_points_tracked as f64 ) ;
@@ -2193,7 +2195,7 @@ mod bucketed_history {
2193
2195
// max-bucket with at least BUCKET_FIXED_POINT_ONE.
2194
2196
let mut highest_max_bucket_with_points = 0 ;
2195
2197
let mut highest_max_bucket_with_full_points = None ;
2196
- let mut total_weight = 0 ;
2198
+ let mut total_weight = 0u128 ;
2197
2199
for ( max_idx, max_bucket) in max_liquidity_offset_history_buckets. iter ( ) . enumerate ( ) {
2198
2200
if * max_bucket >= BUCKET_FIXED_POINT_ONE {
2199
2201
highest_max_bucket_with_full_points = Some ( cmp:: max ( highest_max_bucket_with_full_points. unwrap_or ( 0 ) , max_idx) ) ;
@@ -2206,7 +2208,7 @@ mod bucketed_history {
2206
2208
// squaring the result of multiplying the weights), matching the logic in
2207
2209
// `recalculate_valid_point_count`.
2208
2210
let bucket_weight = ( * max_bucket as u64 ) * ( min_liquidity_offset_history_buckets[ 0 ] as u64 ) ;
2209
- total_weight += bucket_weight * bucket_weight;
2211
+ total_weight += ( bucket_weight * bucket_weight) as u128 ;
2210
2212
}
2211
2213
debug_assert ! ( total_weight as f64 <= total_valid_points_tracked) ;
2212
2214
// Use the highest max-bucket with at least BUCKET_FIXED_POINT_ONE, but if none is
@@ -2343,6 +2345,26 @@ mod bucketed_history {
2343
2345
2344
2346
assert_ne ! ( probability1, probability) ;
2345
2347
}
2348
+
2349
+ #[ test]
2350
+ fn historical_heavy_buckets_operations ( ) {
2351
+ // Checks that we don't hit overflows when working with tons of data (even an
2352
+ // impossible-to-reach amount of data).
2353
+ let mut tracker = HistoricalLiquidityTracker :: new ( ) ;
2354
+ tracker. min_liquidity_offset_history . buckets = [ 0xffff ; 32 ] ;
2355
+ tracker. max_liquidity_offset_history . buckets = [ 0xffff ; 32 ] ;
2356
+ tracker. recalculate_valid_point_count ( ) ;
2357
+ tracker. merge ( & tracker. clone ( ) ) ;
2358
+ assert_eq ! ( tracker. min_liquidity_offset_history. buckets, [ 0xffff ; 32 ] ) ;
2359
+ assert_eq ! ( tracker. max_liquidity_offset_history. buckets, [ 0xffff ; 32 ] ) ;
2360
+
2361
+ let mut directed = tracker. as_directed_mut ( true ) ;
2362
+ let default_params = ProbabilisticScoringFeeParameters :: default ( ) ;
2363
+ directed. calculate_success_probability_times_billion ( & default_params, 42 , 1000 ) ;
2364
+ directed. track_datapoint ( 42 , 52 , 1000 ) ;
2365
+
2366
+ tracker. decay_buckets ( 1.0 ) ;
2367
+ }
2346
2368
}
2347
2369
}
2348
2370
0 commit comments