Skip to content

Commit 55c5b10

Browse files
authored
Merge pull request #3 from fradamt/pr/ralexstokes/3656-1
New consolidation tests, comments
2 parents b87f1fc + 4c60dad commit 55c5b10

File tree

10 files changed

+1109
-499
lines changed

10 files changed

+1109
-499
lines changed

specs/_features/eip7251/beacon-chain.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
509509
def switch_to_compounding_validator(state: BeaconState, index: ValidatorIndex) -> None:
510510
validator = state.validators[index]
511511
if has_eth1_withdrawal_credential(validator):
512-
validator.withdrawal_credentials[:1] = COMPOUNDING_WITHDRAWAL_PREFIX
512+
validator.withdrawal_credentials = COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
513513
queue_excess_active_balance(state, index)
514514
```
515515

tests/core/pyspec/eth2spec/test/eip7251/block_processing/test_process_consolidation.py

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,49 @@
3030
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, threshold_fn=default_activation_threshold)
3131
@spec_test
3232
@single_phase
33-
def test_basic_consolidation(spec, state):
34-
print(spec.config.PRESET_BASE)
33+
def test_basic_consolidation_in_current_consolidation_epoch(spec, state):
3534
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
35+
current_epoch = spec.get_current_epoch(state)
36+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
37+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
38+
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
39+
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
40+
41+
# Set source and target withdrawal credentials to the same eth1 credential
42+
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
43+
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
44+
45+
signed_consolidation = sign_consolidation(spec, state,
46+
spec.Consolidation(
47+
epoch=current_epoch,
48+
source_index=source_index,
49+
target_index=target_index),
50+
source_privkey, target_privkey)
51+
52+
# Set earliest consolidation epoch to the expected exit epoch
53+
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
54+
state.earliest_consolidation_epoch = expected_exit_epoch
3655
consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
3756
# Set the consolidation balance to consume equal to churn limit
3857
state.consolidation_balance_to_consume = consolidation_churn_limit
58+
59+
yield from run_consolidation_processing(spec, state, signed_consolidation)
60+
61+
# Check consolidation churn is decremented correctly
62+
assert state.consolidation_balance_to_consume == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
63+
# Check exit epoch
64+
assert state.validators[0].exit_epoch == expected_exit_epoch
65+
66+
@with_eip7251_and_later
67+
@with_presets([MINIMAL], "need sufficient consolidation churn limit")
68+
@with_custom_state(
69+
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, threshold_fn=default_activation_threshold)
70+
@spec_test
71+
@single_phase
72+
def test_basic_consolidation_in_new_consolidation_epoch(spec, state):
73+
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
74+
# Set consolidation balance to consume to some arbitrary nonzero value below the churn limit
75+
state.consolidation_balance_to_consume = spec.EFFECTIVE_BALANCE_INCREMENT
3976
current_epoch = spec.get_current_epoch(state)
4077
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
4178
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
@@ -56,7 +93,92 @@ def test_basic_consolidation(spec, state):
5693

5794
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
5895
# Check consolidation churn is decremented correctly
96+
# consolidation_balance_to_consume is replenished to the churn limit since we move to a new consolidation epoch
97+
consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
5998
assert state.consolidation_balance_to_consume == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
99+
# Check exit epochs
100+
assert state.validators[0].exit_epoch == expected_exit_epoch
101+
102+
103+
@with_eip7251_and_later
104+
@with_presets([MINIMAL], "need sufficient consolidation churn limit")
105+
@with_custom_state(
106+
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, threshold_fn=default_activation_threshold)
107+
@spec_test
108+
@single_phase
109+
def test_basic_consolidation_with_preexisting_churn(spec, state):
110+
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
111+
current_epoch = spec.get_current_epoch(state)
112+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
113+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
114+
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
115+
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
116+
117+
# Set source and target withdrawal credentials to the same eth1 credential
118+
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
119+
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
120+
121+
signed_consolidation = sign_consolidation(spec, state,
122+
spec.Consolidation(
123+
epoch=current_epoch,
124+
source_index=source_index,
125+
target_index=target_index),
126+
source_privkey, target_privkey)
127+
128+
# Set earliest consolidation epoch to the expected exit epoch
129+
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
130+
state.earliest_consolidation_epoch = expected_exit_epoch
131+
# Set some nonzero preexisting churn lower than churn limit and sufficient to process the consolidation
132+
preexisting_churn = 2*spec.MIN_ACTIVATION_BALANCE
133+
state.consolidation_balance_to_consume = preexisting_churn
134+
135+
yield from run_consolidation_processing(spec, state, signed_consolidation)
136+
137+
# Check consolidation churn is decremented correctly
138+
assert state.consolidation_balance_to_consume == preexisting_churn - spec.MIN_ACTIVATION_BALANCE
139+
# Check exit epoch
140+
assert state.validators[0].exit_epoch == expected_exit_epoch
141+
142+
143+
@with_eip7251_and_later
144+
@with_presets([MINIMAL], "need sufficient consolidation churn limit")
145+
@with_custom_state(
146+
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, threshold_fn=default_activation_threshold)
147+
@spec_test
148+
@single_phase
149+
def test_basic_consolidation_with_insufficient_preexisting_churn(spec, state):
150+
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
151+
current_epoch = spec.get_current_epoch(state)
152+
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
153+
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
154+
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
155+
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
156+
157+
# Set source and target withdrawal credentials to the same eth1 credential
158+
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
159+
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
160+
161+
signed_consolidation = sign_consolidation(spec, state,
162+
spec.Consolidation(
163+
epoch=current_epoch,
164+
source_index=source_index,
165+
target_index=target_index),
166+
source_privkey, target_privkey)
167+
168+
# Set earliest consolidation epoch to the first available epoch
169+
state.earliest_consolidation_epoch = spec.compute_activation_exit_epoch(current_epoch)
170+
# Set preexisting churn lower than required to process the consolidation
171+
preexisting_churn = spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT
172+
state.consolidation_balance_to_consume = preexisting_churn
173+
174+
yield from run_consolidation_processing(spec, state, signed_consolidation)
175+
176+
# It takes one more epoch to process the consolidation due to insufficient churn
177+
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) + 1
178+
# Check consolidation churn is decremented correctly
179+
consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
180+
remainder = spec.MIN_ACTIVATION_BALANCE % preexisting_churn
181+
assert state.consolidation_balance_to_consume == consolidation_churn_limit - remainder
60182
# Check exit epoch
61183
assert state.validators[0].exit_epoch == expected_exit_epoch
62184

@@ -111,6 +233,7 @@ def test_consolidation_churn_limit_balance(spec, state):
111233
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
112234
source_validator = state.validators[source_index]
113235
source_validator.effective_balance = consolidation_churn_limit
236+
# Churn limit increases due to higher total balance
114237
updated_consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
115238
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
116239
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
@@ -128,6 +251,7 @@ def test_consolidation_churn_limit_balance(spec, state):
128251
source_privkey, target_privkey)
129252
yield from run_consolidation_processing(spec, state, signed_consolidation)
130253

254+
# validator's effective balance fits into the churn, exit as soon as possible
131255
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
132256
# Check consolidation churn is decremented correctly
133257
assert state.consolidation_balance_to_consume == updated_consolidation_churn_limit - consolidation_churn_limit
@@ -157,6 +281,7 @@ def test_consolidation_balance_larger_than_churn_limit(spec, state):
157281
set_compounding_withdrawal_credential(spec, state, source_index)
158282
set_compounding_withdrawal_credential(spec, state, target_index)
159283

284+
# Consolidation churn limit increases due to higher total balance
160285
new_churn_limit = spec.get_consolidation_churn_limit(state)
161286
remainder = state.validators[source_index].effective_balance % new_churn_limit
162287
expected_balance = new_churn_limit - remainder
@@ -464,6 +589,21 @@ def test_invalid_exceed_pending_consolidations_limit(spec, state):
464589
source_privkey, target_privkey)
465590
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
466591

592+
@with_eip7251_and_later
593+
@spec_state_test
594+
def test_invalid_not_enough_consolidation_churn_available(spec, state):
595+
state.validators = state.validators[0:2]
596+
state.pending_consolidations = [spec.PendingConsolidation(source_index=0, target_index=1)]
597+
current_epoch = spec.get_current_epoch(state)
598+
source_privkey = pubkey_to_privkey[state.validators[0].pubkey]
599+
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
600+
# Set source and target withdrawal credentials to the same eth1 credential
601+
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
602+
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
603+
signed_consolidation = sign_consolidation(spec, state,
604+
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
605+
source_privkey, target_privkey)
606+
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
467607

468608
@with_eip7251_and_later
469609
@spec_state_test

0 commit comments

Comments
 (0)