def get_base_reward(*, state: 'BeaconState', index: ValidatorIndex,
                    base_reward_quotient: int, previous_total_balance: Gwei,
                    max_deposit_amount: Gwei) -> Gwei:
    if previous_total_balance == 0:
        return Gwei(0)
    adjusted_quotient = (integer_squareroot(previous_total_balance) //
                         base_reward_quotient)
    return Gwei(
        get_effective_balance(
            state.validator_balances,
            index,
            max_deposit_amount,
        ) // adjusted_quotient // 5)
Esempio n. 2
0
    async def _get_eth1_vote(
            self, slot: Slot, state: BeaconState,
            state_machine: BaseBeaconStateMachine) -> Eth1Data:
        slots_per_eth1_voting_period = state_machine.config.SLOTS_PER_ETH1_VOTING_PERIOD
        seconds_per_slot = state_machine.config.SECONDS_PER_SLOT
        eth1_follow_distance = ETH1_FOLLOW_DISTANCE
        eth1_voting_period_start_timestamp = (
            self.genesis_time +
            (slot - slot % slots_per_eth1_voting_period) * seconds_per_slot)

        new_eth1_data = await self._request_eth1_data(
            Timestamp(eth1_voting_period_start_timestamp),
            eth1_follow_distance,
            2 * eth1_follow_distance,
        )
        # Default is the `Eth1Data` at `ETH1_FOLLOW_DISTANCE`
        default_eth1_data = new_eth1_data[0]

        # Compute `previous_eth1_distance` which is the distance between current block and
        # `state.eth1_data`.
        resp: GetDistanceResponse = await self.event_bus.request(
            GetDistanceRequest(
                block_hash=self.starting_eth1_block_hash,
                eth1_voting_period_start_timestamp=Timestamp(
                    eth1_voting_period_start_timestamp),
            ))
        if resp.error is not None:
            return default_eth1_data

        previous_eth1_distance = resp.distance

        # Request all eth1 data within `previous_eth1_distance`
        all_eth1_data: Tuple[Eth1Data, ...] = ()
        # Copy overlapped eth1 data from `new_eth1_data`
        if 2 * eth1_follow_distance >= previous_eth1_distance:
            all_eth1_data = new_eth1_data[:(previous_eth1_distance -
                                            eth1_follow_distance)]
        else:
            all_eth1_data = new_eth1_data[:]
            all_eth1_data += await self._request_eth1_data(
                Timestamp(eth1_voting_period_start_timestamp),
                2 * eth1_follow_distance,
                previous_eth1_distance,
            )

        # Filter out invalid votes
        voting_period_int_sqroot = integer_squareroot(
            slots_per_eth1_voting_period)
        period_tail = slot % slots_per_eth1_voting_period >= voting_period_int_sqroot
        if period_tail:
            votes_to_consider = all_eth1_data
        else:
            votes_to_consider = new_eth1_data

        valid_votes: Tuple[Eth1Data,
                           ...] = tuple(vote for vote in state.eth1_data_votes
                                        if vote in votes_to_consider)

        # Vote with most count wins. Otherwise vote for defaute eth1 data.
        win_vote = max(
            valid_votes,
            key=lambda v: (
                valid_votes.count(v),
                -all_eth1_data.index(v),
            ),  # Tiebreak by smallest distance
            default=default_eth1_data,
        )
        return win_vote
def test_integer_squareroot_edge_cases(value):
    with pytest.raises(ValueError):
        integer_squareroot(value)
def test_integer_squareroot_success(value, expected):
    actual = integer_squareroot(value)
    assert actual == expected
def test_integer_squareroot_correct(value):
    result = integer_squareroot(value)
    assert (result + 1) ** 2 > value
    assert result ** 2 <= value
Esempio n. 6
0
def get_base_reward(state: BeaconState, index: ValidatorIndex,
                    config: Eth2Config) -> Gwei:
    total_balance = get_total_active_balance(state, config)
    effective_balance = state.validators[index].effective_balance
    return Gwei(effective_balance * config.BASE_REWARD_FACTOR //
                integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH)
Esempio n. 7
0
def process_rewards_and_penalties(state: BeaconState,
                                  config: BeaconConfig) -> BeaconState:
    # Compute previous epoch active validator indices and the total balance they account for
    # for later use.
    previous_epoch_active_validator_indices = set(
        get_active_validator_indices(
            state.validator_registry,
            state.previous_epoch(config.SLOTS_PER_EPOCH,
                                 config.GENESIS_EPOCH)))
    previous_total_balance: Gwei = get_total_balance(
        state.validator_balances,
        tuple(previous_epoch_active_validator_indices),
        config.MAX_DEPOSIT_AMOUNT,
    )

    # Compute previous epoch attester indices and the total balance they account for
    # for later use.
    previous_epoch_attestations = get_previous_epoch_attestations(
        state,
        config.SLOTS_PER_EPOCH,
        config.GENESIS_EPOCH,
    )
    previous_epoch_attester_indices = get_attester_indices_from_attesttion(
        state=state,
        attestations=previous_epoch_attestations,
        committee_config=CommitteeConfig(config),
    )

    # Compute inclusion slot/distance of previous attestations for later use.
    inclusion_infos = get_inclusion_infos(
        state=state,
        attestations=previous_epoch_attestations,
        committee_config=CommitteeConfig(config),
    )

    # Compute effective balance of each previous epoch active validator for later use
    effective_balances = {
        index: get_effective_balance(
            state.validator_balances,
            index,
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in previous_epoch_active_validator_indices
    }
    # Compute base reward of each previous epoch active validator for later use
    _base_reward_quotient = (integer_squareroot(previous_total_balance) //
                             config.BASE_REWARD_QUOTIENT)
    base_rewards = {
        index: get_base_reward(
            state=state,
            index=index,
            base_reward_quotient=_base_reward_quotient,
            max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
        )
        for index in previous_epoch_active_validator_indices
    }

    # Initialize the reward (validator) received map
    rewards_received = {
        index: SignedGwei(0)
        for index in previous_epoch_active_validator_indices
    }

    # 1. Process rewards and penalties for justification and finalization
    rewards_received = pipe(
        rewards_received,
        _process_rewards_and_penalties_for_finality(
            state,
            config,
            previous_epoch_active_validator_indices,
            previous_total_balance,
            previous_epoch_attestations,
            previous_epoch_attester_indices,
            inclusion_infos,
            effective_balances,
            base_rewards,
        ),
        _process_rewards_and_penalties_for_attestation_inclusion(
            state,
            config,
            previous_epoch_attester_indices,
            inclusion_infos,
            base_rewards,
        ),
        _process_rewards_and_penalties_for_crosslinks(
            state,
            config,
            previous_epoch_attestations,
            effective_balances,
            base_rewards,
        ))

    # Apply the overall rewards/penalties
    for index in previous_epoch_active_validator_indices:
        state = state.update_validator_balance(
            index,
            # Prevent validator balance under flow
            max(state.validator_balances[index] + rewards_received[index], 0),
        )

    return state