add note about how slashings and exits can interact. add test

This commit is contained in:
Danny Ryan 2020-10-14 17:33:14 -06:00
parent 032a93335c
commit c17a95a175
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
4 changed files with 74 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.

View File

@ -0,0 +1,53 @@
from eth2spec.test.helpers.state import (
state_transition_and_sign_block,
)
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot,
)
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
from eth2spec.test.context import (
spec_state_test,
with_all_phases,
)
def run_slash_and_exit(spec, state, slash_index, exit_index, valid=True):
# 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
def test_slash_and_exit_same_index(spec, state):
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
run_slash_and_exit(spec, state, validator_index, validator_index, valid=False)
@with_all_phases
@spec_state_test
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]
run_slash_and_exit(spec, state, slash_index, exit_index)