예제 #1
0
def test_transfer(state, pubkeys, privkeys):
    pre_state = deepcopy(state)
    current_epoch = get_current_epoch(pre_state)
    sender_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[-1]
    recipient_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
    transfer_pubkey = pubkeys[-1]
    transfer_privkey = privkeys[-1]
    amount = pre_state.validator_balances[sender_index]
    pre_transfer_recipient_balance = pre_state.validator_balances[recipient_index]
    transfer = Transfer(
        sender=sender_index,
        recipient=recipient_index,
        amount=amount,
        fee=0,
        slot=pre_state.slot + 1,
        pubkey=transfer_pubkey,
        signature=EMPTY_SIGNATURE,
    )
    transfer.signature = bls.sign(
        message_hash=signed_root(transfer),
        privkey=transfer_privkey,
        domain=get_domain(
            fork=pre_state.fork,
            epoch=get_current_epoch(pre_state),
            domain_type=spec.DOMAIN_TRANSFER,
        )
    )

    # ensure withdrawal_credentials reproducable
    pre_state.validator_registry[sender_index].withdrawal_credentials = (
        spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer_pubkey)[1:]
    )
    # un-activate so validator can transfer
    pre_state.validator_registry[sender_index].activation_epoch = spec.FAR_FUTURE_EPOCH

    post_state = deepcopy(pre_state)
    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(post_state)
    block.body.transfers.append(transfer)
    state_transition(post_state, block)

    sender_balance = post_state.validator_balances[sender_index]
    recipient_balance = post_state.validator_balances[recipient_index]
    assert sender_balance == 0
    assert recipient_balance == pre_transfer_recipient_balance + amount

    return pre_state, [block], post_state
예제 #2
0
def test_validator_already_exited(state):
    pre_state = deepcopy(state)
    #
    # setup pre_state
    #
    # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow validator able to exit
    pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

    current_epoch = get_current_epoch(pre_state)
    validator_index = get_active_validator_indices(
        pre_state.validator_registry, current_epoch)[0]
    privkey = pubkey_to_privkey[
        pre_state.validator_registry[validator_index].pubkey]

    # but validator already has exited
    pre_state.validator_registry[
        validator_index].exit_epoch = current_epoch + 2

    #
    # build voluntary exit
    #
    voluntary_exit = build_voluntary_exit(
        pre_state,
        current_epoch,
        validator_index,
        privkey,
    )

    with pytest.raises(AssertionError):
        process_voluntary_exit(pre_state, voluntary_exit)

    return pre_state, voluntary_exit, None
예제 #3
0
def test_validator_not_active(state):
    pre_state = deepcopy(state)
    current_epoch = get_current_epoch(pre_state)
    validator_index = get_active_validator_indices(
        pre_state.validator_registry, current_epoch)[0]
    privkey = pubkey_to_privkey[
        pre_state.validator_registry[validator_index].pubkey]

    #
    # setup pre_state
    #
    pre_state.validator_registry[
        validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH

    #
    # build and test voluntary exit
    #
    voluntary_exit = build_voluntary_exit(
        pre_state,
        current_epoch,
        validator_index,
        privkey,
    )

    with pytest.raises(AssertionError):
        process_voluntary_exit(pre_state, voluntary_exit)

    return pre_state, voluntary_exit, None
예제 #4
0
def test_success(state):
    pre_state = deepcopy(state)
    #
    # setup pre_state
    #
    # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
    pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

    #
    # build voluntary exit
    #
    current_epoch = get_current_epoch(pre_state)
    validator_index = get_active_validator_indices(
        pre_state.validator_registry, current_epoch)[0]
    privkey = pubkey_to_privkey[
        pre_state.validator_registry[validator_index].pubkey]

    voluntary_exit = build_voluntary_exit(
        pre_state,
        current_epoch,
        validator_index,
        privkey,
    )

    post_state = deepcopy(pre_state)

    #
    # test valid exit
    #
    process_voluntary_exit(post_state, voluntary_exit)

    assert not pre_state.validator_registry[validator_index].initiated_exit
    assert post_state.validator_registry[validator_index].initiated_exit

    return pre_state, voluntary_exit, post_state
예제 #5
0
def test_validator_not_active_long_enough(state):
    pre_state = deepcopy(state)
    #
    # setup pre_state
    #
    current_epoch = get_current_epoch(pre_state)
    validator_index = get_active_validator_indices(
        pre_state.validator_registry, current_epoch)[0]
    privkey = pubkey_to_privkey[
        pre_state.validator_registry[validator_index].pubkey]

    # but validator already has initiated exit
    pre_state.validator_registry[validator_index].initiated_exit = True

    #
    # build voluntary exit
    #
    voluntary_exit = build_voluntary_exit(
        pre_state,
        current_epoch,
        validator_index,
        privkey,
    )

    assert (current_epoch -
            pre_state.validator_registry[validator_index].activation_epoch <
            spec.PERSISTENT_COMMITTEE_PERIOD)

    with pytest.raises(AssertionError):
        process_voluntary_exit(pre_state, voluntary_exit)

    return pre_state, voluntary_exit, None
예제 #6
0
def test_proposer_slashing(state, pubkeys, privkeys):
    test_state = deepcopy(state)
    current_epoch = get_current_epoch(test_state)
    validator_index = get_active_validator_indices(test_state.validator_registry, current_epoch)[-1]
    privkey = privkeys[validator_index]
    slot = spec.GENESIS_SLOT
    header_1 = BeaconBlockHeader(
        slot=slot,
        previous_block_root=ZERO_HASH,
        state_root=ZERO_HASH,
        block_body_root=ZERO_HASH,
        signature=EMPTY_SIGNATURE,
    )
    header_2 = deepcopy(header_1)
    header_2.previous_block_root = b'\x02' * 32
    header_2.slot = slot + 1

    domain = get_domain(
        fork=test_state.fork,
        epoch=get_current_epoch(test_state),
        domain_type=spec.DOMAIN_BEACON_BLOCK,
    )
    header_1.signature = bls.sign(
        message_hash=signed_root(header_1),
        privkey=privkey,
        domain=domain,
    )
    header_2.signature = bls.sign(
        message_hash=signed_root(header_2),
        privkey=privkey,
        domain=domain,
    )

    proposer_slashing = ProposerSlashing(
        proposer_index=validator_index,
        header_1=header_1,
        header_2=header_2,
    )

    #
    # Add to state via block transition
    #
    block = build_empty_block_for_next_slot(test_state)
    block.body.proposer_slashings.append(proposer_slashing)
    state_transition(test_state, block)

    assert not state.validator_registry[validator_index].initiated_exit
    assert not state.validator_registry[validator_index].slashed

    slashed_validator = test_state.validator_registry[validator_index]
    assert not slashed_validator.initiated_exit
    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 test_state.validator_balances[validator_index] < state.validator_balances[validator_index]

    return state, [block], test_state
예제 #7
0
def test_voluntary_exit(state, pubkeys, privkeys):
    pre_state = deepcopy(state)
    validator_index = get_active_validator_indices(pre_state.validator_registry, get_current_epoch(pre_state))[-1]

    # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
    pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
    # artificially trigger registry update at next epoch transition
    pre_state.validator_registry_update_epoch -= 1

    post_state = deepcopy(pre_state)

    voluntary_exit = VoluntaryExit(
        epoch=get_current_epoch(pre_state),
        validator_index=validator_index,
        signature=EMPTY_SIGNATURE,
    )
    voluntary_exit.signature = bls.sign(
        message_hash=signed_root(voluntary_exit),
        privkey=privkeys[validator_index],
        domain=get_domain(
            fork=pre_state.fork,
            epoch=get_current_epoch(pre_state),
            domain_type=spec.DOMAIN_VOLUNTARY_EXIT,
        )
    )

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

    assert not pre_state.validator_registry[validator_index].initiated_exit
    assert post_state.validator_registry[validator_index].initiated_exit
    assert post_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH

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

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

    return pre_state, [initiate_exit_block, exit_block], post_state
예제 #8
0
def test_ejection(state):
    pre_state = deepcopy(state)

    current_epoch = get_current_epoch(pre_state)
    validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[-1]

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

    # set validator balance to below ejection threshold
    pre_state.validator_balances[validator_index] = spec.EJECTION_BALANCE - 1

    post_state = deepcopy(pre_state)
    #
    # trigger epoch transition
    #
    block = build_empty_block_for_next_slot(post_state)
    block.slot += spec.SLOTS_PER_EPOCH
    state_transition(post_state, block)

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

    return pre_state, [block], post_state