From 53d4fa51871e007b1362637824566d72d2fa3d0f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 13 Oct 2021 02:01:13 +0800 Subject: [PATCH] Make operation (attester_slashing, proposer_slashing, voluntary_exit) at the fork block --- .../test/altair/transition/test_activation.py | 41 +++++++++- .../test/altair/transition/test_slashing.py | 82 ++++++++++++++++++- .../eth2spec/test/helpers/fork_transition.py | 16 ++-- 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py b/tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py index 83933d751..91888b0c3 100644 --- a/tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py +++ b/tests/core/pyspec/eth2spec/test/altair/transition/test_activation.py @@ -10,6 +10,10 @@ from eth2spec.test.helpers.fork_transition import ( transition_until_fork, ) from eth2spec.test.helpers.random import set_some_new_deposits +from eth2spec.test.helpers.state import ( + transition_to, +) +from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits # @@ -114,6 +118,39 @@ def test_transition_with_one_fourth_exiting_validators_exit_at_fork( yield "post", state +@fork_transition_test(PHASE0, ALTAIR, fork_epoch=260) +def test_transition_with_voluntary_exit_at_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): + """ + Create an attester slashing at the transition + """ + transition_to(spec, state, spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH) + transition_until_fork(spec, state, fork_epoch) + + yield "pre", state + + validator_index = 0 + signed_exits = prepare_signed_exits(spec, state, [validator_index]) + operation_dict = {'voluntary_exits': signed_exits} + + # irregular state transition to handle fork: + state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) + blocks = [] + blocks.append(post_tag(block)) + + validator = state.validators[validator_index] + assert validator.exit_epoch < post_spec.FAR_FUTURE_EPOCH + + # continue regular state transition with new spec into next epoch + to_slot = post_spec.SLOTS_PER_EPOCH + state.slot + blocks.extend([ + post_tag(block) for block in + state_transition_across_slots(post_spec, state, to_slot) + ]) + + yield "blocks", blocks + yield "post", state + + # # Activation # @@ -164,9 +201,9 @@ def test_transition_with_deposit_at_fork(state, fork_epoch, spec, post_spec, pre validator_index = len(state.validators) amount = post_spec.MAX_EFFECTIVE_BALANCE deposit = prepare_state_and_deposit(post_spec, state, validator_index, amount, signed=True) - + operation_dict = {'deposits': [deposit]} # irregular state transition to handle fork: - state, block = do_altair_fork(state, spec, post_spec, fork_epoch, deposits=[deposit]) + state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) blocks = [] blocks.append(post_tag(block)) diff --git a/tests/core/pyspec/eth2spec/test/altair/transition/test_slashing.py b/tests/core/pyspec/eth2spec/test/altair/transition/test_slashing.py index d3b9c5b2f..018ce6781 100644 --- a/tests/core/pyspec/eth2spec/test/altair/transition/test_slashing.py +++ b/tests/core/pyspec/eth2spec/test/altair/transition/test_slashing.py @@ -1,8 +1,18 @@ import random -from eth2spec.test.context import fork_transition_test +from eth2spec.test.context import ( + always_bls, + fork_transition_test, +) from eth2spec.test.helpers.constants import PHASE0, ALTAIR +from eth2spec.test.helpers.attester_slashings import ( + get_valid_attester_slashing, +) +from eth2spec.test.helpers.proposer_slashings import ( + get_valid_proposer_slashing, +) from eth2spec.test.helpers.fork_transition import ( do_altair_fork, + state_transition_across_slots, state_transition_across_slots_with_ignoring_proposers, transition_until_fork, ) @@ -59,3 +69,73 @@ def test_transition_with_one_fourth_slashed_active_validators_pre_fork( yield "blocks", blocks yield "post", state + + +@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2) +@always_bls +def test_transition_with_attester_slashing_at_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): + """ + Create an attester slashing at the transition + """ + transition_until_fork(spec, state, fork_epoch) + + yield "pre", state + + # NOTE: it can only be created with pre spec + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) + operation_dict = {'attester_slashings': [attester_slashing]} + + # irregular state transition to handle fork: + state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) + blocks = [] + blocks.append(post_tag(block)) + + indices = set(attester_slashing.attestation_1.attesting_indices).intersection( + attester_slashing.attestation_2.attesting_indices + ) + assert len(indices) > 0 + for validator_index in indices: + assert state.validators[validator_index].slashed + + # continue regular state transition with new spec into next epoch + to_slot = post_spec.SLOTS_PER_EPOCH + state.slot + blocks.extend([ + post_tag(block) for block in + state_transition_across_slots(post_spec, state, to_slot) + ]) + + yield "blocks", blocks + yield "post", state + + +@fork_transition_test(PHASE0, ALTAIR, fork_epoch=2) +@always_bls +def test_transition_with_proposer_slashing_at_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): + """ + Create an attester slashing at the transition + """ + transition_until_fork(spec, state, fork_epoch) + + yield "pre", state + + # NOTE: it can only be created with pre spec + proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) + operation_dict = {'proposer_slashings': [proposer_slashing]} + + # irregular state transition to handle fork: + state, block = do_altair_fork(state, spec, post_spec, fork_epoch, operation_dict=operation_dict) + blocks = [] + blocks.append(post_tag(block)) + + slashed_proposer = state.validators[proposer_slashing.signed_header_1.message.proposer_index] + assert slashed_proposer.slashed + + # continue regular state transition with new spec into next epoch + to_slot = post_spec.SLOTS_PER_EPOCH + state.slot + blocks.extend([ + post_tag(block) for block in + state_transition_across_slots(post_spec, state, to_slot) + ]) + + yield "blocks", blocks + yield "post", state diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index 3a9977326..e0e7d028b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -12,7 +12,10 @@ from eth2spec.test.helpers.block import ( ) -def _state_transition_and_sign_block_at_slot(spec, state, deposits=None): +def _state_transition_and_sign_block_at_slot(spec, + state, + *, + operation_dict=None): """ Cribbed from ``transition_unsigned_block`` helper where the early parts of the state transition have already @@ -21,9 +24,10 @@ def _state_transition_and_sign_block_at_slot(spec, state, deposits=None): Used to produce a block during an irregular state transition. """ block = build_empty_block(spec, state) - # FIXME: not just passing `deposits` - if deposits is not None: - block.body.deposits = deposits + # we can't just pass `body` because randao_reveal and eth1_data was set in `build_empty_block` + if operation_dict is not None: + for key, value in operation_dict.items(): + setattr(block.body, key, value) assert state.latest_block_header.slot < block.slot assert state.slot == block.slot @@ -93,7 +97,7 @@ def state_transition_across_slots_with_ignoring_proposers(spec, state, to_slot, next_slot(spec, state) -def do_altair_fork(state, spec, post_spec, fork_epoch, with_block=True, deposits=None): +def do_altair_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict=None): spec.process_slots(state, state.slot + 1) assert state.slot % spec.SLOTS_PER_EPOCH == 0 @@ -106,7 +110,7 @@ def do_altair_fork(state, spec, post_spec, fork_epoch, with_block=True, deposits assert state.fork.current_version == post_spec.config.ALTAIR_FORK_VERSION if with_block: - return state, _state_transition_and_sign_block_at_slot(post_spec, state, deposits=deposits) + return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict) else: return state, None