Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include recently slashed churn in exit churn queue #785

Merged
merged 7 commits into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -2089,16 +2089,21 @@ def update_validator_registry(state: BeaconState) -> None:
activate_validator(state, index, is_genesis=False)

# Exit validators within the allowable balance churn
balance_churn = 0
for index, validator in enumerate(state.validator_registry):
if validator.exit_epoch == FAR_FUTURE_EPOCH and validator.initiated_exit:
# Check the balance churn would be within the allowance
balance_churn += get_effective_balance(state, index)
if balance_churn > max_balance_churn:
break
if current_epoch < state.validator_registry_update_epoch + LATEST_SLASHED_EXIT_LENGTH:
balance_churn = (
state.latest_slashed_balances[state.validator_registry_update_epoch % LATEST_SLASHED_EXIT_LENGTH] -
state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
)

for index, validator in enumerate(state.validator_registry):
if validator.exit_epoch == FAR_FUTURE_EPOCH and validator.initiated_exit:
# Check the balance churn would be within the allowance
balance_churn += get_effective_balance(state, index)
if balance_churn > max_balance_churn:
break

# Exit validator
exit_validator(state, index)
# Exit validator
exit_validator(state, index)

state.validator_registry_update_epoch = current_epoch
```
Expand Down
48 changes: 46 additions & 2 deletions tests/phase0/test_sanity.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,18 @@ def test_attestation(state, pubkeys, privkeys):

def test_voluntary_exit(state, pubkeys, privkeys):
pre_state = deepcopy(state)
validator_index = get_active_validator_indices(pre_state.validator_registry, get_current_epoch(pre_state))[-1]
validator_index = get_active_validator_indices(
pre_state.validator_registry,
get_current_epoch(pre_state)
)[-1]

# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# artificially trigger registry update at next epoch transition
pre_state.validator_registry_update_epoch -= 1
pre_state.finalized_epoch = get_current_epoch(pre_state) - 1
for crosslink in pre_state.latest_crosslinks:
crosslink.epoch = pre_state.finalized_epoch
pre_state.validator_registry_update_epoch = pre_state.finalized_epoch - 1

post_state = deepcopy(pre_state)

Expand Down Expand Up @@ -363,6 +369,44 @@ def test_voluntary_exit(state, pubkeys, privkeys):
return pre_state, [initiate_exit_block, exit_block], post_state


def test_no_exit_too_long_since_change(state):
pre_state = deepcopy(state)
validator_index = get_active_validator_indices(
pre_state.validator_registry,
get_current_epoch(pre_state)
)[-1]

#
# 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
# artificially trigger registry update at next epoch transition
pre_state.finalized_epoch = get_current_epoch(pre_state) - 1
for crosslink in pre_state.latest_crosslinks:
crosslink.epoch = pre_state.finalized_epoch
# make epochs since registry update greater than LATEST_SLASHED_EXIT_LENGTH
pre_state.validator_registry_update_epoch = (
get_current_epoch(pre_state) - spec.LATEST_SLASHED_EXIT_LENGTH
)
# set validator to have previously initiated exit
pre_state.validator_registry[validator_index].initiated_exit = True

post_state = deepcopy(pre_state)

#
# Process registry change but ensure no exit
#
block = build_empty_block_for_next_slot(post_state)
block.slot += spec.SLOTS_PER_EPOCH
state_transition(post_state, block)

assert post_state.validator_registry_update_epoch == get_current_epoch(post_state) - 1
assert post_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH

return pre_state, [block], post_state


def test_transfer(state, pubkeys, privkeys):
pre_state = deepcopy(state)
current_epoch = get_current_epoch(pre_state)
Expand Down