Skip to content

Commit bb597fc

Browse files
committed
fix new process_voluntary_exit tests for eip7251
1 parent 1d81af3 commit bb597fc

File tree

2 files changed

+297
-467
lines changed

2 files changed

+297
-467
lines changed
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
from eth2spec.test.helpers.constants import MAINNET
2+
from eth2spec.test.context import (
3+
spec_state_test,
4+
with_eip7251_and_later,
5+
with_presets,
6+
)
7+
from eth2spec.test.helpers.keys import pubkey_to_privkey
8+
from eth2spec.test.helpers.voluntary_exits import (
9+
run_voluntary_exit_processing,
10+
sign_voluntary_exit,
11+
)
12+
# ********************
13+
# * EXIT QUEUE TESTS *
14+
# ********************
15+
16+
17+
@with_eip7251_and_later
18+
@spec_state_test
19+
def test_min_balance_exit(spec, state):
20+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
21+
# This state has 64 validators each with 32 ETH
22+
current_epoch = spec.get_current_epoch(state)
23+
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
24+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
25+
churn_limit = spec.get_activation_exit_churn_limit(state)
26+
# Set the balance to consume equal to churn limit
27+
state.exit_balance_to_consume = churn_limit
28+
29+
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[0]
30+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
31+
signed_voluntary_exit = sign_voluntary_exit(
32+
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
33+
34+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
35+
36+
# Check exit queue churn is set correctly
37+
assert state.exit_balance_to_consume == churn_limit - spec.MIN_ACTIVATION_BALANCE
38+
# Check exit epoch and withdrawable epoch
39+
assert state.validators[0].exit_epoch == expected_exit_epoch
40+
assert state.validators[0].withdrawable_epoch == expected_withdrawable_epoch
41+
# Check earliest_exit_epoch
42+
assert state.earliest_exit_epoch == expected_exit_epoch
43+
44+
45+
@with_eip7251_and_later
46+
@spec_state_test
47+
def test_min_balance_exits_up_to_churn(spec, state):
48+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
49+
# This state has 64 validators each with 32 ETH
50+
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
51+
churn_limit = spec.get_activation_exit_churn_limit(state)
52+
# Set the balance to consume equal to churn limit
53+
state.exit_balance_to_consume = churn_limit
54+
num_to_exit = churn_limit // single_validator_balance
55+
56+
# Exit all but 1 validators, all fit in the churn limit
57+
for i in range(num_to_exit-1):
58+
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[i]
59+
spec.initiate_validator_exit(state, validator_index)
60+
61+
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[num_to_exit]
62+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
63+
signed_voluntary_exit = sign_voluntary_exit(
64+
spec, state, spec.VoluntaryExit(epoch=spec.get_current_epoch(state), validator_index=validator_index), privkey)
65+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
66+
67+
# Last validator also fits in the churn limit
68+
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
69+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
70+
# Check exit epoch and withdrawable epoch
71+
assert state.validators[num_to_exit].exit_epoch == expected_exit_epoch
72+
assert state.validators[num_to_exit].withdrawable_epoch == expected_withdrawable_epoch
73+
# Check exit queue churn is set
74+
assert state.exit_balance_to_consume == churn_limit - single_validator_balance * num_to_exit
75+
# Check earliest_exit_epoch
76+
assert state.earliest_exit_epoch == expected_exit_epoch
77+
78+
79+
@with_eip7251_and_later
80+
@spec_state_test
81+
def test_min_balance_exits_above_churn(spec, state):
82+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
83+
# This state has 64 validators each with 32 ETH
84+
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
85+
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
86+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
87+
churn_limit = spec.get_activation_exit_churn_limit(state)
88+
# Set the balance to consume equal to churn limit
89+
state.exit_balance_to_consume = churn_limit
90+
num_to_exit = churn_limit // single_validator_balance
91+
92+
# Exit all but 1 validators, all fit in the churn limit
93+
for i in range(num_to_exit):
94+
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[i]
95+
spec.initiate_validator_exit(state, validator_index)
96+
97+
# Exit one more validator, not fitting in the churn limit
98+
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[num_to_exit]
99+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
100+
signed_voluntary_exit = sign_voluntary_exit(
101+
spec, state, spec.VoluntaryExit(epoch=spec.get_current_epoch(state), validator_index=validator_index), privkey)
102+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
103+
104+
# Check exit epoch and withdrawable epoch. Last validator exits one epoch later
105+
assert state.validators[num_to_exit].exit_epoch == expected_exit_epoch + 1
106+
assert state.validators[num_to_exit].withdrawable_epoch == expected_withdrawable_epoch + 1
107+
# Check exit balance to consume is set correctly
108+
remainder = (num_to_exit + 1) * single_validator_balance % churn_limit
109+
assert state.exit_balance_to_consume == churn_limit - remainder
110+
# Check earliest_exit_epoch
111+
assert state.earliest_exit_epoch == expected_exit_epoch + 1
112+
113+
114+
@with_eip7251_and_later
115+
@spec_state_test
116+
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
117+
def test_max_balance_exit(spec, state):
118+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
119+
current_epoch = spec.get_current_epoch(state)
120+
churn_limit = spec.get_activation_exit_churn_limit(state)
121+
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
122+
# Set validator effective balance to 2048 ETH
123+
to_exit = spec.MAX_EFFECTIVE_BALANCE_EIP7251
124+
state.validators[validator_index].effective_balance = to_exit
125+
126+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
127+
signed_voluntary_exit = sign_voluntary_exit(
128+
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
129+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
130+
131+
# Check exit epoch and withdrawable epoch
132+
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
133+
expected_exit_epoch += to_exit // churn_limit
134+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
135+
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
136+
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
137+
# Check exit_balance_to_consume
138+
remainder = to_exit % churn_limit
139+
assert state.exit_balance_to_consume == churn_limit - remainder
140+
# Check earliest_exit_epoch
141+
assert state.earliest_exit_epoch == expected_exit_epoch
142+
143+
144+
@with_eip7251_and_later
145+
@spec_state_test
146+
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
147+
def test_exit_with_balance_equal_to_churn_limit(spec, state):
148+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
149+
current_epoch = spec.get_current_epoch(state)
150+
churn_limit = spec.get_activation_exit_churn_limit(state)
151+
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
152+
# Set 0th validator effective balance to churn_limit
153+
state.validators[validator_index].effective_balance = churn_limit
154+
155+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
156+
signed_voluntary_exit = sign_voluntary_exit(
157+
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
158+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
159+
160+
# Validator consumes churn limit fully in the current epoch
161+
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
162+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
163+
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
164+
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
165+
# Check exit_balance_to_consume
166+
assert state.exit_balance_to_consume == 0
167+
# Check earliest_exit_epoch
168+
assert state.earliest_exit_epoch == expected_exit_epoch
169+
170+
171+
@with_eip7251_and_later
172+
@spec_state_test
173+
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
174+
def test_exit_with_balance_multiple_of_churn_limit(spec, state):
175+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
176+
current_epoch = spec.get_current_epoch(state)
177+
churn_limit = spec.get_activation_exit_churn_limit(state)
178+
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
179+
# Set validator effective balance to a multiple of churn_limit
180+
epochs_to_consume = 3
181+
state.validators[0].effective_balance = epochs_to_consume * churn_limit
182+
183+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
184+
signed_voluntary_exit = sign_voluntary_exit(
185+
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
186+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
187+
188+
# Validator consumes churn limit fully in the next 3 epochs (current included)
189+
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + epochs_to_consume
190+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
191+
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
192+
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
193+
# Check exit_balance_to_consume
194+
assert state.exit_balance_to_consume == churn_limit
195+
# Check earliest_exit_epoch
196+
assert state.earliest_exit_epoch == expected_exit_epoch
197+
198+
199+
200+
@with_eip7251_and_later
201+
@spec_state_test
202+
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
203+
def test_exit_existing_churn_and_churn_limit_balance(spec, state):
204+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
205+
current_epoch = spec.get_current_epoch(state)
206+
churn_limit = spec.get_activation_exit_churn_limit(state)
207+
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
208+
209+
# set exit epoch to the first available one and set exit balance to consume to full churn limit
210+
earliest_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
211+
state.earliest_exit_epoch = earliest_exit_epoch
212+
state.exit_balance_to_consume = churn_limit
213+
# consume some churn in exit epoch
214+
existing_churn = spec.EFFECTIVE_BALANCE_INCREMENT
215+
state.exit_balance_to_consume -= existing_churn
216+
# Set validator effective balance to the churn limit
217+
state.validators[validator_index].effective_balance = churn_limit
218+
219+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
220+
signed_voluntary_exit = sign_voluntary_exit(
221+
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
222+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
223+
224+
expected_exit_epoch = earliest_exit_epoch + 1
225+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
226+
# Check exit epoch
227+
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
228+
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
229+
# Check balance consumed in exit epoch is the remainder 1 ETH
230+
assert state.exit_balance_to_consume == churn_limit - existing_churn
231+
# check earliest exit epoch
232+
assert state.earliest_exit_epoch == expected_exit_epoch
233+
234+
235+
236+
@with_eip7251_and_later
237+
@spec_state_test
238+
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
239+
def test_exit_existing_churn_and_balance_multiple_of_churn_limit(spec, state):
240+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
241+
current_epoch = spec.get_current_epoch(state)
242+
churn_limit = spec.get_activation_exit_churn_limit(state)
243+
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
244+
245+
# set exit epoch to the first available one and set exit balance to consume to full churn limit
246+
earliest_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
247+
state.earliest_exit_epoch = earliest_exit_epoch
248+
state.exit_balance_to_consume = churn_limit
249+
# consume some churn in exit epoch
250+
existing_churn = spec.EFFECTIVE_BALANCE_INCREMENT
251+
state.exit_balance_to_consume -= existing_churn
252+
253+
# Set validator effective balance to a multiple of churn_limit
254+
epochs_to_consume = 3
255+
state.validators[validator_index].effective_balance = epochs_to_consume * churn_limit
256+
257+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
258+
signed_voluntary_exit = sign_voluntary_exit(
259+
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
260+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
261+
262+
# Validator fully consumes epochs_to_consume and gets into the next one
263+
expected_exit_epoch = earliest_exit_epoch + epochs_to_consume
264+
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
265+
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
266+
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
267+
# Check exit_balance_to_consume
268+
assert state.exit_balance_to_consume == churn_limit - existing_churn
269+
# Check earliest_exit_epoch
270+
assert state.earliest_exit_epoch == expected_exit_epoch
271+
272+
273+
274+
@with_eip7251_and_later
275+
@spec_state_test
276+
def test_invalid_validator_has_pending_withdrawal(spec, state):
277+
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
278+
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
279+
280+
281+
current_epoch = spec.get_current_epoch(state)
282+
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
283+
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
284+
285+
voluntary_exit = spec.VoluntaryExit(
286+
epoch=current_epoch,
287+
validator_index=validator_index,
288+
)
289+
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
290+
291+
state.pending_partial_withdrawals.append(spec.PendingPartialWithdrawal(
292+
index=validator_index,
293+
amount=1,
294+
withdrawable_epoch=spec.compute_activation_exit_epoch(current_epoch),
295+
))
296+
297+
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)

0 commit comments

Comments
 (0)