def test_transition_with_leaking_at_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ Leaking starts at epoch 6 (MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2). The leaking starts at the fork transition in this case. """ transition_until_fork(spec, state, fork_epoch) assert not spec.is_in_inactivity_leak(state) assert spec.get_current_epoch(state) < fork_epoch yield "pre", state # irregular state transition to handle fork: blocks = [] state, block = do_altair_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # check post transition state assert spec.is_in_inactivity_leak(state) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True) yield "blocks", blocks yield "post", state
def test_transition_with_non_empty_activation_queue(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ Create some deposits before the transition """ transition_until_fork(spec, state, fork_epoch) deposited_indices = set_some_new_deposits(spec, state, rng=random.Random(5566)) assert spec.get_current_epoch(state) < fork_epoch assert len(deposited_indices) > 0 for validator_index in deposited_indices: assert not spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state)) yield "pre", state # irregular state transition to handle fork: blocks = [] state, block = do_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True) yield "blocks", blocks yield "post", state
def test_transition_with_one_fourth_exiting_validators_exit_at_fork( state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ 1/4 validators initiated voluntary exit before the fork, and being exited and inactive *right after* the fork transition. """ exited_indices = exit_random_validators( spec, state, rng=random.Random(5566), fraction=0.25, exit_epoch=fork_epoch, from_epoch=spec.get_current_epoch(state), ) transition_until_fork(spec, state, fork_epoch) # check pre state assert len(exited_indices) > 0 for index in exited_indices: validator = state.validators[index] assert not validator.slashed assert fork_epoch == validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert spec.is_active_validator(validator, spec.get_current_epoch(state)) assert not spec.is_in_inactivity_leak(state) assert spec.get_current_epoch(state) < fork_epoch yield "pre", state # irregular state transition to handle fork: blocks = [] state, block = do_altair_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # check post transition state for index in exited_indices: validator = state.validators[index] assert not validator.slashed assert not post_spec.is_active_validator( validator, post_spec.get_current_epoch(state)) assert not post_spec.is_in_inactivity_leak(state) # ensure that none of the current sync committee members are exited validators exited_pubkeys = [ state.validators[index].pubkey for index in exited_indices ] assert not any( set(exited_pubkeys).intersection( list(state.current_sync_committee.pubkeys))) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True) yield "blocks", blocks yield "post", state
def test_normal_transition(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ Transition from the initial ``state`` to the epoch after the ``fork_epoch``, producing blocks for every slot along the way. """ yield "pre", state assert spec.get_current_epoch(state) < fork_epoch # regular state transition until fork: to_slot = fork_epoch * spec.SLOTS_PER_EPOCH - 1 blocks = [] blocks.extend([ pre_tag(block) for block in state_transition_across_slots(spec, state, to_slot) ]) # irregular state transition to handle fork: state, block = do_altair_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks) assert state.slot % post_spec.SLOTS_PER_EPOCH == 0 assert post_spec.get_current_epoch(state) == fork_epoch + 1 slots_with_blocks = [block.message.slot for block in blocks] assert len(set(slots_with_blocks)) == len(slots_with_blocks) assert set(range(1, state.slot + 1)) == set(slots_with_blocks) yield "blocks", blocks yield "post", state
def test_transition_with_one_fourth_slashed_active_validators_pre_fork( state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ 1/4 validators are slashed but still active at the fork transition. """ # slash 1/4 validators slashed_indices = slash_random_validators(spec, state, rng=random.Random(5566), fraction=0.25) assert len(slashed_indices) > 0 # check if some validators are slashed but still active for validator_index in slashed_indices: validator = state.validators[validator_index] assert validator.slashed assert spec.is_active_validator(validator, spec.get_current_epoch(state)) assert not spec.is_in_inactivity_leak(state) transition_until_fork(spec, state, fork_epoch) assert spec.get_current_epoch(state) < fork_epoch yield "pre", state # irregular state transition to handle fork: state, _ = do_fork(state, spec, post_spec, fork_epoch, with_block=False) # ensure that some of the current sync committee members are slashed slashed_pubkeys = [ state.validators[index].pubkey for index in slashed_indices ] assert any( set(slashed_pubkeys).intersection( list(state.current_sync_committee.pubkeys))) assert any( set(slashed_pubkeys).difference( list(state.current_sync_committee.pubkeys))) # continue regular state transition with new spec into next epoch # since the proposer might have been slashed, here we only create blocks with non-slashed proposers blocks = [] transition_to_next_epoch_and_append_blocks( post_spec, state, post_tag, blocks, only_last_block=True, ignoring_proposers=slashed_indices, ) # check post state for validator in state.validators: assert post_spec.is_active_validator( validator, post_spec.get_current_epoch(state)) assert not post_spec.is_in_inactivity_leak(state) yield "blocks", blocks yield "post", state
def test_sample_transition(state, fork_epoch, spec, post_spec, pre_tag, post_tag): transition_until_fork(spec, state, fork_epoch) # check pre state assert spec.get_current_epoch(state) < fork_epoch yield "pre", state # irregular state transition to handle fork: blocks = [] state, block = do_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True) yield "blocks", blocks yield "post", state
def test_transition_with_activation_at_fork_epoch(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ Create some deposits before the transition """ transition_until_fork(spec, state, fork_epoch) selected_indices = set_some_activations(spec, state, rng=random.Random(5566), activation_epoch=fork_epoch) assert spec.get_current_epoch(state) < fork_epoch assert len(selected_indices) > 0 for validator_index in selected_indices: validator = state.validators[validator_index] assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) assert validator.activation_epoch == fork_epoch yield "pre", state # irregular state transition to handle fork: blocks = [] state, block = do_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks, only_last_block=True) # now they are active for validator_index in selected_indices: validator = state.validators[validator_index] assert post_spec.is_active_validator( validator, post_spec.get_current_epoch(state)) yield "blocks", blocks yield "post", state
def test_transition_missing_last_pre_fork_block(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ Transition from the initial ``state`` to the epoch after the ``fork_epoch``, producing blocks for every slot along the way except for the last block of the old fork. """ yield "pre", state assert spec.get_current_epoch(state) < fork_epoch # regular state transition until fork: last_slot_of_pre_fork = fork_epoch * spec.SLOTS_PER_EPOCH - 1 to_slot = last_slot_of_pre_fork blocks = [] blocks.extend([ pre_tag(block) for block in state_transition_across_slots( spec, state, to_slot, block_filter=skip_slots(last_slot_of_pre_fork)) ]) # irregular state transition to handle fork: state, block = do_altair_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition with new spec into next epoch transition_to_next_epoch_and_append_blocks(post_spec, state, post_tag, blocks) assert state.slot % post_spec.SLOTS_PER_EPOCH == 0 assert post_spec.get_current_epoch(state) == fork_epoch + 1 slots_with_blocks = [block.message.slot for block in blocks] assert len(set(slots_with_blocks)) == len(slots_with_blocks) expected_slots = set(range(1, state.slot + 1)).difference( set([last_slot_of_pre_fork])) assert expected_slots == set(slots_with_blocks) yield "blocks", blocks yield "post", state