add exit queue test

This commit is contained in:
Danny Ryan 2019-04-14 09:13:53 +10:00
parent f7c5b0a1c6
commit 37004404d0
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
3 changed files with 106 additions and 82 deletions

View File

@ -1311,23 +1311,26 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
Note that this function mutates ``state``.
"""
validator = state.validator_registry[index]
# Operation is a no-op if validator is already in the queue
if validator.exit_epoch == FAR_FUTURE_EPOCH:
# Update exit queue counters
delayed_activation_exit_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
if state.exit_epoch < delayed_activation_exit_epoch:
state.exit_epoch = delayed_activation_exit_epoch
if validator.exit_epoch != FAR_FUTURE_EPOCH:
return
if state.exit_queue_filled >= MAX_EXITS_PER_EPOCH:
state.exit_epoch += 1
state.exit_queue_filled = 0
# Update exit queue counters
delayed_activation_exit_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
if state.exit_epoch < delayed_activation_exit_epoch:
state.exit_epoch = delayed_activation_exit_epoch
# Set validator exit epoch and withdrawable epoch
validator.exit_epoch = state.exit_epoch
validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
if state.exit_queue_filled >= MAX_EXITS_PER_EPOCH:
state.exit_epoch += 1
state.exit_queue_filled = 0
# Extend queue
state.exit_queue_filled += 1
# Set validator exit epoch and withdrawable epoch
validator.exit_epoch = state.exit_epoch
validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# Extend queue
state.exit_queue_filled += 1
```
#### `slash_validator`

View File

@ -15,8 +15,8 @@ from tests.phase0.helpers import (
)
# mark entire file as 'voluntary_exits'
pytestmark = pytest.mark.voluntary_exits
# mark entire file as 'deposits'
pytestmark = pytest.mark.deposits
def test_success(state):

View File

@ -18,124 +18,145 @@ from tests.phase0.helpers import (
pytestmark = pytest.mark.voluntary_exits
def test_success(state):
pre_state = deepcopy(state)
#
# setup pre_state
#
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
def run_voluntary_exit_processing(state, voluntary_exit, valid=True):
"""
Run ``process_voluntary_exit`` returning the pre and post state.
If ``valid == False``, run expecting ``AssertionError``
"""
post_state = deepcopy(state)
#
# build voluntary exit
#
current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
if not valid:
with pytest.raises(AssertionError):
process_voluntary_exit(post_state, voluntary_exit)
return state, None
process_voluntary_exit(post_state, voluntary_exit)
validator_index = voluntary_exit.validator_index
assert state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
assert post_state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
return state, post_state
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.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
pre_state,
state,
current_epoch,
validator_index,
privkey,
)
post_state = deepcopy(pre_state)
pre_state, post_state = run_voluntary_exit_processing(state, voluntary_exit)
return pre_state, voluntary_exit, post_state
#
# test valid exit
#
process_voluntary_exit(post_state, voluntary_exit)
assert pre_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
assert post_state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
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.validator_registry,current_epoch)[:spec.MAX_EXITS_PER_EPOCH]
post_state = state
for index in initial_indices:
privkey = pubkey_to_privkey[state.validator_registry[index].pubkey]
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
index,
privkey,
)
_, post_state = run_voluntary_exit_processing(post_state, voluntary_exit)
# exit an additional validator
validator_index = get_active_validator_indices(state.validator_registry,current_epoch)[-1]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
validator_index,
privkey,
)
pre_state, post_state = run_voluntary_exit_processing(post_state, voluntary_exit)
assert (
post_state.validator_registry[validator_index].exit_epoch ==
post_state.validator_registry[initial_indices[0]].exit_epoch + 1
)
return pre_state, voluntary_exit, post_state
def test_validator_not_active(state):
pre_state = deepcopy(state)
current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
#
# setup pre_state
#
pre_state.validator_registry[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validator_registry[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
#
# build and test voluntary exit
#
voluntary_exit = build_voluntary_exit(
pre_state,
state,
current_epoch,
validator_index,
privkey,
)
with pytest.raises(AssertionError):
process_voluntary_exit(pre_state, voluntary_exit)
return pre_state, voluntary_exit, None
pre_state, post_state = run_voluntary_exit_processing(state, voluntary_exit, False)
return pre_state, voluntary_exit, post_state
def test_validator_already_exited(state):
pre_state = deepcopy(state)
#
# setup pre_state
#
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow validator able to exit
pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
# but validator already has exited
pre_state.validator_registry[validator_index].exit_epoch = current_epoch + 2
state.validator_registry[validator_index].exit_epoch = current_epoch + 2
#
# build voluntary exit
#
voluntary_exit = build_voluntary_exit(
pre_state,
state,
current_epoch,
validator_index,
privkey,
)
with pytest.raises(AssertionError):
process_voluntary_exit(pre_state, voluntary_exit)
return pre_state, voluntary_exit, None
pre_state, post_state = run_voluntary_exit_processing(state, voluntary_exit, False)
return pre_state, voluntary_exit, post_state
def test_validator_not_active_long_enough(state):
pre_state = deepcopy(state)
#
# setup pre_state
#
current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state.validator_registry, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
#
# build voluntary exit
#
voluntary_exit = build_voluntary_exit(
pre_state,
state,
current_epoch,
validator_index,
privkey,
)
assert (
current_epoch - pre_state.validator_registry[validator_index].activation_epoch <
current_epoch - state.validator_registry[validator_index].activation_epoch <
spec.PERSISTENT_COMMITTEE_PERIOD
)
with pytest.raises(AssertionError):
process_voluntary_exit(pre_state, voluntary_exit)
return pre_state, voluntary_exit, None
pre_state, post_state = run_voluntary_exit_processing(state, voluntary_exit, False)
return pre_state, voluntary_exit, post_state