fix new process_voluntary_exit tests for eip7251

This commit is contained in:
fradamt 2024-04-14 21:17:17 +02:00
parent 1d81af386c
commit bb597fc326
2 changed files with 297 additions and 467 deletions

View File

@ -0,0 +1,297 @@
from eth2spec.test.helpers.constants import MAINNET
from eth2spec.test.context import (
spec_state_test,
with_eip7251_and_later,
with_presets,
)
from eth2spec.test.helpers.keys import pubkey_to_privkey
from eth2spec.test.helpers.voluntary_exits import (
run_voluntary_exit_processing,
sign_voluntary_exit,
)
# ********************
# * EXIT QUEUE TESTS *
# ********************
@with_eip7251_and_later
@spec_state_test
def test_min_balance_exit(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 64 validators each with 32 ETH
current_epoch = spec.get_current_epoch(state)
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set the balance to consume equal to churn limit
state.exit_balance_to_consume = churn_limit
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Check exit queue churn is set correctly
assert state.exit_balance_to_consume == churn_limit - spec.MIN_ACTIVATION_BALANCE
# Check exit epoch and withdrawable epoch
assert state.validators[0].exit_epoch == expected_exit_epoch
assert state.validators[0].withdrawable_epoch == expected_withdrawable_epoch
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
def test_min_balance_exits_up_to_churn(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 64 validators each with 32 ETH
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set the balance to consume equal to churn limit
state.exit_balance_to_consume = churn_limit
num_to_exit = churn_limit // single_validator_balance
# Exit all but 1 validators, all fit in the churn limit
for i in range(num_to_exit-1):
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[i]
spec.initiate_validator_exit(state, validator_index)
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[num_to_exit]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=spec.get_current_epoch(state), validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Last validator also fits in the churn limit
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# Check exit epoch and withdrawable epoch
assert state.validators[num_to_exit].exit_epoch == expected_exit_epoch
assert state.validators[num_to_exit].withdrawable_epoch == expected_withdrawable_epoch
# Check exit queue churn is set
assert state.exit_balance_to_consume == churn_limit - single_validator_balance * num_to_exit
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
def test_min_balance_exits_above_churn(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 64 validators each with 32 ETH
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set the balance to consume equal to churn limit
state.exit_balance_to_consume = churn_limit
num_to_exit = churn_limit // single_validator_balance
# Exit all but 1 validators, all fit in the churn limit
for i in range(num_to_exit):
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[i]
spec.initiate_validator_exit(state, validator_index)
# Exit one more validator, not fitting in the churn limit
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[num_to_exit]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=spec.get_current_epoch(state), validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Check exit epoch and withdrawable epoch. Last validator exits one epoch later
assert state.validators[num_to_exit].exit_epoch == expected_exit_epoch + 1
assert state.validators[num_to_exit].withdrawable_epoch == expected_withdrawable_epoch + 1
# Check exit balance to consume is set correctly
remainder = (num_to_exit + 1) * single_validator_balance % churn_limit
assert state.exit_balance_to_consume == churn_limit - remainder
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch + 1
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_max_balance_exit(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
churn_limit = spec.get_activation_exit_churn_limit(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
# Set validator effective balance to 2048 ETH
to_exit = spec.MAX_EFFECTIVE_BALANCE_EIP7251
state.validators[validator_index].effective_balance = to_exit
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Check exit epoch and withdrawable epoch
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
expected_exit_epoch += to_exit // churn_limit
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
# Check exit_balance_to_consume
remainder = to_exit % churn_limit
assert state.exit_balance_to_consume == churn_limit - remainder
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_exit_with_balance_equal_to_churn_limit(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
churn_limit = spec.get_activation_exit_churn_limit(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
# Set 0th validator effective balance to churn_limit
state.validators[validator_index].effective_balance = churn_limit
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Validator consumes churn limit fully in the current epoch
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
# Check exit_balance_to_consume
assert state.exit_balance_to_consume == 0
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_exit_with_balance_multiple_of_churn_limit(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
churn_limit = spec.get_activation_exit_churn_limit(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
# Set validator effective balance to a multiple of churn_limit
epochs_to_consume = 3
state.validators[0].effective_balance = epochs_to_consume * churn_limit
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Validator consumes churn limit fully in the next 3 epochs (current included)
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + epochs_to_consume
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
# Check exit_balance_to_consume
assert state.exit_balance_to_consume == churn_limit
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_exit_existing_churn_and_churn_limit_balance(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
churn_limit = spec.get_activation_exit_churn_limit(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
# set exit epoch to the first available one and set exit balance to consume to full churn limit
earliest_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
state.earliest_exit_epoch = earliest_exit_epoch
state.exit_balance_to_consume = churn_limit
# consume some churn in exit epoch
existing_churn = spec.EFFECTIVE_BALANCE_INCREMENT
state.exit_balance_to_consume -= existing_churn
# Set validator effective balance to the churn limit
state.validators[validator_index].effective_balance = churn_limit
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
expected_exit_epoch = earliest_exit_epoch + 1
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
# Check balance consumed in exit epoch is the remainder 1 ETH
assert state.exit_balance_to_consume == churn_limit - existing_churn
# check earliest exit epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_exit_existing_churn_and_balance_multiple_of_churn_limit(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
churn_limit = spec.get_activation_exit_churn_limit(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
# set exit epoch to the first available one and set exit balance to consume to full churn limit
earliest_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
state.earliest_exit_epoch = earliest_exit_epoch
state.exit_balance_to_consume = churn_limit
# consume some churn in exit epoch
existing_churn = spec.EFFECTIVE_BALANCE_INCREMENT
state.exit_balance_to_consume -= existing_churn
# Set validator effective balance to a multiple of churn_limit
epochs_to_consume = 3
state.validators[validator_index].effective_balance = epochs_to_consume * churn_limit
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
# Validator fully consumes epochs_to_consume and gets into the next one
expected_exit_epoch = earliest_exit_epoch + epochs_to_consume
expected_withdrawable_epoch = expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
assert state.validators[validator_index].withdrawable_epoch == expected_withdrawable_epoch
# Check exit_balance_to_consume
assert state.exit_balance_to_consume == churn_limit - existing_churn
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_has_pending_withdrawal(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = spec.VoluntaryExit(
epoch=current_epoch,
validator_index=validator_index,
)
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
state.pending_partial_withdrawals.append(spec.PendingPartialWithdrawal(
index=validator_index,
amount=1,
withdrawable_epoch=spec.compute_activation_exit_epoch(current_epoch),
))
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)

View File

@ -1,467 +0,0 @@
from eth2spec.test.helpers.constants import (MINIMAL, MAINNET)
from eth2spec.test.context import (
spec_state_test,
with_eip7251_and_later,
with_presets,
always_bls,
spec_test, single_phase,
with_custom_state,
scaled_churn_balances_min_churn_limit,
)
from eth2spec.test.helpers.keys import pubkey_to_privkey
from eth2spec.test.helpers.voluntary_exits import (
run_voluntary_exit_processing,
sign_voluntary_exit,
)
# ********************
# * EXIT QUEUE TESTS *
# ********************
@with_eip7251_and_later
@spec_state_test
def test_min_balance_exit(spec, state):
# This state has 64 validators each with 32 ETH
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set the balance to consume equal to churn limit
state.exit_balance_to_consume = churn_limit
yield "pre", state
# Exit validators, all which fit in the churn limit
spec.initiate_validator_exit(state, 0)
yield "post", state
# Check exit queue churn is set
assert state.exit_balance_to_consume == churn_limit - spec.MIN_ACTIVATION_BALANCE
# Check exit epoch
assert state.validators[0].exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
def test_min_balance_exits_up_to_churn(spec, state):
# This state has 64 validators each with 32 ETH
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set the balance to consume equal to churn limit
state.exit_balance_to_consume = churn_limit
yield "pre", state
# Exit validators, all which fit in the churn limit
for i in range(churn_limit // spec.MIN_ACTIVATION_BALANCE):
validator_index = i
spec.initiate_validator_exit(state, validator_index)
yield f"post{i}", state
# Check exit queue churn is set
assert state.exit_balance_to_consume == churn_limit - single_validator_balance * (i + 1)
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
yield "post", state
@with_eip7251_and_later
@spec_state_test
def test_min_balance_exits_above_churn(spec, state):
# This state has 64 validators each with 32 ETH
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set the balance to consume equal to churn limit
state.exit_balance_to_consume = churn_limit
yield "pre", state
# Exit validators, all which fit in the churn limit
for i in range(churn_limit // spec.MIN_ACTIVATION_BALANCE):
validator_index = i
spec.initiate_validator_exit(state, validator_index)
# Check exit queue churn is set
assert state.exit_balance_to_consume == churn_limit - single_validator_balance * (i + 1)
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
# Exit balance has been fully consumed
assert state.exit_balance_to_consume == 0
# Exit an additional validator, doesn't fit in the churn limit, so exit
# epoch is incremented
validator_index = churn_limit // spec.MIN_ACTIVATION_BALANCE
spec.initiate_validator_exit(state, validator_index)
yield "post", state
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch + 1
# Check exit balance to consume is set
assert state.exit_balance_to_consume == churn_limit - single_validator_balance
# @with_eip7251_and_later
# @spec_state_test
# def test_exit_balance_to_consume_large_validator(spec, state):
# # Set 0th validator effective balance to 2048 ETH
# state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE_EIP7251
# churn_limit = spec.get_validator_churn_limit(state)
# expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
# expected_exit_epoch += spec.MAX_EFFECTIVE_BALANCE_EIP7251 // churn_limit
# validator_index = 0
# spec.initiate_validator_exit(state, validator_index)
# # Check exit epoch
# assert state.validators[validator_index].exit_epoch == expected_exit_epoch
# # Check exit_balance_to_consume
# assert state.exit_balance_to_consume == churn_limit - (spec.MAX_EFFECTIVE_BALANCE_EIP7251 % churn_limit)
# # Check earliest_exit_epoch
# assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_max_balance_exit(spec, state):
churn_limit = spec.get_activation_exit_churn_limit(state)
assert churn_limit == spec.MIN_ACTIVATION_BALANCE * spec.config.MIN_PER_EPOCH_CHURN_LIMIT
# Set 0th validator effective balance to 2048 ETH
state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE_EIP7251
yield 'pre', state
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
# Validator consumes exit churn for 16 epochs, exits at the 17th one
expected_exit_epoch += (spec.MAX_EFFECTIVE_BALANCE_EIP7251 // churn_limit)
validator_index = 0
spec.initiate_validator_exit(state, validator_index)
yield 'post', state
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
# Check exit_balance_to_consume
assert state.exit_balance_to_consume == churn_limit
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == expected_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_exit_with_balance_equal_to_churn_limit(spec, state):
churn_limit = spec.get_activation_exit_churn_limit(state)
# Set 0th validator effective balance to churn_limit
state.validators[0].effective_balance = churn_limit
yield 'pre', state
validator_index = 0
spec.initiate_validator_exit(state, validator_index)
yield 'post', state
# Validator consumes churn limit fully in the current epoch
assert (state.validators[validator_index].exit_epoch ==
spec.compute_activation_exit_epoch(spec.get_current_epoch(state)))
# Check exit_balance_to_consume
assert state.exit_balance_to_consume == 0
# Check earliest_exit_epoch
assert state.earliest_exit_epoch == state.validators[validator_index].exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_exit_churn_limit_balance_existing_churn_(spec, state):
cl = spec.get_activation_exit_churn_limit(state)
# set exit epoch to the first available one and set exit balance to consume to full churn limit
state.earliest_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
state.exit_balance_to_consume = cl
# consume some churn in exit epoch
state.exit_balance_to_consume -= 1000000000
# Set 0th validator effective balance to the churn limit
state.validators[0].effective_balance = cl
yield 'pre', state
# The existing 1 ETH churn will push an extra epoch
expected_exit_epoch = state.earliest_exit_epoch + 1
yield 'post', state
validator_index = 0
spec.initiate_validator_exit(state, validator_index)
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
# Check balance consumed in exit epoch is the remainder 1 ETH
assert state.exit_balance_to_consume == cl - 1000000000
# check earliest exit epoch
assert expected_exit_epoch == state.earliest_exit_epoch
@with_eip7251_and_later
@spec_state_test
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
def test_multi_epoch_exit_existing_churn(spec, state):
cl = spec.get_activation_exit_churn_limit(state)
# set exit epoch to the first available one and set exit balance to consume to full churn limit
state.earliest_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
state.exit_balance_to_consume = cl
# consume some churn in exit epoch
state.exit_balance_to_consume -= 1000000000
# Set 0th validator effective balance to 2x the churn limit
state.validators[0].effective_balance = 2 * cl
yield 'pre', state
# Two extra epochs will be necessary
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + 2
validator_index = 0
spec.initiate_validator_exit(state, validator_index)
yield 'post', state
# Check exit epoch
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
# Check balance consumed in exit epoch is the remainder 1 ETH
assert state.exit_balance_to_consume == cl - 1000000000
# check earliest exit epoch
assert expected_exit_epoch == state.earliest_exit_epoch
# Repurposed from phase0 voluntary exit tests, should disable the phase0 ones
def run_test_success_exit_queue(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
churn_limit = spec.get_activation_exit_churn_limit(state)
# exit `MAX_EXITS_PER_EPOCH`
max_exits = churn_limit // spec.MIN_ACTIVATION_BALANCE
initial_indices = spec.get_active_validator_indices(state, current_epoch)[:max_exits]
# Prepare a bunch of exits, based on the current state
exit_queue = []
for index in initial_indices:
privkey = pubkey_to_privkey[state.validators[index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=index), privkey)
exit_queue.append(signed_voluntary_exit)
# Now run all the exits
for voluntary_exit in exit_queue:
# the function yields data, but we are just interested in running it here, ignore yields.
for _ in run_voluntary_exit_processing(spec, state, voluntary_exit):
continue
# exit an additional validator
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
# This is the interesting part of the test: on a pre-state with a full exit queue,
# when processing an additional exit, it results in an exit in a later epoch
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
for index in initial_indices:
assert (
state.validators[validator_index].exit_epoch ==
state.validators[index].exit_epoch + 1
)
assert state.earliest_exit_epoch == state.validators[validator_index].exit_epoch
consumed_churn = spec.MIN_ACTIVATION_BALANCE * (max_exits + 1)
assert state.exit_balance_to_consume == churn_limit - (consumed_churn % churn_limit)
@with_eip7251_and_later
@spec_state_test
def test_success_exit_queue__min_churn(spec, state):
yield from run_test_success_exit_queue(spec, state)
@with_eip7251_and_later
@with_presets([MINIMAL],
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
@spec_test
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
@single_phase
def test_success_exit_queue__scaled_churn(spec, state):
churn_limit = spec.get_activation_exit_churn_limit(state)
assert churn_limit > spec.config.MIN_PER_EPOCH_CHURN_LIMIT
yield from run_test_success_exit_queue(spec, state)
# After here no modifications were made, can just leave them in phase0 as is
@with_eip7251_and_later
@spec_state_test
def test_basic(spec, state):
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
assert state.validators[validator_index].exit_epoch == spec.compute_activation_exit_epoch(current_epoch)
@with_eip7251_and_later
@spec_state_test
@always_bls
def test_invalid_incorrect_signature(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
voluntary_exit = spec.VoluntaryExit(
epoch=current_epoch,
validator_index=validator_index,
)
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, 12345)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
@with_eip7251_and_later
@spec_state_test
def test_default_exit_epoch_subsequent_exit(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
# Exit one validator prior to this new one
exited_index = spec.get_active_validator_indices(state, current_epoch)[-1]
state.validators[exited_index].exit_epoch = current_epoch - 1
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
assert state.validators[validator_index].exit_epoch == spec.compute_activation_exit_epoch(current_epoch)
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_exit_in_future(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = spec.VoluntaryExit(
epoch=current_epoch + 1,
validator_index=validator_index,
)
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_incorrect_validator_index(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = spec.VoluntaryExit(
epoch=current_epoch,
validator_index=len(state.validators),
)
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_not_active(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
state.validators[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_already_exited(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow validator able to exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
# but validator already has exited
state.validators[validator_index].exit_epoch = current_epoch + 2
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_not_active_long_enough(spec, state):
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
signed_voluntary_exit = sign_voluntary_exit(
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
assert (
current_epoch - state.validators[validator_index].activation_epoch <
spec.config.SHARD_COMMITTEE_PERIOD
)
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
@with_eip7251_and_later
@spec_state_test
def test_invalid_validator_has_pending_withdrawal(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
voluntary_exit = spec.VoluntaryExit(
epoch=current_epoch,
validator_index=validator_index,
)
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
state.pending_partial_withdrawals.append(spec.PendingPartialWithdrawal(
index=validator_index,
amount=1,
withdrawable_epoch=spec.compute_activation_exit_epoch(current_epoch),
))
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)