Skip to content

Commit b4311fe

Browse files
authored
Merge pull request #3984 from mkalinin/epoch-processing-tests
electra: Epoch processing tests
2 parents 50f8fa6 + 44c1c31 commit b4311fe

File tree

6 files changed

+244
-5
lines changed

6 files changed

+244
-5
lines changed

specs/electra/beacon-chain.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,23 +792,25 @@ def process_epoch(state: BeaconState) -> None:
792792

793793
#### Modified `process_registry_updates`
794794

795-
*Note*: The function `process_registry_updates` is modified to use the updated definition of `initiate_validator_exit`
795+
*Note*: The function `process_registry_updates` is modified to
796+
use the updated definitions of `initiate_validator_exit` and `is_eligible_for_activation_queue`
796797
and changes how the activation epochs are computed for eligible validators.
797798

798799
```python
799800
def process_registry_updates(state: BeaconState) -> None:
800801
# Process activation eligibility and ejections
801802
for index, validator in enumerate(state.validators):
802-
if is_eligible_for_activation_queue(validator):
803+
if is_eligible_for_activation_queue(validator): # [Modified in Electra:EIP7251]
803804
validator.activation_eligibility_epoch = get_current_epoch(state) + 1
804805

805806
if (
806807
is_active_validator(validator, get_current_epoch(state))
807808
and validator.effective_balance <= EJECTION_BALANCE
808809
):
809-
initiate_validator_exit(state, ValidatorIndex(index))
810+
initiate_validator_exit(state, ValidatorIndex(index)) # [Modified in Electra:EIP7251]
810811

811812
# Activate all eligible validators
813+
# [Modified in Electra:EIP7251]
812814
activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
813815
for validator in state.validators:
814816
if is_eligible_for_activation(state, validator):

tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def run_test_activation_churn_limit(spec, state):
2323

2424
validator_count_0 = len(state.validators)
2525

26+
balance = spec.MIN_ACTIVATION_BALANCE if is_post_electra(spec) else spec.MAX_EFFECTIVE_BALANCE
27+
2628
for i in range(mock_activations):
2729
index = validator_count_0 + i
2830
validator = spec.Validator(
@@ -32,10 +34,10 @@ def run_test_activation_churn_limit(spec, state):
3234
activation_epoch=spec.FAR_FUTURE_EPOCH,
3335
exit_epoch=spec.FAR_FUTURE_EPOCH,
3436
withdrawable_epoch=spec.FAR_FUTURE_EPOCH,
35-
effective_balance=spec.MAX_EFFECTIVE_BALANCE,
37+
effective_balance=balance,
3638
)
3739
state.validators.append(validator)
38-
state.balances.append(spec.MAX_EFFECTIVE_BALANCE)
40+
state.balances.append(balance)
3941
state.previous_epoch_participation.append(spec.ParticipationFlags(0b0000_0000))
4042
state.current_epoch_participation.append(spec.ParticipationFlags(0b0000_0000))
4143
state.inactivity_scores.append(0)

tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_process_pending_deposits.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22
from eth2spec.test.context import (
33
spec_state_test,
44
with_electra_and_later,
5+
with_presets,
6+
spec_test,
7+
single_phase,
8+
with_custom_state,
9+
scaled_churn_balances_exceed_activation_exit_churn_limit,
10+
default_activation_threshold,
511
)
612
from eth2spec.test.helpers.deposits import prepare_pending_deposit
713
from eth2spec.test.helpers.state import (
814
next_epoch_with_full_participation,
915
advance_finality_to,
1016
set_full_participation,
1117
)
18+
from eth2spec.test.helpers.constants import MINIMAL
1219

1320

1421
def run_process_pending_deposits(spec, state):
@@ -488,3 +495,26 @@ def test_process_pending_deposits_withdrawable_validator_not_churned(spec, state
488495
assert state.pending_deposits == [
489496
prepare_pending_deposit(spec, validator_index=1, amount=amount)
490497
]
498+
499+
500+
@with_electra_and_later
501+
@with_presets([MINIMAL], "need sufficient consolidation churn limit")
502+
@with_custom_state(
503+
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
504+
threshold_fn=default_activation_threshold,
505+
)
506+
@spec_test
507+
@single_phase
508+
def test_process_pending_deposits_scaled_churn(spec, state):
509+
index = 0
510+
amount = spec.get_activation_exit_churn_limit(state)
511+
state.pending_deposits.append(
512+
prepare_pending_deposit(spec, index, amount)
513+
)
514+
pre_balance = state.balances[index]
515+
516+
yield from run_process_pending_deposits(spec, state)
517+
518+
assert state.balances[index] == pre_balance + amount
519+
assert state.deposit_balance_to_consume == 0
520+
assert state.pending_deposits == []

tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
from eth2spec.test.helpers.state import (
1010
next_epoch_with_full_participation,
1111
)
12+
from eth2spec.test.helpers.withdrawals import (
13+
set_eth1_withdrawal_credential_with_balance,
14+
set_compounding_withdrawal_credential_with_balance,
15+
)
1216

1317
# ***********************
1418
# * CONSOLIDATION TESTS *
@@ -302,3 +306,131 @@ def test_pending_consolidation_with_pending_deposit(spec, state):
302306
# Pending deposit to the source was not processed.
303307
# It should only be processed in the next epoch transition
304308
assert state.pending_deposits == [pending_deposit]
309+
310+
311+
@with_electra_and_later
312+
@spec_state_test
313+
def test_pending_consolidation_source_balance_less_than_max_effective(spec, state):
314+
current_epoch = spec.get_current_epoch(state)
315+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
316+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
317+
# append pending consolidation
318+
state.pending_consolidations.append(
319+
spec.PendingConsolidation(source_index=source_index, target_index=target_index)
320+
)
321+
# Set withdrawable epoch to current epoch to allow processing
322+
state.validators[source_index].withdrawable_epoch = current_epoch
323+
# Set source and target withdrawal credential to eth1
324+
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
325+
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
326+
# Set the source balance to be less than effective_balance
327+
pre_balance_source = state.validators[source_index].effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 8
328+
state.balances[source_index] = pre_balance_source
329+
330+
pre_balance_target = state.balances[target_index]
331+
332+
assert state.balances[source_index] < spec.get_max_effective_balance(state.validators[source_index])
333+
334+
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
335+
336+
# Pending consolidation was successfully processed
337+
assert state.balances[target_index] == pre_balance_target + pre_balance_source
338+
assert state.balances[source_index] == 0
339+
assert state.pending_consolidations == []
340+
341+
342+
@with_electra_and_later
343+
@spec_state_test
344+
def test_pending_consolidation_source_balance_greater_than_max_effective(spec, state):
345+
current_epoch = spec.get_current_epoch(state)
346+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
347+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
348+
# append pending consolidation
349+
state.pending_consolidations.append(
350+
spec.PendingConsolidation(source_index=source_index, target_index=target_index)
351+
)
352+
# Set withdrawable epoch to current epoch to allow processing
353+
state.validators[source_index].withdrawable_epoch = current_epoch
354+
# Set source and target withdrawal credential to eth1
355+
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
356+
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
357+
# Set the source balance to be greater than effective_balance
358+
excess_source_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 8
359+
pre_balance_source = state.validators[source_index].effective_balance + excess_source_balance
360+
state.balances[source_index] = pre_balance_source
361+
362+
pre_balance_target = state.balances[target_index]
363+
364+
source_max_effective_balance = spec.get_max_effective_balance(state.validators[source_index])
365+
assert state.balances[source_index] > source_max_effective_balance
366+
367+
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
368+
369+
# Pending consolidation was successfully processed
370+
assert state.balances[target_index] == pre_balance_target + source_max_effective_balance
371+
assert state.balances[source_index] == excess_source_balance
372+
assert state.pending_consolidations == []
373+
374+
375+
@with_electra_and_later
376+
@spec_state_test
377+
def test_pending_consolidation_source_balance_less_than_max_effective_compounding(spec, state):
378+
current_epoch = spec.get_current_epoch(state)
379+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
380+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
381+
# append pending consolidation
382+
state.pending_consolidations.append(
383+
spec.PendingConsolidation(source_index=source_index, target_index=target_index)
384+
)
385+
# Set withdrawable epoch to current epoch to allow processing
386+
state.validators[source_index].withdrawable_epoch = current_epoch
387+
# Set source and target withdrawal credential to compounding
388+
set_compounding_withdrawal_credential_with_balance(spec, state, source_index)
389+
set_compounding_withdrawal_credential_with_balance(spec, state, target_index)
390+
# Set the source balance to be less than effective_balance
391+
pre_balance_source = state.validators[source_index].effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 8
392+
state.balances[source_index] = pre_balance_source
393+
394+
pre_balance_target = state.balances[target_index]
395+
396+
assert state.balances[source_index] < spec.get_max_effective_balance(state.validators[source_index])
397+
398+
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
399+
400+
# Pending consolidation was successfully processed
401+
assert state.balances[target_index] == pre_balance_target + pre_balance_source
402+
assert state.balances[source_index] == 0
403+
assert state.pending_consolidations == []
404+
405+
406+
@with_electra_and_later
407+
@spec_state_test
408+
def test_pending_consolidation_source_balance_greater_than_max_effective_compounding(spec, state):
409+
current_epoch = spec.get_current_epoch(state)
410+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
411+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
412+
# append pending consolidation
413+
state.pending_consolidations.append(
414+
spec.PendingConsolidation(source_index=source_index, target_index=target_index)
415+
)
416+
# Set withdrawable epoch to current epoch to allow processing
417+
state.validators[source_index].withdrawable_epoch = current_epoch
418+
# Set source and target withdrawal credential to compounding
419+
set_compounding_withdrawal_credential_with_balance(spec, state, source_index)
420+
set_compounding_withdrawal_credential_with_balance(spec, state, target_index)
421+
# Set the source balance to be greater than effective_balance
422+
excess_source_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 8
423+
pre_balance_source = state.validators[source_index].effective_balance + excess_source_balance
424+
state.balances[source_index] = pre_balance_source
425+
426+
pre_balance_target = state.balances[target_index]
427+
428+
source_max_effective_balance = spec.get_max_effective_balance(state.validators[source_index])
429+
assert state.balances[source_index] > source_max_effective_balance
430+
431+
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
432+
433+
# Pending consolidation was successfully processed
434+
assert state.balances[target_index] == pre_balance_target + source_max_effective_balance
435+
assert state.balances[source_index] == excess_source_balance
436+
assert state.pending_consolidations == []
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from eth2spec.test.helpers.deposits import mock_deposit
2+
from eth2spec.test.helpers.state import next_epoch
3+
from eth2spec.test.context import spec_state_test, with_electra_and_later
4+
from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with
5+
from eth2spec.test.helpers.withdrawals import (
6+
set_eth1_withdrawal_credential_with_balance,
7+
set_compounding_withdrawal_credential_with_balance
8+
)
9+
10+
11+
def run_test_activation_queue_eligibility(spec, state, validator_index, balance):
12+
# move past first two irregular epochs wrt finality
13+
next_epoch(spec, state)
14+
next_epoch(spec, state)
15+
16+
state.balances[validator_index] = balance
17+
state.validators[validator_index].effective_balance = balance
18+
19+
# ready for entrance into activation queue
20+
mock_deposit(spec, state, validator_index)
21+
22+
yield from run_epoch_processing_with(spec, state, 'process_registry_updates')
23+
24+
# validator moved into activation queue if eligible
25+
validator = state.validators[validator_index]
26+
if validator.effective_balance < spec.MIN_ACTIVATION_BALANCE:
27+
assert validator.activation_eligibility_epoch == spec.FAR_FUTURE_EPOCH
28+
else:
29+
assert validator.activation_eligibility_epoch < spec.FAR_FUTURE_EPOCH
30+
31+
32+
@with_electra_and_later
33+
@spec_state_test
34+
def test_activation_queue_eligibility__less_than_min_activation_balance(spec, state):
35+
index = 3
36+
balance = spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT
37+
yield from run_test_activation_queue_eligibility(spec, state, index, balance)
38+
39+
40+
@with_electra_and_later
41+
@spec_state_test
42+
def test_activation_queue_eligibility__min_activation_balance(spec, state):
43+
index = 5
44+
balance = spec.MIN_ACTIVATION_BALANCE
45+
yield from run_test_activation_queue_eligibility(spec, state, index, balance)
46+
47+
48+
@with_electra_and_later
49+
@spec_state_test
50+
def test_activation_queue_eligibility__min_activation_balance_eth1_creds(spec, state):
51+
index = 7
52+
balance = spec.MIN_ACTIVATION_BALANCE
53+
set_eth1_withdrawal_credential_with_balance(spec, state, index)
54+
yield from run_test_activation_queue_eligibility(spec, state, index, balance)
55+
56+
57+
@with_electra_and_later
58+
@spec_state_test
59+
def test_activation_queue_eligibility__min_activation_balance_compounding_creds(spec, state):
60+
index = 11
61+
balance = spec.MIN_ACTIVATION_BALANCE
62+
set_compounding_withdrawal_credential_with_balance(spec, state, index)
63+
yield from run_test_activation_queue_eligibility(spec, state, index, balance)
64+
65+
66+
@with_electra_and_later
67+
@spec_state_test
68+
def test_activation_queue_eligibility__greater_than_min_activation_balance(spec, state):
69+
index = 13
70+
balance = spec.MIN_ACTIVATION_BALANCE + spec.EFFECTIVE_BALANCE_INCREMENT
71+
set_compounding_withdrawal_credential_with_balance(spec, state, index)
72+
yield from run_test_activation_queue_eligibility(spec, state, index, balance)

tests/generators/epoch_processing/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
_new_electra_mods_1 = {key: 'eth2spec.test.electra.epoch_processing.test_process_' + key for key in [
4141
'effective_balance_updates',
4242
'pending_consolidations',
43+
'registry_updates',
4344
]}
4445
# This is a trick to allow tests be split into multiple files and use the same test format.
4546
_new_electra_mods_2 = {key: 'eth2spec.test.electra.epoch_processing.' + key for key in [

0 commit comments

Comments
 (0)