Exemple #1
0
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
Exemple #2
0
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_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_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_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
Exemple #4
0
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_no_attestations_until_after_fork(
        state, fork_epoch, spec, post_spec, pre_tag, post_tag):
    """
    Transition from the initial ``state`` to the ``fork_epoch`` with no attestations,
    then transition forward with enough attestations to finalize the fork epoch.
    """
    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_fork(state, spec, post_spec, fork_epoch)
    blocks.append(post_tag(block))

    # continue regular state transition but add attestations
    # for enough epochs to finalize the ``fork_epoch``
    block = next_epoch_via_signed_block(post_spec, state)
    blocks.append(post_tag(block))
    for _ in range(4):
        _, blocks_in_epoch, state = next_slots_with_attestations(
            post_spec,
            state,
            post_spec.SLOTS_PER_EPOCH,
            False,
            True,
        )
        blocks.extend([post_tag(block) for block in blocks_in_epoch])

    assert state.slot % post_spec.SLOTS_PER_EPOCH == 0
    assert post_spec.get_current_epoch(state) == fork_epoch + 5

    assert state.current_justified_checkpoint.epoch == fork_epoch + 3
    assert state.finalized_checkpoint.epoch == fork_epoch + 1

    yield "blocks", blocks
    yield "post", state
Exemple #7
0
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_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
def test_transition_only_blocks_post_fork(state, fork_epoch, spec, post_spec,
                                          pre_tag, post_tag):
    """
    Transition from the initial ``state`` to the epoch after the ``fork_epoch``,
    skipping blocks for every slot along the way except for the first block
    in the ending epoch.
    """
    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=no_blocks)
    ])

    # irregular state transition to handle fork:
    state, _ = do_fork(state, spec, post_spec, fork_epoch, with_block=False)

    # continue regular state transition with new spec into next epoch
    to_slot = post_spec.SLOTS_PER_EPOCH + state.slot
    last_slot = (fork_epoch + 1) * post_spec.SLOTS_PER_EPOCH
    blocks.extend([
        post_tag(block) for block in state_transition_across_slots(
            post_spec, state, to_slot, block_filter=only_at(last_slot))
    ])

    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(slots_with_blocks) == 1
    assert slots_with_blocks[0] == last_slot

    yield "blocks", blocks
    yield "post", state
Exemple #10
0
def test_transition_with_one_fourth_exiting_validators_exit_post_fork(
        state, fork_epoch, spec, post_spec, pre_tag, post_tag):
    """
    1/4 validators initiated voluntary exit before the fork,
    and are exiting but still active *after* the fork transition.
    """
    exited_indices = exit_random_validators(
        spec,
        state,
        rng=random.Random(5566),
        fraction=0.25,
        exit_epoch=10,
        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_fork(state, spec, post_spec, fork_epoch)
    blocks.append(post_tag(block))

    # ensure that some of the current sync committee members are exiting
    exited_pubkeys = [
        state.validators[index].pubkey for index in exited_indices
    ]
    assert any(
        set(exited_pubkeys).intersection(
            list(state.current_sync_committee.pubkeys)))
    assert any(
        set(exited_pubkeys).difference(
            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)

    # check state
    for index in exited_indices:
        validator = state.validators[index]
        assert not validator.slashed
        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
Exemple #11
0
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_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)

    exited_pubkeys = [
        state.validators[index].pubkey for index in exited_indices
    ]
    some_sync_committee_exited = any(
        set(exited_pubkeys).intersection(
            list(state.current_sync_committee.pubkeys)))
    if post_spec.fork == ALTAIR:
        # in Altair fork, the sync committee members would be set with only active validators
        assert not some_sync_committee_exited
    else:
        assert some_sync_committee_exited

    # 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 _run_transition_test_with_attestations(state,
                                           fork_epoch,
                                           spec,
                                           post_spec,
                                           pre_tag,
                                           post_tag,
                                           participation_fn=None,
                                           expect_finality=True):
    yield "pre", state

    current_epoch = spec.get_current_epoch(state)
    assert current_epoch < fork_epoch
    assert current_epoch == spec.GENESIS_EPOCH

    # skip genesis epoch to avoid dealing with some edge cases...
    block = next_epoch_via_signed_block(spec, state)

    # regular state transition until fork:
    fill_cur_epoch = False
    fill_prev_epoch = True
    blocks = [pre_tag(block)]
    current_epoch = spec.get_current_epoch(state)
    for _ in range(current_epoch, fork_epoch - 1):
        _, blocks_in_epoch, state = next_slots_with_attestations(
            spec,
            state,
            spec.SLOTS_PER_EPOCH,
            fill_cur_epoch,
            fill_prev_epoch,
            participation_fn=participation_fn,
        )
        blocks.extend([pre_tag(block) for block in blocks_in_epoch])

    _, blocks_in_epoch, state = next_slots_with_attestations(
        spec,
        state,
        spec.SLOTS_PER_EPOCH - 1,
        fill_cur_epoch,
        fill_prev_epoch,
        participation_fn=participation_fn,
    )
    blocks.extend([pre_tag(block) for block in blocks_in_epoch])
    assert spec.get_current_epoch(state) == fork_epoch - 1
    assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0

    # irregular state transition to handle fork:
    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
    for _ in range(4):
        _, blocks_in_epoch, state = next_slots_with_attestations(
            post_spec,
            state,
            post_spec.SLOTS_PER_EPOCH,
            fill_cur_epoch,
            fill_prev_epoch,
            participation_fn=participation_fn,
        )
        blocks.extend([post_tag(block) for block in blocks_in_epoch])

    assert state.slot % post_spec.SLOTS_PER_EPOCH == 0
    assert post_spec.get_current_epoch(state) == fork_epoch + 4

    if expect_finality:
        assert state.current_justified_checkpoint.epoch == fork_epoch + 2
        assert state.finalized_checkpoint.epoch == fork_epoch
    else:
        assert state.current_justified_checkpoint.epoch == spec.GENESIS_EPOCH
        assert state.finalized_checkpoint.epoch == spec.GENESIS_EPOCH

    assert len(blocks) == (fork_epoch + 3) * post_spec.SLOTS_PER_EPOCH + 1
    assert len(blocks) == len(set(blocks))

    blocks_without_attestations = [
        block for block in blocks if len(block.message.body.attestations) == 0
    ]
    assert len(blocks_without_attestations) == 2
    slots_without_attestations = [
        b.message.slot for b in blocks_without_attestations
    ]

    assert set(slots_without_attestations) == set(
        [spec.SLOTS_PER_EPOCH, fork_epoch * spec.SLOTS_PER_EPOCH])

    yield "blocks", blocks
    yield "post", state