コード例 #1
0
def test_voluntary_exit(spec, state):
    validator_index = spec.get_active_validator_indices(
        state, spec.get_current_epoch(state))[-1]

    # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
    state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

    signed_exits = prepare_signed_exits(spec, state, [validator_index])
    yield 'pre', state

    # Add to state via block transition
    initiate_exit_block = build_empty_block_for_next_slot(spec, state)
    initiate_exit_block.body.voluntary_exits = signed_exits
    signed_initiate_exit_block = state_transition_and_sign_block(
        spec, state, initiate_exit_block)

    assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH

    # Process within epoch transition
    exit_block = build_empty_block(spec, state,
                                   state.slot + spec.SLOTS_PER_EPOCH)
    signed_exit_block = state_transition_and_sign_block(
        spec, state, exit_block)

    yield 'blocks', [signed_initiate_exit_block, signed_exit_block]
    yield 'post', state

    assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
コード例 #2
0
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 not valid:
        yield 'post', None
        return

    yield 'post', state
コード例 #3
0
def get_random_voluntary_exits(spec, state, to_be_slashed_indices, rng):
    num_exits = rng.randrange(spec.MAX_VOLUNTARY_EXITS)
    indices = set(
        spec.get_active_validator_indices(
            state, spec.get_current_epoch(state)).copy())
    eligible_indices = indices - to_be_slashed_indices
    exit_indices = [eligible_indices.pop() for _ in range(num_exits)]
    return prepare_signed_exits(spec, state, exit_indices)
コード例 #4
0
def get_random_voluntary_exits(spec, state, to_be_slashed_indices, rng):
    num_exits = rng.randrange(1, spec.MAX_VOLUNTARY_EXITS)
    active_indices = set(
        spec.get_active_validator_indices(
            state, spec.get_current_epoch(state)).copy())
    indices = set(index for index in active_indices
                  if _eligible_for_exit(spec, state, index))
    eligible_indices = indices - to_be_slashed_indices
    indices_count = min(num_exits, len(eligible_indices))
    exit_indices = [eligible_indices.pop() for _ in range(indices_count)]
    return prepare_signed_exits(spec, state, exit_indices)
コード例 #5
0
def test_double_validator_exit_same_block(spec, state):
    validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]

    # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
    state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

    # Same index tries to exit twice, but should only be able to do so once.
    signed_exits = prepare_signed_exits(spec, state, [validator_index, validator_index])
    yield 'pre', state

    # Add to state via block transition
    initiate_exit_block = build_empty_block_for_next_slot(spec, state)
    initiate_exit_block.body.voluntary_exits = signed_exits
    signed_initiate_exit_block = state_transition_and_sign_block(spec, state, initiate_exit_block, expect_fail=True)

    yield 'blocks', [signed_initiate_exit_block]
    yield 'post', None
コード例 #6
0
def run_transition_with_operation(state, fork_epoch, spec, post_spec, pre_tag,
                                  post_tag, operation_type, operation_at_slot):
    """
    Generate `operation_type` operation with the spec before fork.
    The operation would be included into the block at `operation_at_slot`.
    """
    is_at_fork = operation_at_slot == fork_epoch * spec.SLOTS_PER_EPOCH
    is_right_before_fork = operation_at_slot == fork_epoch * spec.SLOTS_PER_EPOCH - 1
    assert is_at_fork or is_right_before_fork

    if is_at_fork:
        transition_until_fork(spec, state, fork_epoch)
    elif is_right_before_fork:
        _transition_until_fork_minus_one(spec, state, fork_epoch)

    is_slashing_operation = operation_type in (OperationType.PROPOSER_SLASHING,
                                               OperationType.ATTESTER_SLASHING)
    # prepare operation
    selected_validator_index = None
    if is_slashing_operation:
        # avoid slashing the next proposer
        future_state = state.copy()
        next_slot(spec, future_state)
        proposer_index = spec.get_beacon_proposer_index(future_state)
        selected_validator_index = (proposer_index + 1) % len(state.validators)
        if operation_type == OperationType.PROPOSER_SLASHING:
            proposer_slashing = get_valid_proposer_slashing(
                spec,
                state,
                slashed_index=selected_validator_index,
                signed_1=True,
                signed_2=True)
            operation_dict = {'proposer_slashings': [proposer_slashing]}
        else:
            # operation_type == OperationType.ATTESTER_SLASHING:
            attester_slashing = get_valid_attester_slashing_by_indices(
                spec,
                state,
                [selected_validator_index],
                signed_1=True,
                signed_2=True,
            )
            operation_dict = {'attester_slashings': [attester_slashing]}
    elif operation_type == OperationType.DEPOSIT:
        # create a new deposit
        selected_validator_index = len(state.validators)
        amount = spec.MAX_EFFECTIVE_BALANCE
        deposit = prepare_state_and_deposit(spec,
                                            state,
                                            selected_validator_index,
                                            amount,
                                            signed=True)
        operation_dict = {'deposits': [deposit]}
    elif operation_type == OperationType.VOLUNTARY_EXIT:
        selected_validator_index = 0
        signed_exits = prepare_signed_exits(spec, state,
                                            [selected_validator_index])
        operation_dict = {'voluntary_exits': signed_exits}

    def _check_state():
        if operation_type == OperationType.PROPOSER_SLASHING:
            slashed_proposer = state.validators[
                proposer_slashing.signed_header_1.message.proposer_index]
            assert slashed_proposer.slashed
        elif operation_type == OperationType.ATTESTER_SLASHING:
            indices = set(
                attester_slashing.attestation_1.attesting_indices
            ).intersection(attester_slashing.attestation_2.attesting_indices)
            assert selected_validator_index in indices
            assert len(indices) > 0
            for validator_index in indices:
                assert state.validators[validator_index].slashed
        elif operation_type == OperationType.DEPOSIT:
            assert not post_spec.is_active_validator(
                state.validators[selected_validator_index],
                post_spec.get_current_epoch(state))
        elif operation_type == OperationType.VOLUNTARY_EXIT:
            validator = state.validators[selected_validator_index]
            assert validator.exit_epoch < post_spec.FAR_FUTURE_EPOCH

    yield "pre", state

    blocks = []

    if is_right_before_fork:
        # add a block with operation.
        block = build_empty_block_for_next_slot(spec, state)
        _set_operations_by_dict(block, operation_dict)
        signed_block = state_transition_and_sign_block(spec, state, block)
        blocks.append(pre_tag(signed_block))

        _check_state()

    # irregular state transition to handle fork:
    _operation_at_slot = operation_dict if is_at_fork else None
    state, block = do_fork(state,
                           spec,
                           post_spec,
                           fork_epoch,
                           operation_dict=_operation_at_slot)
    blocks.append(post_tag(block))

    if is_at_fork:
        _check_state()

    # after the fork
    if operation_type == OperationType.DEPOSIT:
        state = _transition_until_active(post_spec, state, post_tag, blocks,
                                         selected_validator_index)
    else:
        # avoid using the slashed validators as block proposers
        ignoring_proposers = [selected_validator_index
                              ] if is_slashing_operation else None

        # 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,
            ignoring_proposers=ignoring_proposers,
        )

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