Merge pull request #2103 from ethereum/slash-exit
note in validator guide about slashing and exit operation interaction
This commit is contained in:
commit
2c337d68ff
|
@ -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`
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue