def process_transfers(state: BeaconState, block: BaseBeaconBlock,
                      config: Eth2Config) -> BeaconState:
    if len(block.body.transfers) > config.MAX_TRANSFERS:
        raise ValidationError(
            f"The block ({block}) has too many transfers:\n"
            f"\tFound {len(block.body.transfers)} transfers, "
            f"maximum: {config.MAX_TRANSFERS}")

    for transfer in block.body.transfers:
        validate_transfer(
            state,
            transfer,
            config,
        )
        state = decrease_balance(
            state,
            transfer.sender,
            transfer.amount + transfer.fee,
        )
        state = increase_balance(
            state,
            transfer.recipient,
            transfer.amount,
        )
        state = increase_balance(
            state,
            get_beacon_proposer_index(
                state,
                CommitteeConfig(config),
            ),
            transfer.fee,
        )

    return state
def slash_validator(state: BeaconState,
                    index: ValidatorIndex,
                    config: Eth2Config,
                    whistleblower_index: ValidatorIndex = None) -> BeaconState:
    """
    Slash the validator with index ``index``.

    Exit the validator, penalize the validator, and reward the whistleblower.
    """
    # NOTE: remove in phase 1
    assert whistleblower_index is None

    slots_per_epoch = config.SLOTS_PER_EPOCH

    current_epoch = state.current_epoch(slots_per_epoch)

    state = initiate_validator_exit(state, index, config)
    state = state.update_validator_with_fn(
        index,
        _set_validator_slashed,
        current_epoch,
        config.EPOCHS_PER_SLASHINGS_VECTOR,
    )

    slashed_balance = state.validators[index].effective_balance
    slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR
    state = state.copy(slashings=update_tuple_item_with_fn(
        state.slashings,
        slashed_epoch,
        lambda balance, slashed_balance: Gwei(balance + slashed_balance),
        slashed_balance,
    ))
    state = decrease_balance(
        state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT)

    proposer_index = get_beacon_proposer_index(state, CommitteeConfig(config))
    if whistleblower_index is None:
        whistleblower_index = proposer_index
    whistleblower_reward = Gwei(slashed_balance //
                                config.WHISTLEBLOWER_REWARD_QUOTIENT)
    proposer_reward = Gwei(whistleblower_reward //
                           config.PROPOSER_REWARD_QUOTIENT)
    state = increase_balance(state, proposer_index, proposer_reward)
    state = increase_balance(
        state,
        whistleblower_index,
        Gwei(whistleblower_reward - proposer_reward),
    )

    return state
Beispiel #3
0
def slash_validator(
    state: BeaconState,
    index: ValidatorIndex,
    config: Eth2Config,
    whistleblower_index: ValidatorIndex = None,
) -> BeaconState:
    """
    Slash the validator with index ``index``.

    Exit the validator, penalize the validator, and reward the whistleblower.
    """
    # NOTE: remove in phase 1
    assert whistleblower_index is None

    slots_per_epoch = config.SLOTS_PER_EPOCH

    current_epoch = state.current_epoch(slots_per_epoch)

    state = initiate_validator_exit(state, index, config)

    state = state.transform(
        ("validators", index),
        partial(
            _set_validator_slashed,
            current_epoch=current_epoch,
            epochs_per_slashings_vector=config.EPOCHS_PER_SLASHINGS_VECTOR,
        ),
    )

    slashed_balance = state.validators[index].effective_balance
    slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR
    state = state.transform(("slashings", slashed_epoch),
                            lambda balance: Gwei(balance + slashed_balance))
    state = decrease_balance(
        state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT)

    proposer_index = get_beacon_proposer_index(state, config)
    if whistleblower_index is None:
        whistleblower_index = proposer_index
    whistleblower_reward = Gwei(slashed_balance //
                                config.WHISTLEBLOWER_REWARD_QUOTIENT)
    proposer_reward = Gwei(whistleblower_reward //
                           config.PROPOSER_REWARD_QUOTIENT)
    state = increase_balance(state, proposer_index, proposer_reward)
    state = increase_balance(state, whistleblower_index,
                             Gwei(whistleblower_reward - proposer_reward))

    return state
Beispiel #4
0
def process_rewards_and_penalties(
    state: BeaconState, config: Eth2Config
) -> BeaconState:
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    if current_epoch == config.GENESIS_EPOCH:
        return state

    rewards_for_attestations, penalties_for_attestations = get_attestation_deltas(
        state, config
    )
    rewards_for_crosslinks, penalties_for_crosslinks = get_crosslink_deltas(
        state, config
    )

    for index in range(len(state.validators)):
        index = ValidatorIndex(index)
        state = increase_balance(
            state,
            index,
            Gwei(rewards_for_attestations[index] + rewards_for_crosslinks[index]),
        )
        state = decrease_balance(
            state,
            index,
            Gwei(penalties_for_attestations[index] + penalties_for_crosslinks[index]),
        )

    return state
Beispiel #5
0
def process_deposit(state: BeaconState,
                    deposit: Deposit,
                    config: Eth2Config) -> BeaconState:
    """
    Process a deposit from Ethereum 1.0.
    """
    validate_deposit_proof(state, deposit, DEPOSIT_CONTRACT_TREE_DEPTH)

    # Increment the next deposit index we are expecting. Note that this
    # needs to be done here because while the deposit contract will never
    # create an invalid Merkle branch, it may admit an invalid deposit
    # object, and we need to be able to skip over it
    state = state.copy(
        eth1_deposit_index=state.eth1_deposit_index + 1,
    )

    pubkey = deposit.data.pubkey
    amount = deposit.data.amount
    validator_pubkeys = tuple(v.pubkey for v in state.validators)
    if pubkey not in validator_pubkeys:
        # Verify the deposit signature (proof of possession) for new validators.
        # Note: The deposit contract does not check signatures.
        # Note: Deposits are valid across forks, thus the deposit domain
        # is retrieved directly from `compute_domain`.
        is_valid_proof_of_possession = bls.verify(
            message_hash=deposit.data.signing_root,
            pubkey=pubkey,
            signature=deposit.data.signature,
            domain=compute_domain(
                SignatureDomain.DOMAIN_DEPOSIT,
            ),
        )
        if not is_valid_proof_of_possession:
            return state

        withdrawal_credentials = deposit.data.withdrawal_credentials
        validator = Validator.create_pending_validator(
            pubkey,
            withdrawal_credentials,
            amount,
            config,
        )

        return state.copy(
            validators=state.validators + (validator,),
            balances=state.balances + (amount, ),
        )
    else:
        index = ValidatorIndex(validator_pubkeys.index(pubkey))
        return increase_balance(
            state,
            index,
            amount,
        )
def test_increase_balance(genesis_state, delta):
    index = random.sample(range(len(genesis_state.validators)), 1)[0]
    prior_balance = genesis_state.balances[index]
    state = increase_balance(genesis_state, index, delta)
    assert state.balances[index] == Gwei(prior_balance + delta)