Merge pull request #2103 from ethereum/slash-exit

note in validator guide about slashing and exit operation interaction
This commit is contained in:
Danny Ryan 2020-10-16 08:39:17 -06:00 committed by GitHub
commit 2c337d68ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 15 deletions

View File

@ -358,6 +358,10 @@ The `proof` for each deposit must be constructed against the deposit root contai
Up to `MAX_VOLUNTARY_EXITS`, [`VoluntaryExit`](./beacon-chain.md#voluntaryexit) objects can be included in the `block`. The exits must satisfy the verification conditions found in [exits processing](./beacon-chain.md#voluntary-exits).
*Note*: If a slashing for a validator is included in the same block as a
voluntary exit, the voluntary exit will fail and cause the block to be invalid
due to the slashing being processed first. Implementers must take heed of this
operation interaction when packing blocks.
#### Packaging into a `SignedBeaconBlock`

View File

@ -1,4 +1,19 @@
from eth2spec.utils import bls
from eth2spec.test.helpers.keys import privkeys
def prepare_signed_exits(spec, state, indices):
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT)
def create_signed_exit(index):
exit = spec.VoluntaryExit(
epoch=spec.get_current_epoch(state),
validator_index=index,
)
signing_root = spec.compute_signing_root(exit, domain)
return spec.SignedVoluntaryExit(message=exit, signature=bls.Sign(privkeys[index], signing_root))
return [create_signed_exit(index) for index in indices]
def sign_voluntary_exit(spec, state, voluntary_exit, privkey):

View File

@ -9,7 +9,7 @@ from eth2spec.test.helpers.block import (
sign_block,
transition_unsigned_block,
)
from eth2spec.test.helpers.keys import privkeys, pubkeys
from eth2spec.test.helpers.keys import pubkeys
from eth2spec.test.helpers.attester_slashings import (
get_valid_attester_slashing_by_indices,
get_valid_attester_slashing,
@ -18,6 +18,7 @@ from eth2spec.test.helpers.attester_slashings import (
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing, check_proposer_slashing_effect
from eth2spec.test.helpers.attestations import get_valid_attestation
from eth2spec.test.helpers.deposits import prepare_state_and_deposit
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
from eth2spec.test.helpers.shard_transitions import get_shard_transition_of_committee
from eth2spec.test.context import (
@ -794,20 +795,6 @@ def test_attestation(spec, state):
assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
def prepare_signed_exits(spec, state, indices):
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT)
def create_signed_exit(index):
exit = spec.VoluntaryExit(
epoch=spec.get_current_epoch(state),
validator_index=index,
)
signing_root = spec.compute_signing_root(exit, domain)
return spec.SignedVoluntaryExit(message=exit, signature=bls.Sign(privkeys[index], signing_root))
return [create_signed_exit(index) for index in indices]
# In phase1 a committee is computed for SHARD_COMMITTEE_PERIOD slots ago,
# exceeding the minimal-config randao mixes memory size.
# Applies to all voluntary-exit sanity block tests.
@ -895,6 +882,51 @@ def test_multiple_different_validator_exits_same_block(spec, state):
assert state.validators[index].exit_epoch < spec.FAR_FUTURE_EPOCH
def run_slash_and_exit(spec, state, slash_index, exit_index, valid=True):
"""
Helper function to run a test that slashes and exits two validators
"""
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state)
proposer_slashing = get_valid_proposer_slashing(
spec, state, slashed_index=slash_index, signed_1=True, signed_2=True)
signed_exit = prepare_signed_exits(spec, state, [exit_index])[0]
block.body.proposer_slashings.append(proposer_slashing)
block.body.voluntary_exits.append(signed_exit)
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=(not valid))
yield 'blocks', [signed_block]
if valid:
yield 'post', state
else:
yield 'post', None
@with_all_phases
@spec_state_test
@disable_process_reveal_deadlines
def test_slash_and_exit_same_index(spec, state):
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
yield from run_slash_and_exit(spec, state, validator_index, validator_index, valid=False)
@with_all_phases
@spec_state_test
@disable_process_reveal_deadlines
def test_slash_and_exit_diff_index(spec, state):
slash_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
exit_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-2]
yield from run_slash_and_exit(spec, state, slash_index, exit_index)
@with_all_phases
@spec_state_test
def test_balance_driven_status_transitions(spec, state):