2019-05-06 17:10:43 +02:00

173 lines
5.3 KiB
Python

import pytest
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import (
get_active_validator_indices,
get_churn_limit,
get_current_epoch,
process_voluntary_exit,
)
from tests.helpers import (
build_voluntary_exit,
pubkey_to_privkey,
)
from tests.context import spec_state_test
def run_voluntary_exit_processing(state, voluntary_exit, valid=True):
"""
Run ``process_voluntary_exit``, yielding:
- pre-state ('pre')
- voluntary_exit ('voluntary_exit')
- post-state ('post').
If ``valid == False``, run expecting ``AssertionError``
"""
validator_index = voluntary_exit.validator_index
pre_exit_epoch = state.validator_registry[validator_index].exit_epoch
yield 'pre', state
yield 'voluntary_exit', voluntary_exit
if not valid:
with pytest.raises(AssertionError):
process_voluntary_exit(state, voluntary_exit)
yield 'post', None
return
process_voluntary_exit(state, voluntary_exit)
yield 'post', state
assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
@spec_state_test
def test_success(state):
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
validator_index,
privkey,
)
yield from run_voluntary_exit_processing(state, voluntary_exit)
@spec_state_test
def test_success_exit_queue(state):
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = get_current_epoch(state)
# exit `MAX_EXITS_PER_EPOCH`
initial_indices = get_active_validator_indices(state, current_epoch)[:get_churn_limit(state)]
# Prepare a bunch of exits, based on the current state
exit_queue = []
for index in initial_indices:
privkey = pubkey_to_privkey[state.validator_registry[index].pubkey]
exit_queue.append(build_voluntary_exit(
state,
current_epoch,
index,
privkey,
))
# 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(state, voluntary_exit):
continue
# exit an additional validator
validator_index = get_active_validator_indices(state, current_epoch)[-1]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
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(state, voluntary_exit)
assert (
state.validator_registry[validator_index].exit_epoch ==
state.validator_registry[initial_indices[0]].exit_epoch + 1
)
@spec_state_test
def test_validator_not_active(state):
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
state.validator_registry[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
# build and test voluntary exit
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
validator_index,
privkey,
)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@spec_state_test
def test_validator_already_exited(state):
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow validator able to exit
state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
# but validator already has exited
state.validator_registry[validator_index].exit_epoch = current_epoch + 2
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
validator_index,
privkey,
)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@spec_state_test
def test_validator_not_active_long_enough(state):
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
validator_index,
privkey,
)
assert (
current_epoch - state.validator_registry[validator_index].activation_epoch <
spec.PERSISTENT_COMMITTEE_PERIOD
)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)