def test_balance_driven_status_transitions(spec, state):
    current_epoch = spec.get_current_epoch(state)
    validator_index = spec.get_active_validator_indices(state,
                                                        current_epoch)[-1]

    assert state.validator_registry[
        validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH

    # set validator balance to below ejection threshold
    state.validator_registry[
        validator_index].effective_balance = spec.EJECTION_BALANCE

    yield 'pre', state

    # trigger epoch transition
    block = build_empty_block_for_next_slot(spec, state)
    block.slot += spec.SLOTS_PER_EPOCH
    sign_block(spec, state, block)
    spec.state_transition(state, block)

    yield 'blocks', [block], List[spec.BeaconBlock]
    yield 'post', state

    assert state.validator_registry[
        validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
Exemple #2
0
def test_attestation(state):
    state.slot = spec.SLOTS_PER_EPOCH

    yield 'pre', state

    attestation = get_valid_attestation(state, signed=True)

    # Add to state via block transition
    pre_current_attestations_len = len(state.current_epoch_attestations)
    attestation_block = build_empty_block_for_next_slot(state)
    attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
    attestation_block.body.attestations.append(attestation)
    sign_block(state, attestation_block)
    state_transition(state, attestation_block)

    assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1

    # Epoch transition should move to previous_epoch_attestations
    pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations)

    epoch_block = build_empty_block_for_next_slot(state)
    epoch_block.slot += spec.SLOTS_PER_EPOCH
    sign_block(state, epoch_block)
    state_transition(state, epoch_block)

    yield 'blocks', [attestation_block, epoch_block], [spec.BeaconBlock]
    yield 'post', state

    assert len(state.current_epoch_attestations) == 0
    assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
Exemple #3
0
def test_proposer_slashing(state):
    # copy for later balance lookups.
    pre_state = deepcopy(state)
    proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
    validator_index = proposer_slashing.proposer_index

    assert not state.validator_registry[validator_index].slashed

    yield 'pre', state

    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(state)
    block.body.proposer_slashings.append(proposer_slashing)
    sign_block(state, block)
    yield 'blocks', [block], [spec.BeaconBlock]

    state_transition(state, block)
    yield 'post', state

    # check if slashed
    slashed_validator = state.validator_registry[validator_index]
    assert slashed_validator.slashed
    assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
    assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
    # lost whistleblower reward
    assert get_balance(state, validator_index) < get_balance(pre_state, validator_index)
Exemple #4
0
def test_transfer(state):
    # overwrite default 0 to test
    spec.MAX_TRANSFERS = 1

    sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
    amount = get_balance(state, sender_index)

    transfer = get_valid_transfer(state, state.slot + 1, sender_index, amount, signed=True)
    recipient_index = transfer.recipient
    pre_transfer_recipient_balance = get_balance(state, recipient_index)

    # un-activate so validator can transfer
    state.validator_registry[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH

    yield 'pre', state

    # Add to state via block transition
    block = build_empty_block_for_next_slot(state)
    block.body.transfers.append(transfer)
    sign_block(state, block)

    yield 'blocks', [block], [spec.BeaconBlock]

    state_transition(state, block)
    yield 'post', state

    sender_balance = get_balance(state, sender_index)
    recipient_balance = get_balance(state, recipient_index)
    assert sender_balance == 0
    assert recipient_balance == pre_transfer_recipient_balance + amount
Exemple #5
0
def add_attestation_to_state(spec, state, attestation, slot):
    block = build_empty_block_for_next_slot(spec, state)
    block.slot = slot
    block.body.attestations.append(attestation)
    spec.process_slots(state, block.slot)
    sign_block(spec, state, block)
    spec.state_transition(state, block)
Exemple #6
0
def run_process_registry_updates(spec, state, valid=True):
    """
    Run ``process_crosslinks``, yielding:
      - pre-state ('pre')
      - post-state ('post').
    If ``valid == False``, run expecting ``AssertionError``
    """
    # transition state to slot before state transition
    slot = state.slot + (spec.SLOTS_PER_EPOCH -
                         state.slot % spec.SLOTS_PER_EPOCH) - 1
    block = build_empty_block_for_next_slot(spec, state)
    block.slot = slot
    sign_block(spec, state, block)
    state_transition(state, block)

    # cache state before epoch transition
    spec.process_slot(state)

    # process components of epoch transition before registry update
    spec.process_justification_and_finalization(state)
    spec.process_crosslinks(state)
    spec.process_rewards_and_penalties(state)

    yield 'pre', state
    spec.process_registry_updates(state)
    yield 'post', state
Exemple #7
0
def test_deposit_in_block(spec, state):
    initial_registry_len = len(state.validators)
    initial_balances_len = len(state.balances)

    validator_index = len(state.validators)
    amount = spec.MAX_EFFECTIVE_BALANCE
    deposit = prepare_state_and_deposit(spec,
                                        state,
                                        validator_index,
                                        amount,
                                        signed=True)

    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)
    block.body.deposits.append(deposit)
    sign_block(spec, state, block)

    state_transition_and_sign_block(spec, state, block)

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

    assert len(state.validators) == initial_registry_len + 1
    assert len(state.balances) == initial_balances_len + 1
    assert get_balance(state, validator_index) == spec.MAX_EFFECTIVE_BALANCE
    assert state.validators[validator_index].pubkey == pubkeys[validator_index]
Exemple #8
0
def test_eth1_data_votes_no_consensus(spec, state):
    # Don't run when it will take very, very long to simulate. Minimal configuration suffices.
    if spec.SLOTS_PER_ETH1_VOTING_PERIOD > 16:
        return

    pre_eth1_hash = state.eth1_data.block_hash

    offset_block = build_empty_block(spec,
                                     state,
                                     slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD -
                                     1)
    sign_block(spec, state, offset_block)
    state_transition_and_sign_block(spec, state, offset_block)
    yield 'pre', state

    a = b'\xaa' * 32
    b = b'\xbb' * 32

    blocks = []

    for i in range(0, spec.SLOTS_PER_ETH1_VOTING_PERIOD):
        block = build_empty_block_for_next_slot(spec, state)
        # wait for precisely 50% for A, then start voting B for other 50%
        block.body.eth1_data.block_hash = b if i * 2 >= spec.SLOTS_PER_ETH1_VOTING_PERIOD else a
        sign_block(spec, state, block)
        state_transition_and_sign_block(spec, state, block)
        blocks.append(block)

    assert len(state.eth1_data_votes) == spec.SLOTS_PER_ETH1_VOTING_PERIOD
    assert state.eth1_data.block_hash == pre_eth1_hash

    yield 'blocks', blocks
    yield 'post', state
Exemple #9
0
def state_transition_and_sign_block(spec, state, block):
    """
    State transition via the provided ``block``
    then package the block with the state root and signature.
    """
    spec.state_transition(state, block)
    block.state_root = state.hash_tree_root()
    sign_block(spec, state, block)
Exemple #10
0
def test_invalid_state_root(spec, state):
    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)
    block.state_root = b"\xaa" * 32
    sign_block(spec, state, block)

    expect_assertion_error(
        lambda: spec.state_transition(state, block, validate_state_root=True))

    yield 'blocks', [block]
    yield 'post', None
def test_skipped_slots(spec, state):
    pre_slot = state.slot
    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)
    block.slot += 3
    sign_block(spec, state, block)
    yield 'blocks', [block], List[spec.BeaconBlock]

    spec.state_transition(state, block)
    yield 'post', state

    assert state.slot == block.slot
    for slot in range(pre_slot, state.slot):
        assert spec.get_block_root_at_slot(state, slot) == block.parent_root
Exemple #12
0
def test_empty_epoch_transition(state):
    pre_slot = state.slot
    yield 'pre', state

    block = build_empty_block_for_next_slot(state)
    block.slot += spec.SLOTS_PER_EPOCH
    sign_block(state, block)
    yield 'blocks', [block], [spec.BeaconBlock]

    state_transition(state, block)
    yield 'post', state

    assert state.slot == block.slot
    for slot in range(pre_slot, state.slot):
        assert get_block_root_at_slot(state, slot) == block.previous_block_root
Exemple #13
0
def test_empty_epoch_transition(spec, state):
    pre_slot = state.slot
    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)
    block.slot += spec.SLOTS_PER_EPOCH
    sign_block(spec, state, block)

    state_transition_and_sign_block(spec, state, block)

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

    assert state.slot == block.slot
    for slot in range(pre_slot, state.slot):
        assert spec.get_block_root_at_slot(state, slot) == block.parent_root
Exemple #14
0
def test_on_block_bad_parent_root(spec, state):
    # Initialization
    store = spec.get_genesis_store(state)
    time = 100
    spec.on_tick(store, time)

    # Fail receiving block of `GENESIS_SLOT + 1` slot
    block = build_empty_block_for_next_slot(spec, state)
    spec.state_transition(state, block)
    block.state_root = state.hash_tree_root()

    block.parent_root = b'\x45' * 32

    sign_block(spec, state, block)

    run_on_block(spec, store, block, False)
def process_and_sign_block_without_header_validations(spec, state, block):
    """
    Artificially bypass the restrictions in the state transition to transition and sign block

    WARNING UNSAFE: Only use when generating valid-looking invalid blocks for test vectors
    """

    # Perform single mutation in `process_block_header`
    state.latest_block_header = spec.BeaconBlockHeader(
        slot=block.slot,
        proposer_index=block.proposer_index,
        parent_root=block.parent_root,
        state_root=spec.Bytes32(),
        body_root=block.body.hash_tree_root(),
    )

    # Perform rest of process_block transitions
    spec.process_randao(state, block.body)
    spec.process_eth1_data(state, block.body)
    spec.process_operations(state, block.body)

    # Insert post-state rot
    block.state_root = state.hash_tree_root()

    # Sign block
    return sign_block(spec, state, block)
Exemple #16
0
def process_and_sign_block_without_header_validations(spec, state, block):
    """
    Artificially bypass the restrictions in the state transition to transition and sign block

    WARNING UNSAFE: Only use when generating valid-looking invalid blocks for test vectors
    """

    # Perform single mutation in `process_block_header`
    state.latest_block_header = spec.BeaconBlockHeader(
        slot=block.slot,
        proposer_index=block.proposer_index,
        parent_root=block.parent_root,
        state_root=spec.Bytes32(),
        body_root=block.body.hash_tree_root(),
    )
    if is_post_merge(spec):
        if spec.is_execution_enabled(state, block.body):
            spec.process_execution_payload(state, block.body.execution_payload,
                                           spec.EXECUTION_ENGINE)

    # Perform rest of process_block transitions
    spec.process_randao(state, block.body)
    spec.process_eth1_data(state, block.body)
    spec.process_operations(state, block.body)
    if is_post_altair(spec):
        spec.process_sync_aggregate(state, block.body.sync_aggregate)

    # Insert post-state rot
    block.state_root = state.hash_tree_root()

    # Sign block
    return sign_block(spec, state, block)
Exemple #17
0
def test_skipped_slots(spec, state):
    pre_slot = state.slot
    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)
    block.slot += 3
    sign_block(spec, state, block)

    state_transition_and_sign_block(spec, state, block)

    yield 'blocks', [block], List[spec.BeaconBlock]
    yield 'post', state

    assert state.slot == block.slot
    assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.ZERO_HASH
    for slot in range(pre_slot, state.slot):
        assert spec.get_block_root_at_slot(state, slot) == block.parent_root
Exemple #18
0
def test_expected_deposit_in_block(spec, state):
    # Make the state expect a deposit, then don't provide it.
    state.eth1_data.deposit_count += 1
    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)
    sign_block(spec, state, block)
    bad = False
    try:
        state_transition_and_sign_block(spec, state, block)
        bad = True
    except AssertionError:
        pass
    if bad:
        raise AssertionError("expected deposit was not enforced")

    yield 'blocks', [block]
    yield 'post', None
Exemple #19
0
def test_historical_batch(spec, state):
    state.slot += spec.SLOTS_PER_HISTORICAL_ROOT - (
        state.slot % spec.SLOTS_PER_HISTORICAL_ROOT) - 1
    pre_historical_roots_len = len(state.historical_roots)

    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state, signed=True)
    sign_block(spec, state, block)
    state_transition_and_sign_block(spec, state, block)

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

    assert state.slot == block.slot
    assert spec.get_current_epoch(state) % (spec.SLOTS_PER_HISTORICAL_ROOT //
                                            spec.SLOTS_PER_EPOCH) == 0
    assert len(state.historical_roots) == pre_historical_roots_len + 1
Exemple #20
0
def test_voluntary_exit(state):
    validator_index = get_active_validator_indices(
        state,
        get_current_epoch(state)
    )[-1]

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

    yield 'pre', state

    voluntary_exit = VoluntaryExit(
        epoch=get_current_epoch(state),
        validator_index=validator_index,
    )
    voluntary_exit.signature = bls_sign(
        message_hash=signing_root(voluntary_exit),
        privkey=privkeys[validator_index],
        domain=get_domain(
            state=state,
            domain_type=spec.DOMAIN_VOLUNTARY_EXIT,
        )
    )

    # Add to state via block transition
    initiate_exit_block = build_empty_block_for_next_slot(state)
    initiate_exit_block.body.voluntary_exits.append(voluntary_exit)
    sign_block(state, initiate_exit_block)
    state_transition(state, initiate_exit_block)

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

    # Process within epoch transition
    exit_block = build_empty_block_for_next_slot(state)
    exit_block.slot += spec.SLOTS_PER_EPOCH
    sign_block(state, exit_block)
    state_transition(state, exit_block)

    yield 'blocks', [initiate_exit_block, exit_block], [spec.BeaconBlock]
    yield 'post', state

    assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
Exemple #21
0
def state_transition_and_sign_block(spec, state, block, expect_fail=False):
    """
    State transition via the provided ``block``
    then package the block with the correct state root and signature.
    """
    if expect_fail:
        expect_assertion_error(lambda: transition_unsigned_block(spec, state, block))
    else:
        transition_unsigned_block(spec, state, block)
    block.state_root = state.hash_tree_root()
    return sign_block(spec, state, block)
def run_process_crosslinks(state, valid=True):
    """
    Run ``process_crosslinks``, yielding:
      - pre-state ('pre')
      - post-state ('post').
    If ``valid == False``, run expecting ``AssertionError``
    """
    # transition state to slot before state transition
    slot = state.slot + (spec.SLOTS_PER_EPOCH -
                         state.slot % spec.SLOTS_PER_EPOCH) - 1
    block = build_empty_block_for_next_slot(state)
    block.slot = slot
    sign_block(state, block)
    state_transition(state, block)

    # cache state before epoch transition
    cache_state(state)

    yield 'pre', state
    process_crosslinks(state)
    yield 'post', state
Exemple #23
0
def test_attester_slashing(spec, state):
    # copy for later balance lookups.
    pre_state = deepcopy(state)

    attester_slashing = get_valid_attester_slashing(spec,
                                                    state,
                                                    signed_1=True,
                                                    signed_2=True)
    validator_index = (
        attester_slashing.attestation_1.custody_bit_0_indices +
        attester_slashing.attestation_1.custody_bit_1_indices)[0]

    assert not state.validators[validator_index].slashed

    yield 'pre', state

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

    state_transition_and_sign_block(spec, state, block)

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

    slashed_validator = state.validators[validator_index]
    assert slashed_validator.slashed
    assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
    assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
    # lost whistleblower reward
    assert get_balance(state, validator_index) < get_balance(
        pre_state, validator_index)

    proposer_index = spec.get_beacon_proposer_index(state)
    # gained whistleblower reward
    assert (get_balance(state, proposer_index) > get_balance(
        pre_state, proposer_index))
Exemple #24
0
def test_deposit_top_up(state):
    validator_index = 0
    amount = spec.MAX_EFFECTIVE_BALANCE // 4
    deposit = prepare_state_and_deposit(state, validator_index, amount)

    initial_registry_len = len(state.validator_registry)
    initial_balances_len = len(state.balances)
    validator_pre_balance = get_balance(state, validator_index)

    yield 'pre', state

    block = build_empty_block_for_next_slot(state)
    block.body.deposits.append(deposit)
    sign_block(state, block)

    yield 'blocks', [block], [spec.BeaconBlock]

    state_transition(state, block)
    yield 'post', state

    assert len(state.validator_registry) == initial_registry_len
    assert len(state.balances) == initial_balances_len
    assert get_balance(state, validator_index) == validator_pre_balance + amount
def _state_transition_and_sign_block_at_slot(spec, state):
    """
    Cribbed from ``transition_unsigned_block`` helper
    where the early parts of the state transition have already
    been applied to ``state``.

    Used to produce a block during an irregular state transition.
    """
    block = build_empty_block(spec, state)

    assert state.latest_block_header.slot < block.slot
    assert state.slot == block.slot
    spec.process_block(state, block)
    block.state_root = state.hash_tree_root()
    return sign_block(spec, state, block)
Exemple #26
0
def test_invalid_proposer_index_sig_from_proposer_index(spec, state):
    yield 'pre', state

    block = build_empty_block_for_next_slot(spec, state)

    # Set invalid proposer index but correct signature wrt proposer_index
    active_indices = spec.get_active_validator_indices(state, spec.get_current_epoch(state))
    active_indices = [i for i in active_indices if i != block.proposer_index]
    block.proposer_index = active_indices[0]  # invalid proposer index

    invalid_signed_block = sign_block(spec, state, block, block.proposer_index)

    expect_assertion_error(lambda: spec.state_transition(state, invalid_signed_block))

    yield 'blocks', [invalid_signed_block]
    yield 'post', None
Exemple #27
0
def test_prev_slot_block_transition(spec, state):
    # Go to clean slot
    spec.process_slots(state, state.slot + 1)
    # Make a block for it
    block = build_empty_block(spec, state, slot=state.slot)
    proposer_index = spec.get_beacon_proposer_index(state)
    # Transition to next slot, above block will not be invalid on top of new state.
    spec.process_slots(state, state.slot + 1)

    yield 'pre', state
    # State is beyond block slot, but the block can still be realistic when invalid.
    # Try the transition, and update the state root to where it is halted. Then sign with the supposed proposer.
    expect_assertion_error(lambda: transition_unsigned_block(spec, state, block))
    block.state_root = state.hash_tree_root()
    signed_block = sign_block(spec, state, block, proposer_index=proposer_index)
    yield 'blocks', [signed_block]
    yield 'post', None
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_altair_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_block(post_spec, state)
    blocks.append(post_tag(sign_block(post_spec, state, 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 #29
0
def test_on_block_bad_parent_root(spec, state):
    test_steps = []
    # Initialization
    store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
    yield 'anchor_state', state
    yield 'anchor_block', anchor_block
    current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time
    on_tick_and_append_step(spec, store, current_time, test_steps)
    assert store.time == current_time

    # Fail receiving block of `GENESIS_SLOT + 1` slot
    block = build_empty_block_for_next_slot(spec, state)
    transition_unsigned_block(spec, state, block)
    block.state_root = state.hash_tree_root()

    block.parent_root = b'\x45' * 32

    signed_block = sign_block(spec, state, block)

    yield from add_block(spec, store, signed_block, test_steps, valid=False)

    yield 'steps', test_steps
Exemple #30
0
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
    been applied to ``state``.

    Used to produce a block during an irregular state transition.

    The optional `operation_dict` is a dict of {'<BeaconBlockBody field>': <value>}.
    This is used for assigning the block operations.
    p.s. we can't just pass `body` and assign it because randao_reveal and eth1_data was set in `build_empty_block`
    Thus use dict to pass operations.
    """
    block = build_empty_block(spec, state)

    if operation_dict:
        _set_operations_by_dict(block, operation_dict)

    assert state.latest_block_header.slot < block.slot
    assert state.slot == block.slot
    spec.process_block(state, block)
    block.state_root = state.hash_tree_root()
    return sign_block(spec, state, block)