1
+ from unittest .mock import Mock
2
+
1
3
import pytest
2
4
3
5
from src .constants import MAX_EFFECTIVE_BALANCE_ELECTRA , MAX_EFFECTIVE_BALANCE
@@ -43,6 +45,16 @@ def simple_validators(
43
45
return validators
44
46
45
47
48
+ TEST_ELECTRA_FORK_EPOCH = 450
49
+
50
+
51
+ @pytest .fixture (params = [TEST_ELECTRA_FORK_EPOCH ])
52
+ def electra_fork_epoch (request ):
53
+ # sets the electra fork epoch to the test value for calculating the penalty
54
+ MidtermSlashingPenalty .cl_spec = Mock (ELECTRA_FORK_EPOCH = request .param )
55
+ return request .param
56
+
57
+
46
58
@pytest .mark .unit
47
59
@pytest .mark .parametrize (
48
60
("blockstamp" , "all_validators" , "lido_validators" , "report_cl_rebase" , "expected_result" ),
@@ -109,7 +121,7 @@ def simple_validators(
109
121
],
110
122
)
111
123
def test_is_high_midterm_slashing_penalty (
112
- blockstamp , all_validators , lido_validators , report_cl_rebase , expected_result
124
+ blockstamp , electra_fork_epoch , all_validators , lido_validators , report_cl_rebase , expected_result
113
125
):
114
126
chain_config = ChainConfig (
115
127
slots_per_epoch = 32 ,
@@ -154,7 +166,7 @@ def test_is_high_midterm_slashing_penalty(
154
166
),
155
167
],
156
168
)
157
- def test_get_possible_slashed_epochs (validator , ref_epoch , expected_result ):
169
+ def test_get_possible_slashed_epochs (validator , electra_fork_epoch , ref_epoch , expected_result ):
158
170
result = MidtermSlashingPenalty .get_possible_slashed_epochs (validator , ref_epoch )
159
171
160
172
assert result == expected_result
@@ -169,7 +181,7 @@ def test_get_possible_slashed_epochs(validator, ref_epoch, expected_result):
169
181
# the same midterm epoch
170
182
225 ,
171
183
simple_validators (0 , 9 , slashed = True ),
172
- {18 : simple_validators (0 , 9 , slashed = True )},
184
+ {( 18 , 4050 ) : simple_validators (0 , 9 , slashed = True )},
173
185
),
174
186
(
175
187
# midterm frames in past
@@ -185,14 +197,14 @@ def test_get_possible_slashed_epochs(validator, ref_epoch, expected_result):
185
197
* simple_validators (10 , 59 , slashed = True , withdrawable_epoch = "8417" ),
186
198
],
187
199
{
188
- 18 : simple_validators (0 , 9 , slashed = True ),
189
- 19 : simple_validators (10 , 59 , slashed = True , withdrawable_epoch = "8417" ),
200
+ ( 18 , 4050 ) : simple_validators (0 , 9 , slashed = True ),
201
+ ( 19 , 4275 ) : simple_validators (10 , 59 , slashed = True , withdrawable_epoch = "8417" ),
190
202
},
191
203
),
192
204
],
193
205
)
194
206
def test_get_per_frame_lido_validators_with_future_midterm_epoch (
195
- ref_epoch , future_midterm_penalty_lido_slashed_validators , expected_result
207
+ ref_epoch , electra_fork_epoch , future_midterm_penalty_lido_slashed_validators , expected_result
196
208
):
197
209
frame_config = FrameConfig (
198
210
initial_epoch = EpochNumber (0 ),
@@ -211,48 +223,70 @@ def test_get_per_frame_lido_validators_with_future_midterm_epoch(
211
223
212
224
@pytest .mark .unit
213
225
@pytest .mark .parametrize (
214
- ("ref_epoch" , "per_frame_validators" , "all_slashed_validators" , "active_validators_count" , "expected_result" ),
226
+ ("ref_epoch" , "electra_fork_epoch" , " per_frame_validators" , "all_slashed_validators" , "active_validators_count" , "expected_result" ),
215
227
[
216
- (225 , {}, [], 100 , {}),
228
+ (225 , 225 , {}, [], 50000 , {}),
217
229
(
218
- # one is slashed
230
+ # one is slashed before electra
219
231
225 ,
220
- {18 : simple_validators (0 , 0 , slashed = True )},
232
+ 4500 ,
233
+ {(18 , 4050 ): simple_validators (0 , 0 , slashed = True )},
221
234
simple_validators (0 , 0 , slashed = True ),
222
- 100 ,
223
- {18 : 960_000_000 },
235
+ 50000 ,
236
+ {18 : 0 },
224
237
),
225
238
(
226
- # all are slashed
239
+ # one is slashed after electra
240
+ 225 ,
241
+ 225 ,
242
+ {(18 , 4050 ): simple_validators (0 , 0 , slashed = True )},
243
+ simple_validators (0 , 0 , slashed = True ),
244
+ 50000 ,
245
+ {18 : 1_920_000 },
246
+ ),
247
+ (
248
+ # all are slashed before electra
249
+ 225 ,
250
+ 4500 ,
251
+ {(18 , 4050 ): simple_validators (0 , 99 , slashed = True )},
252
+ simple_validators (0 , 99 , slashed = True ),
253
+ 50000 ,
254
+ {18 : 0 },
255
+ ),
256
+ (
257
+ # all are slashed after electra
258
+ 225 ,
227
259
225 ,
228
- {18 : simple_validators (0 , 99 , slashed = True )},
260
+ {( 18 , 4050 ) : simple_validators (0 , 99 , slashed = True )},
229
261
simple_validators (0 , 99 , slashed = True ),
230
- 100 ,
231
- {18 : 100 * 32 * 10 ** 9 },
262
+ 50000 ,
263
+ {18 : 19_200_000_000 },
232
264
),
233
265
(
234
- # slashed in different frames with determined slashing epochs
266
+ # slashed in different frames with determined slashing epochs in different forks
235
267
225 ,
268
+ 4500 ,
236
269
{
237
- 18 : simple_validators (0 , 9 , slashed = True ),
238
- 19 : simple_validators (10 , 59 , slashed = True , exit_epoch = "8000" , withdrawable_epoch = "8417" ),
270
+ ( 18 , 4050 ) : simple_validators (0 , 0 , slashed = True ),
271
+ ( 19 , 4725 ) : simple_validators (10 , 59 , slashed = True , exit_epoch = "8000" , withdrawable_epoch = "8417" ),
239
272
},
240
273
[
241
- * simple_validators (0 , 9 , slashed = True ),
274
+ * simple_validators (0 , 0 , slashed = True ),
242
275
* simple_validators (10 , 59 , slashed = True , exit_epoch = "8000" , withdrawable_epoch = "8417" ),
243
276
],
244
- 100 ,
245
- {18 : 10 * 32 * 10 ** 9 , 19 : 50 * 32 * 10 ** 9 },
277
+ 50000 ,
278
+ {18 : 0 , 19 : 4_896_000_000 },
246
279
),
247
280
(
248
- # slashed in different epochs in different frames without determined shasling epochs
281
+ # slashed in different epochs in different frames without determined slashing epochs in different forks
249
282
225 ,
283
+ 4500 ,
250
284
{
251
- 18 : [
285
+ ( 18 , 4050 ) : [
252
286
* simple_validators (0 , 5 ),
253
287
* simple_validators (6 , 9 , slashed = True , exit_epoch = "8192" , withdrawable_epoch = "8197" ),
254
288
],
255
- 19 : [
289
+ ( 19 , 4725 ) : [
256
290
* simple_validators (10 , 29 , slashed = True , exit_epoch = "8000" , withdrawable_epoch = "8417" ),
257
291
* simple_validators (30 , 59 , slashed = True , exit_epoch = "8417" , withdrawable_epoch = "8419" ),
258
292
],
@@ -263,13 +297,19 @@ def test_get_per_frame_lido_validators_with_future_midterm_epoch(
263
297
* simple_validators (10 , 29 , slashed = True , exit_epoch = "8000" , withdrawable_epoch = "8417" ),
264
298
* simple_validators (30 , 59 , slashed = True , exit_epoch = "8417" , withdrawable_epoch = "8419" ),
265
299
],
266
- 100 ,
267
- {18 : 10 * 32 * 10 ** 9 , 19 : 50 * 32 * 10 ** 9 },
300
+ 50000 ,
301
+ {18 : 0 , 19 : 5_760_000_000 },
268
302
),
269
303
],
304
+ indirect = ["electra_fork_epoch" ],
270
305
)
271
306
def test_get_future_midterm_penalty_sum_in_frames (
272
- ref_epoch , per_frame_validators , all_slashed_validators , active_validators_count , expected_result
307
+ ref_epoch ,
308
+ electra_fork_epoch ,
309
+ per_frame_validators ,
310
+ all_slashed_validators ,
311
+ active_validators_count ,
312
+ expected_result ,
273
313
):
274
314
result = MidtermSlashingPenalty .get_future_midterm_penalty_sum_in_frames (
275
315
EpochNumber (ref_epoch ), all_slashed_validators , active_validators_count * 32 * 10 ** 9 , per_frame_validators
@@ -280,12 +320,65 @@ def test_get_future_midterm_penalty_sum_in_frames(
280
320
281
321
@pytest .mark .unit
282
322
@pytest .mark .parametrize (
283
- ("ref_epoch" , "all_slashed_validators" , "total_balance" , "validators_in_frame" , "expected_result" ),
323
+ (
324
+ "ref_epoch" ,
325
+ "is_after_electra" ,
326
+ "all_slashed_validators" ,
327
+ "total_balance" ,
328
+ "validators_in_frame" ,
329
+ "expected_result" ,
330
+ ),
284
331
[
285
- (225 , [], 100 * 32 * 10 ** 9 , [], 0 ),
332
+ # BEFORE ELECTRA
333
+ (225 , False , [], 100 * 32 * 10 ** 9 , [], 0 ),
334
+ (
335
+ # one is slashed
336
+ 225 ,
337
+ False ,
338
+ simple_validators (0 , 0 , slashed = True ),
339
+ 100 * 32 * 10 ** 9 ,
340
+ simple_validators (0 , 0 , slashed = True ),
341
+ 0 ,
342
+ ),
343
+ (
344
+ # all are slashed
345
+ 225 ,
346
+ False ,
347
+ simple_validators (0 , 99 , slashed = True ),
348
+ 100 * 32 * 10 ** 9 ,
349
+ simple_validators (0 , 99 , slashed = True ),
350
+ 100 * 32 * 10 ** 9 ,
351
+ ),
352
+ (
353
+ # several are slashed
354
+ 225 ,
355
+ False ,
356
+ simple_validators (0 , 9 , slashed = True ),
357
+ 100 * 32 * 10 ** 9 ,
358
+ simple_validators (0 , 9 , slashed = True ),
359
+ 10 * 9 * 10 ** 9 ,
360
+ ),
361
+ (
362
+ # slashed in different epochs in different frames without determined slashing epochs
363
+ 225 ,
364
+ False ,
365
+ [
366
+ * simple_validators (0 , 5 , slashed = True ),
367
+ * simple_validators (6 , 9 , slashed = True , exit_epoch = "8192" , withdrawable_epoch = "8197" ),
368
+ ],
369
+ 100 * 32 * 10 ** 9 ,
370
+ [
371
+ * simple_validators (0 , 5 , slashed = True ),
372
+ * simple_validators (6 , 9 , slashed = True , exit_epoch = "8192" , withdrawable_epoch = "8197" ),
373
+ ],
374
+ 10 * 9 * 10 ** 9 ,
375
+ ),
376
+ # AFTER ELECTRA
377
+ (225 , True , [], 100 * 32 * 10 ** 9 , [], 0 ),
286
378
(
287
379
# one is slashed
288
380
225 ,
381
+ True ,
289
382
simple_validators (0 , 0 , slashed = True ),
290
383
100 * 32 * 10 ** 9 ,
291
384
simple_validators (0 , 0 , slashed = True ),
@@ -294,6 +387,7 @@ def test_get_future_midterm_penalty_sum_in_frames(
294
387
(
295
388
# all are slashed
296
389
225 ,
390
+ True ,
297
391
simple_validators (0 , 99 , slashed = True ),
298
392
100 * 32 * 10 ** 9 ,
299
393
simple_validators (0 , 99 , slashed = True ),
@@ -302,6 +396,7 @@ def test_get_future_midterm_penalty_sum_in_frames(
302
396
(
303
397
# several are slashed
304
398
225 ,
399
+ True ,
305
400
simple_validators (0 , 9 , slashed = True ),
306
401
100 * 32 * 10 ** 9 ,
307
402
simple_validators (0 , 9 , slashed = True ),
@@ -310,6 +405,7 @@ def test_get_future_midterm_penalty_sum_in_frames(
310
405
(
311
406
# slashed in different epochs in different frames without determined slashing epochs
312
407
225 ,
408
+ True ,
313
409
[
314
410
* simple_validators (0 , 5 , slashed = True ),
315
411
* simple_validators (6 , 9 , slashed = True , exit_epoch = "8192" , withdrawable_epoch = "8197" ),
@@ -324,10 +420,20 @@ def test_get_future_midterm_penalty_sum_in_frames(
324
420
],
325
421
)
326
422
def test_predict_midterm_penalty_in_frame (
327
- ref_epoch , all_slashed_validators , total_balance , validators_in_frame , expected_result
423
+ ref_epoch ,
424
+ is_after_electra ,
425
+ all_slashed_validators ,
426
+ total_balance ,
427
+ validators_in_frame ,
428
+ expected_result ,
429
+ electra_fork_epoch ,
328
430
):
329
431
result = MidtermSlashingPenalty .predict_midterm_penalty_in_frame (
330
- EpochNumber (ref_epoch ), all_slashed_validators , total_balance , validators_in_frame
432
+ report_ref_epoch = EpochNumber (ref_epoch ),
433
+ frame_ref_epoch = EpochNumber (electra_fork_epoch if is_after_electra else electra_fork_epoch - 1 ),
434
+ all_slashed_validators = all_slashed_validators ,
435
+ total_balance = total_balance ,
436
+ midterm_penalized_validators_in_frame = validators_in_frame ,
331
437
)
332
438
333
439
assert result == expected_result
@@ -380,8 +486,8 @@ def test_predict_midterm_penalty_in_frame(
380
486
"10_000 bounded slashing with 2048 EB, 10% active validators with 2048 EB and the rest part with 32 EB" ,
381
487
],
382
488
)
383
- def test_get_midterm_penalty (bounded_slashed_validators , active_validators , expected_penalty ):
384
- result = MidtermSlashingPenalty .get_validator_midterm_penalty (
489
+ def test_get_validator_midterm_penalty_electra (bounded_slashed_validators , active_validators , expected_penalty ):
490
+ result = MidtermSlashingPenalty .get_validator_midterm_penalty_electra (
385
491
validator = simple_validators (0 , 0 )[0 ],
386
492
bound_slashed_validators = bounded_slashed_validators ,
387
493
total_balance = Gwei (sum (int (v .validator .effective_balance ) for v in active_validators )),
@@ -390,6 +496,27 @@ def test_get_midterm_penalty(bounded_slashed_validators, active_validators, expe
390
496
assert result == expected_penalty
391
497
392
498
499
+ @pytest .mark .unit
500
+ @pytest .mark .parametrize (
501
+ ("bounded_slashings_count" , "active_validators_count" , "expected_penalty" ),
502
+ [
503
+ (1 , 500000 , 0 ),
504
+ (100 , 500000 , 0 ),
505
+ (1000 , 500000 , 0 ),
506
+ (5000 , 500000 , 0 ),
507
+ (10000 , 500000 , 1000000000 ),
508
+ (20000 , 500000 , 3000000000 ),
509
+ (50000 , 500000 , 9000000000 ),
510
+ ],
511
+ )
512
+ def test_get_validator_midterm_penalty (bounded_slashings_count , active_validators_count , expected_penalty ):
513
+ result = MidtermSlashingPenalty .get_validator_midterm_penalty (
514
+ simple_validators (0 , 0 )[0 ], bounded_slashings_count , active_validators_count * 32 * 10 ** 9
515
+ )
516
+
517
+ assert result == expected_penalty
518
+
519
+
393
520
@pytest .mark .unit
394
521
@pytest .mark .parametrize (
395
522
("ref_epoch" , "slashed_validators" , "midterm_penalty_epoch" , "expected_bounded" ),
@@ -490,6 +617,26 @@ def test_get_frame_by_epoch(epoch, expected_frame):
490
617
assert frame_by_epoch == expected_frame
491
618
492
619
620
+ @pytest .mark .unit
621
+ @pytest .mark .parametrize (
622
+ ("frame_number" , "expected_ref_epoch" ),
623
+ [
624
+ (0 , 0 ),
625
+ (1 , 225 ),
626
+ (2 , 450 ),
627
+ (3 , 675 ),
628
+ ],
629
+ )
630
+ def test_get_ref_epoch_by_frame (frame_number , expected_ref_epoch ):
631
+ frame_config = FrameConfig (
632
+ initial_epoch = EpochNumber (0 ),
633
+ epochs_per_frame = EpochNumber (225 ),
634
+ fast_lane_length_slots = 0 ,
635
+ )
636
+ ref_epoch = MidtermSlashingPenalty .get_ref_epoch_by_frame (frame_number , frame_config )
637
+ assert ref_epoch == expected_ref_epoch
638
+
639
+
493
640
@pytest .mark .unit
494
641
def test_get_midterm_slashing_epoch ():
495
642
result = MidtermSlashingPenalty .get_midterm_penalty_epoch (simple_validators (0 , 0 )[0 ])
0 commit comments