Ejemplo n.º 1
0
def test_multiple_attester_slashings_partial_overlap(spec, state):
    if spec.MAX_ATTESTER_SLASHINGS < 2:
        return dump_skipping_message(
            "Skip test if config cannot handle multiple AttesterSlashings per block"
        )

    # copy for later balance lookups.
    pre_state = state.copy()

    full_indices = spec.get_active_validator_indices(
        state, spec.get_current_epoch(state))[:8]
    one_third_length = len(full_indices) // 3

    attester_slashing_1 = get_valid_attester_slashing_by_indices(
        spec,
        state,
        full_indices[:one_third_length * 2],
        signed_1=True,
        signed_2=True,
    )
    attester_slashing_2 = get_valid_attester_slashing_by_indices(
        spec,
        state,
        full_indices[one_third_length:],
        signed_1=True,
        signed_2=True,
    )
    attester_slashings = [attester_slashing_1, attester_slashing_2]

    assert not any(state.validators[i].slashed for i in full_indices)

    yield 'pre', state

    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(spec, state)
    block.body.attester_slashings = attester_slashings

    signed_block = state_transition_and_sign_block(spec, state, block)

    yield 'blocks', [signed_block]
    yield 'post', state

    check_attester_slashing_effect(spec, pre_state, state, full_indices)
Ejemplo n.º 2
0
def test_success_proposer_index_slashed(spec, state):
    # Transition past genesis slot because generally doesn't have a proposer
    next_epoch_via_block(spec, state)

    proposer_index = spec.get_beacon_proposer_index(state)
    attester_slashing = get_valid_attester_slashing_by_indices(
        spec,
        state,
        [proposer_index],
        signed_1=True,
        signed_2=True,
    )

    yield from run_attester_slashing_processing(spec, state, attester_slashing)
def get_random_attester_slashings(spec, state, rng):
    num_slashings = rng.randrange(spec.MAX_ATTESTER_SLASHINGS)
    indices = spec.get_active_validator_indices(
        state, spec.get_current_epoch(state)).copy()
    slot_range = list(
        range(state.slot - spec.SLOTS_PER_HISTORICAL_ROOT + 1, state.slot))
    slashings = [
        get_valid_attester_slashing_by_indices(
            spec,
            state,
            sorted([
                indices.pop(rng.randrange(len(indices)))
                for _ in range(rng.randrange(1, 4))
            ]),
            slot=slot_range.pop(rng.randrange(len(slot_range))),
            signed_1=True,
            signed_2=True,
        ) for _ in range(num_slashings)
    ]
    return slashings
Ejemplo n.º 4
0
def get_random_attester_slashings(spec, state, rng, slashed_indices=[]):
    """
    Caller can supply ``slashed_indices`` if they are aware of other indices
    that will be slashed by other operations in the same block as the one that
    contains the output of this function.
    """
    # ensure at least one attester slashing, the max count
    # is small so not much room for random inclusion
    num_slashings = rng.randrange(1, spec.MAX_ATTESTER_SLASHINGS)
    active_indices = spec.get_active_validator_indices(
        state, spec.get_current_epoch(state)).copy()
    indices = [
        index for index in active_indices if
        (not state.validators[index].slashed and index not in slashed_indices)
    ]
    sample_upper_bound = 4
    max_slashed_count = num_slashings * sample_upper_bound - 1
    if len(indices) < max_slashed_count:
        return []

    slot_range = list(
        range(state.slot - spec.SLOTS_PER_HISTORICAL_ROOT + 1, state.slot))
    slashings = [
        get_valid_attester_slashing_by_indices(
            spec,
            state,
            sorted([
                indices.pop(rng.randrange(len(indices)))
                for _ in range(rng.randrange(1, sample_upper_bound))
            ]),
            slot=slot_range.pop(rng.randrange(len(slot_range))),
            signed_1=True,
            signed_2=True,
        ) for _ in range(num_slashings)
    ]
    return slashings
Ejemplo n.º 5
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