add exit queue test
This commit is contained in:
parent
f7c5b0a1c6
commit
37004404d0
|
@ -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`
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue