Exemple #1
0
def _determine_new_justified_epoch_and_bitfield(state: BeaconState,
                                                config: Eth2Config) -> Tuple[Epoch, int]:
    genesis_epoch = config.GENESIS_EPOCH
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, genesis_epoch)
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)

    previous_epoch_justifiable = _is_epoch_justifiable(
        state,
        previous_epoch,
        config,
    )
    current_epoch_justifiable = _is_epoch_justifiable(
        state,
        current_epoch,
        config,
    )

    (
        new_current_justified_epoch,
        justification_bitfield,
    ) = _determine_updated_justifications(
        previous_epoch_justifiable,
        previous_epoch,
        current_epoch_justifiable,
        current_epoch,
        state.current_justified_epoch,
        state.justification_bitfield << 1,
    )

    return (
        new_current_justified_epoch,
        justification_bitfield,
    )
Exemple #2
0
def _determine_new_justified_epoch_and_bitfield(
        state: BeaconState, config: Eth2Config) -> Tuple[Epoch, Bitfield]:
    genesis_epoch = config.GENESIS_EPOCH
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          genesis_epoch)
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)

    previous_epoch_justifiable = _is_epoch_justifiable(state, previous_epoch,
                                                       config)
    current_epoch_justifiable = _is_epoch_justifiable(state, current_epoch,
                                                      config)

    (
        new_current_justified_epoch,
        justification_bits,
    ) = _determine_updated_justifications(
        previous_epoch_justifiable,
        previous_epoch,
        current_epoch_justifiable,
        current_epoch,
        state.current_justified_checkpoint.epoch,
        (False, ) + state.justification_bits[:-1],
    )

    return (new_current_justified_epoch, justification_bits)
Exemple #3
0
def _validate_attestation_data(
    state: BeaconState, data: AttestationData, config: Eth2Config
) -> None:
    slots_per_epoch = config.SLOTS_PER_EPOCH
    current_epoch = state.current_epoch(slots_per_epoch)
    previous_epoch = state.previous_epoch(slots_per_epoch)

    attestation_slot = data.slot

    if data.target.epoch == current_epoch:
        expected_checkpoint = state.current_justified_checkpoint
    else:
        expected_checkpoint = state.previous_justified_checkpoint

    _validate_eligible_committee_index(
        state,
        attestation_slot,
        data.index,
        config.MAX_COMMITTEES_PER_SLOT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    )

    _validate_eligible_target_epoch(data.target.epoch, current_epoch, previous_epoch)
    _validate_slot_matches_target_epoch(
        data.target.epoch, attestation_slot, slots_per_epoch
    )
    validate_attestation_slot(
        attestation_slot,
        state.slot,
        slots_per_epoch,
        config.MIN_ATTESTATION_INCLUSION_DELAY,
    )
    _validate_checkpoint(data.source, expected_checkpoint)
def _validate_attestation_data(state: BeaconState, data: AttestationData,
                               config: Eth2Config) -> None:
    slots_per_epoch = config.SLOTS_PER_EPOCH
    current_epoch = state.current_epoch(slots_per_epoch)
    previous_epoch = state.previous_epoch(slots_per_epoch,
                                          config.GENESIS_EPOCH)

    attestation_slot = get_attestation_data_slot(state, data, config)

    if data.target.epoch == current_epoch:
        expected_checkpoint = state.current_justified_checkpoint
        parent_crosslink = state.current_crosslinks[data.crosslink.shard]
    else:
        expected_checkpoint = state.previous_justified_checkpoint
        parent_crosslink = state.previous_crosslinks[data.crosslink.shard]

    _validate_eligible_shard_number(data.crosslink.shard, config.SHARD_COUNT)
    _validate_eligible_target_epoch(data.target.epoch, current_epoch,
                                    previous_epoch)
    validate_attestation_slot(
        attestation_slot,
        state.slot,
        slots_per_epoch,
        config.MIN_ATTESTATION_INCLUSION_DELAY,
    )
    _validate_checkpoint(data.source, expected_checkpoint)
    _validate_crosslink(
        data.crosslink,
        data.target.epoch,
        parent_crosslink,
        config.MAX_EPOCHS_PER_CROSSLINK,
    )
Exemple #5
0
def get_crosslink_deltas(
        state: BeaconState,
        config: Eth2Config) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
    rewards = tuple(0 for _ in range(len(state.validators)))
    penalties = tuple(0 for _ in range(len(state.validators)))
    epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH)
    active_validators_indices = get_active_validator_indices(
        state.validators, epoch)
    epoch_committee_count = get_committee_count(
        len(active_validators_indices),
        config.SHARD_COUNT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    )
    epoch_start_shard = get_start_shard(
        state,
        epoch,
        CommitteeConfig(config),
    )
    for shard_offset in range(epoch_committee_count):
        shard = Shard((epoch_start_shard + shard_offset) % config.SHARD_COUNT)
        crosslink_committee = set(
            get_crosslink_committee(
                state,
                epoch,
                shard,
                CommitteeConfig(config),
            ))
        _, attesting_indices = get_winning_crosslink_and_attesting_indices(
            state=state,
            epoch=epoch,
            shard=shard,
            config=config,
        )
        total_attesting_balance = get_total_balance(
            state,
            attesting_indices,
        )
        total_committee_balance = get_total_balance(
            state,
            crosslink_committee,
        )
        for index in crosslink_committee:
            base_reward = get_base_reward(state, index, config)
            if index in attesting_indices:
                rewards = update_tuple_item_with_fn(
                    rewards, index, lambda balance, delta: balance + delta,
                    base_reward * total_attesting_balance //
                    total_committee_balance)
            else:
                penalties = update_tuple_item_with_fn(
                    penalties,
                    index,
                    lambda balance, delta: balance + delta,
                    base_reward,
                )
    return tuple(Gwei(reward) for reward in rewards), tuple(
        Gwei(penalty) for penalty in penalties)
Exemple #6
0
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState:
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)

    new_current_crosslinks = state.current_crosslinks

    for epoch in (previous_epoch, current_epoch):
        active_validators_indices = get_active_validator_indices(
            state.validators, epoch)
        epoch_committee_count = get_committee_count(
            len(active_validators_indices),
            config.SHARD_COUNT,
            config.SLOTS_PER_EPOCH,
            config.TARGET_COMMITTEE_SIZE,
        )
        epoch_start_shard = get_start_shard(
            state,
            epoch,
            CommitteeConfig(config),
        )
        for shard_offset in range(epoch_committee_count):
            shard = Shard(
                (epoch_start_shard + shard_offset) % config.SHARD_COUNT)
            crosslink_committee = set(
                get_crosslink_committee(
                    state,
                    epoch,
                    shard,
                    CommitteeConfig(config),
                ))

            if not crosslink_committee:
                # empty crosslink committee this epoch
                continue

            winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(
                state=state,
                epoch=epoch,
                shard=shard,
                config=config,
            )
            threshold_met = _is_threshold_met_against_committee(
                state,
                attesting_indices,
                crosslink_committee,
            )
            if threshold_met:
                new_current_crosslinks = update_tuple_item(
                    new_current_crosslinks,
                    shard,
                    winning_crosslink,
                )

    return state.copy(
        previous_crosslinks=state.current_crosslinks,
        current_crosslinks=new_current_crosslinks,
    )
def get_matching_source_attestations(
        state: BeaconState, epoch: Epoch,
        config: Eth2Config) -> Tuple[PendingAttestation, ...]:
    if epoch == state.current_epoch(config.SLOTS_PER_EPOCH):
        return state.current_epoch_attestations
    elif epoch == state.previous_epoch(config.SLOTS_PER_EPOCH):
        return state.previous_epoch_attestations
    else:
        raise InvalidEpochError
Exemple #8
0
def _process_rewards_and_penalties_for_crosslinks(
    state: BeaconState, config: Eth2Config,
    effective_balances: Dict[ValidatorIndex,
                             Gwei], base_rewards: Dict[ValidatorIndex, Gwei]
) -> Tuple[Dict[ValidatorIndex, Gwei], Dict[ValidatorIndex,
                                            Gwei]]:  # noqa: E501
    previous_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    current_epoch_start_slot = get_epoch_start_slot(
        state.current_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    rewards_received = {
        ValidatorIndex(index): Gwei(0)
        for index in range(len(state.validator_registry))
    }
    penalties_received = rewards_received.copy()
    for slot in range(previous_epoch_start_slot, current_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            winning_root, attesting_validator_indices = get_winning_root_and_participants(
                state=state,
                shard=shard,
                effective_balances=effective_balances,
                committee_config=CommitteeConfig(config),
            )
            total_attesting_balance = get_total_balance(
                state.validator_balances,
                attesting_validator_indices,
                config.MAX_DEPOSIT_AMOUNT,
            )
            total_balance = get_total_balance_from_effective_balances(
                effective_balances,
                crosslink_committee,
            )
            for index in attesting_validator_indices:
                rewards_received = _update_rewards_or_penalies(
                    index,
                    base_rewards[index] * total_attesting_balance //
                    total_balance,
                    rewards_received,
                )
            for index in set(crosslink_committee).difference(
                    attesting_validator_indices):
                penalties_received = _update_rewards_or_penalies(
                    index,
                    base_rewards[index],
                    penalties_received,
                )
    return (rewards_received, penalties_received)
Exemple #9
0
def get_committee_assignment(
        state: BeaconState,
        config: BeaconConfig,
        epoch: Epoch,
        validator_index: ValidatorIndex,
        registry_change: bool = False) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``
    and ``registry_change``.
    ``CommitteeAssignment.committee`` is the tuple array of validators in the committee
    ``CommitteeAssignment.shard`` is the shard to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to
        propose a beacon block at the assigned slot.
    """
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)
    next_epoch = Epoch(current_epoch + 1)

    validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch)

    epoch_start_slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH)

    committee_config = CommitteeConfig(config)

    for slot in range(epoch_start_slot,
                      epoch_start_slot + config.SLOTS_PER_EPOCH):
        crosslink_committees = get_crosslink_committees_at_slot(
            state,
            slot,
            committee_config,
            registry_change=registry_change,
        )
        selected_committees = [
            committee for committee in crosslink_committees
            if validator_index in committee[0]
        ]
        if len(selected_committees) > 0:
            validators = selected_committees[0][0]
            shard = selected_committees[0][1]
            is_proposer = validator_index == get_beacon_proposer_index(
                state,
                Slot(slot),
                committee_config,
                registry_change=registry_change,
            )

            return CommitteeAssignment(validators, shard, Slot(slot),
                                       is_proposer)

    raise NoCommitteeAssignment
Exemple #10
0
def process_justification(state: BeaconState,
                          config: BeaconConfig) -> BeaconState:

    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)

    current_epoch_justifiable, previous_epoch_justifiable = _current_previous_epochs_justifiable(
        state,
        current_epoch,
        previous_epoch,
        config,
    )

    _justification_bitfield = state.justification_bitfield << 1
    if previous_epoch_justifiable and current_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 3
    elif previous_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 2
    elif current_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 1
    else:
        justification_bitfield = _justification_bitfield

    if current_epoch_justifiable:
        new_justified_epoch = current_epoch
    elif previous_epoch_justifiable:
        new_justified_epoch = previous_epoch
    else:
        new_justified_epoch = state.justified_epoch

    finalized_epoch, _ = _get_finalized_epoch(
        justification_bitfield,
        state.previous_justified_epoch,
        state.justified_epoch,
        state.finalized_epoch,
        previous_epoch,
    )

    return state.copy(
        previous_justified_epoch=state.justified_epoch,
        justified_epoch=new_justified_epoch,
        justification_bitfield=justification_bitfield,
        finalized_epoch=finalized_epoch,
    )
Exemple #11
0
def process_justification(state: BeaconState,
                          config: Eth2Config) -> BeaconState:
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH)

    current_epoch_justifiable = _is_epoch_justifiable(
        state,
        state.current_epoch_attestations,
        current_epoch,
        config,
    )
    previous_epoch_justifiable = _is_epoch_justifiable(
        state,
        state.previous_epoch_attestations,
        previous_epoch,
        config,
    )

    _justification_bitfield = state.justification_bitfield << 1
    if previous_epoch_justifiable and current_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 3
    elif previous_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 2
    elif current_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 1
    else:
        justification_bitfield = _justification_bitfield

    if current_epoch_justifiable:
        new_justified_epoch = current_epoch
    elif previous_epoch_justifiable:
        new_justified_epoch = previous_epoch
    else:
        new_justified_epoch = state.current_justified_epoch

    new_finalized_epoch, _ = _get_finalized_epoch(
        justification_bitfield,
        state.previous_justified_epoch,
        state.current_justified_epoch,
        state.finalized_epoch,
        previous_epoch,
    )

    # Update state
    state = state.copy(
        previous_justified_epoch=state.current_justified_epoch,
        previous_justified_root=state.current_justified_root,
        justification_bitfield=justification_bitfield,
    )

    if new_justified_epoch != state.current_justified_epoch:
        state = state.copy(
            current_justified_epoch=new_justified_epoch,
            current_justified_root=get_block_root(
                state,
                get_epoch_start_slot(new_justified_epoch,
                                     config.SLOTS_PER_EPOCH),
                config.SLOTS_PER_HISTORICAL_ROOT,
            ),
        )

    if new_finalized_epoch != state.finalized_epoch:
        state = state.copy(finalized_epoch=new_finalized_epoch,
                           finalized_root=get_block_root(
                               state,
                               get_epoch_start_slot(new_finalized_epoch,
                                                    config.SLOTS_PER_EPOCH),
                               config.SLOTS_PER_HISTORICAL_ROOT,
                           ))

    return state
Exemple #12
0
def process_crosslinks(state: BeaconState, config: BeaconConfig) -> BeaconState:
    """
    Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec:
    https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks

    For each shard from the past two epochs, find the shard block
    root that has been attested to by the most stake.
    If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard.
    Return resulting ``state``
    """
    latest_crosslinks = state.latest_crosslinks
    previous_epoch_attestations = get_previous_epoch_attestations(
        state,
        config.EPOCH_LENGTH,
        config.GENESIS_EPOCH,
    )
    current_epoch_attestations = get_current_epoch_attestations(state, config.EPOCH_LENGTH)
    prev_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.EPOCH_LENGTH, config.GENESIS_EPOCH),
        config.EPOCH_LENGTH,
    )
    next_epoch_start_slot = get_epoch_start_slot(
        state.next_epoch(config.EPOCH_LENGTH),
        config.EPOCH_LENGTH,
    )
    for slot in range(prev_epoch_start_slot, next_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            try:
                winning_root, total_attesting_balance = get_winning_root(
                    state=state,
                    shard=shard,
                    # Use `_filter_attestations_by_shard` to filter out attestations
                    # not attesting to this shard so we don't need to going over
                    # irrelevent attestations over and over again.
                    attestations=_filter_attestations_by_shard(
                        previous_epoch_attestations + current_epoch_attestations,
                        shard,
                    ),
                    max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
                    committee_config=CommitteeConfig(config),
                )
            except NoWinningRootError:
                # No winning shard block root found for this shard.
                pass
            else:
                total_balance = sum(
                    get_effective_balance(state.validator_balances, i, config.MAX_DEPOSIT_AMOUNT)
                    for i in crosslink_committee
                )
                if 3 * total_attesting_balance >= 2 * total_balance:
                    latest_crosslinks = update_tuple_item(
                        latest_crosslinks,
                        shard,
                        CrosslinkRecord(
                            epoch=state.current_epoch(config.EPOCH_LENGTH),
                            shard_block_root=winning_root,
                        ),
                    )
                else:
                    # Don't update the crosslink of this shard
                    pass
    state = state.copy(
        latest_crosslinks=latest_crosslinks,
    )
    return state
def get_attestation_deltas(
        state: BeaconState,
        config: Eth2Config) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
    rewards = tuple(0 for _ in range(len(state.validators)))
    penalties = tuple(0 for _ in range(len(state.validators)))
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH)
    total_balance = get_total_active_balance(state, config)
    eligible_validator_indices = tuple(
        ValidatorIndex(index) for index, v in enumerate(state.validators)
        if v.is_active(previous_epoch) or (
            v.slashed and previous_epoch + 1 < v.withdrawable_epoch))

    matching_source_attestations = get_matching_source_attestations(
        state, previous_epoch, config)
    matching_target_attestations = get_matching_target_attestations(
        state, previous_epoch, config)
    matching_head_attestations = get_matching_head_attestations(
        state, previous_epoch, config)

    increment = config.EFFECTIVE_BALANCE_INCREMENT
    total_balance_in_increment = total_balance // increment
    for attestations in (
            matching_source_attestations,
            matching_target_attestations,
            matching_head_attestations,
    ):
        unslashed_attesting_indices = get_unslashed_attesting_indices(
            state, attestations, config)
        attesting_balance = get_total_balance(state,
                                              unslashed_attesting_indices,
                                              config)
        attesting_balance_in_increment = attesting_balance // increment
        for index in eligible_validator_indices:
            if index in unslashed_attesting_indices:
                if is_in_inactivity_leak(state, config):
                    reward = get_base_reward(state, index, config)
                else:
                    reward = Gwei((get_base_reward(state, index, config) *
                                   attesting_balance_in_increment) //
                                  total_balance_in_increment)
                rewards = update_tuple_item_with_fn(
                    rewards, index, lambda balance, delta: balance + delta,
                    reward)
            else:
                penalties = update_tuple_item_with_fn(
                    penalties,
                    index,
                    lambda balance, delta: balance + delta,
                    get_base_reward(state, index, config),
                )

    for index in get_unslashed_attesting_indices(state,
                                                 matching_source_attestations,
                                                 config):
        attestation = min(
            (a for a in matching_source_attestations if index in
             get_attesting_indices(state, a.data, a.aggregation_bits, config)),
            key=lambda a: a.inclusion_delay,
        )
        proposer_reward = get_proposer_reward(state, index, config)
        rewards = update_tuple_item_with_fn(
            rewards,
            attestation.proposer_index,
            lambda balance, delta: balance + delta,
            proposer_reward,
        )
        base_reward = get_base_reward(state, index, config)
        max_attester_reward = base_reward - proposer_reward
        rewards = update_tuple_item_with_fn(
            rewards,
            index,
            lambda balance, delta: balance + delta,
            (max_attester_reward // attestation.inclusion_delay),
        )

    if is_in_inactivity_leak(state, config):
        matching_target_attesting_indices = get_unslashed_attesting_indices(
            state, matching_target_attestations, config)
        for index in eligible_validator_indices:
            base_reward = get_base_reward(state, index, config)
            penalties = update_tuple_item_with_fn(
                penalties,
                index,
                lambda balance, delta: balance + delta,
                BASE_REWARDS_PER_EPOCH * base_reward -
                get_proposer_reward(state, index, config),
            )
            if index not in matching_target_attesting_indices:
                effective_balance = state.validators[index].effective_balance
                penalties = update_tuple_item_with_fn(
                    penalties,
                    index,
                    lambda balance, delta: balance + delta,
                    effective_balance *
                    get_finality_delay(state, config.SLOTS_PER_EPOCH) //
                    config.INACTIVITY_PENALTY_QUOTIENT,
                )
    return (
        tuple(Gwei(reward) for reward in rewards),
        tuple(Gwei(penalty) for penalty in penalties),
    )
def get_finality_delay(state: BeaconState, slots_per_epoch: int) -> int:
    return state.previous_epoch(
        slots_per_epoch) - state.finalized_checkpoint.epoch
Exemple #15
0
def get_attestation_deltas(state: BeaconState,
                           config: Eth2Config) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
    committee_config = CommitteeConfig(config)
    rewards = tuple(
        0 for _ in range(len(state.validators))
    )
    penalties = tuple(
        0 for _ in range(len(state.validators))
    )
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH)
    total_balance = get_total_active_balance(state, config)
    eligible_validator_indices = tuple(
        ValidatorIndex(index) for index, v in enumerate(state.validators)
        if v.is_active(previous_epoch) or (
            v.slashed and previous_epoch + 1 < v.withdrawable_epoch
        )
    )

    matching_source_attestations = get_matching_source_attestations(
        state,
        previous_epoch,
        config,
    )
    matching_target_attestations = get_matching_target_attestations(
        state,
        previous_epoch,
        config,
    )
    matching_head_attestations = get_matching_head_attestations(
        state,
        previous_epoch,
        config,
    )

    for attestations in (
            matching_source_attestations,
            matching_target_attestations,
            matching_head_attestations
    ):
        unslashed_attesting_indices = get_unslashed_attesting_indices(
            state,
            attestations,
            committee_config,
        )
        attesting_balance = get_total_balance(state, unslashed_attesting_indices)
        for index in eligible_validator_indices:
            if index in unslashed_attesting_indices:
                rewards = update_tuple_item_with_fn(
                    rewards,
                    index,
                    lambda balance, delta: balance + delta,
                    get_base_reward(
                        state,
                        index,
                        config,
                    ) * attesting_balance // total_balance,
                )
            else:
                penalties = update_tuple_item_with_fn(
                    penalties,
                    index,
                    lambda balance, delta: balance + delta,
                    get_base_reward(
                        state,
                        index,
                        config,
                    ),
                )

    for index in get_unslashed_attesting_indices(
            state,
            matching_source_attestations,
            committee_config,
    ):
        attestation = min(
            (
                a for a in matching_source_attestations
                if index in get_attesting_indices(
                    state,
                    a.data,
                    a.aggregation_bitfield,
                    committee_config,
                )
            ),
            key=lambda a: a.inclusion_delay,
        )
        base_reward = get_base_reward(state, index, config)
        proposer_reward = base_reward // config.PROPOSER_REWARD_QUOTIENT
        rewards = update_tuple_item_with_fn(
            rewards,
            attestation.proposer_index,
            lambda balance, delta: balance + delta,
            proposer_reward,
        )
        max_attester_reward = base_reward - proposer_reward
        rewards = update_tuple_item_with_fn(
            rewards,
            index,
            lambda balance, delta: balance + delta,
            (
                max_attester_reward *
                config.MIN_ATTESTATION_INCLUSION_DELAY //
                attestation.inclusion_delay
            )
        )

    finality_delay = previous_epoch - state.finalized_epoch
    if finality_delay > config.MIN_EPOCHS_TO_INACTIVITY_PENALTY:
        matching_target_attesting_indices = get_unslashed_attesting_indices(
            state,
            matching_target_attestations,
            committee_config,
        )
        for index in eligible_validator_indices:
            penalties = update_tuple_item_with_fn(
                penalties,
                index,
                lambda balance, delta: balance + delta,
                BASE_REWARDS_PER_EPOCH * get_base_reward(
                    state,
                    index,
                    config,
                ),
            )
            if index not in matching_target_attesting_indices:
                effective_balance = state.validators[index].effective_balance
                penalties = update_tuple_item_with_fn(
                    penalties,
                    index,
                    lambda balance, delta: balance + delta,
                    effective_balance * finality_delay // config.INACTIVITY_PENALTY_QUOTIENT,
                )
    return tuple(
        Gwei(reward) for reward in rewards
    ), tuple(
        Gwei(penalty) for penalty in penalties
    )
Exemple #16
0
def process_rewards_and_penalties(state: BeaconState,
                                  config: Eth2Config) -> 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)))
    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 = state.previous_epoch_attestations
    previous_epoch_attester_indices = get_attester_indices_from_attestations(
        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 = {
        ValidatorIndex(index): get_effective_balance(
            state.validator_balances,
            ValidatorIndex(index),
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }
    # Compute base reward of each previous epoch active validator for later use
    base_rewards = {
        ValidatorIndex(index): get_base_reward(
            state=state,
            index=ValidatorIndex(index),
            base_reward_quotient=config.BASE_REWARD_QUOTIENT,
            previous_total_balance=previous_total_balance,
            max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }

    # 1. Process rewards and penalties for justification and finalization
    finality_rewards, finality_penalties = _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,
    )
    # 2. Process rewards and penalties for crosslinks
    crosslinks_rewards, crosslinks_penalties = _process_rewards_and_penalties_for_crosslinks(
        state,
        config,
        effective_balances,
        base_rewards,
    )

    # Apply the overall rewards/penalties
    for index in range(len(state.validator_registry)):
        state = state.update_validator_balance(
            ValidatorIndex(index),
            # Prevent validator balance under flow
            max(
                (state.validator_balances[index] + finality_rewards[index] +
                 crosslinks_rewards[index] - finality_penalties[index] -
                 crosslinks_penalties[index]),
                0,
            ),
        )

    return state
def process_attestations(state: BeaconState,
                         block: BaseBeaconBlock,
                         config: Eth2Config) -> BeaconState:
    """
    Implements 'per-block-processing.operations.attestations' portion of Phase 0 spec:
    https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#attestations-1

    Validate the ``attestations`` contained within the ``block`` in the context of ``state``.
    If any invalid, throw ``ValidationError``.
    Otherwise, append a ``PendingAttestationRecords`` for each to ``previous_epoch_attestations``
    or ``current_epoch_attestations``.
    Return resulting ``state``.
    """
    if len(block.body.attestations) > config.MAX_ATTESTATIONS:
        raise ValidationError(
            f"The block ({block}) has too many attestations:\n"
            f"\tFound {len(block.body.attestations)} attestations, "
            f"maximum: {config.MAX_ATTESTATIONS}"
        )

    for attestation in block.body.attestations:
        validate_attestation(
            state,
            attestation,
            config.MIN_ATTESTATION_INCLUSION_DELAY,
            config.SLOTS_PER_HISTORICAL_ROOT,
            CommitteeConfig(config),
        )

    # update attestations
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH)
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    new_previous_epoch_pending_attestations = []
    new_current_epoch_pending_attestations = []
    for attestation in block.body.attestations:
        if slot_to_epoch(attestation.data.slot, config.SLOTS_PER_EPOCH) == current_epoch:
            new_current_epoch_pending_attestations.append(
                PendingAttestationRecord(
                    data=attestation.data,
                    aggregation_bitfield=attestation.aggregation_bitfield,
                    custody_bitfield=attestation.custody_bitfield,
                    slot_included=state.slot,
                )
            )
        elif slot_to_epoch(attestation.data.slot, config.SLOTS_PER_EPOCH) == previous_epoch:
            new_previous_epoch_pending_attestations.append(
                PendingAttestationRecord(
                    data=attestation.data,
                    aggregation_bitfield=attestation.aggregation_bitfield,
                    custody_bitfield=attestation.custody_bitfield,
                    slot_included=state.slot,
                )
            )

    state = state.copy(
        previous_epoch_attestations=(
            state.previous_epoch_attestations + tuple(new_previous_epoch_pending_attestations)
        ),
        current_epoch_attestations=(
            state.current_epoch_attestations + tuple(new_current_epoch_pending_attestations)
        ),
    )
    return state
Exemple #18
0
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState:
    """
    Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec:
    https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks

    For each shard from the past two epochs, find the shard block
    root that has been attested to by the most stake.
    If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard.
    Return resulting ``state``
    """
    latest_crosslinks = state.latest_crosslinks
    effective_balances = {
        ValidatorIndex(index): get_effective_balance(
            state.validator_balances,
            ValidatorIndex(index),
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }
    previous_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    next_epoch_start_slot = get_epoch_start_slot(
        state.next_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    for slot in range(previous_epoch_start_slot, next_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            winning_root, attesting_validator_indices = get_winning_root_and_participants(
                state=state,
                shard=shard,
                effective_balances=effective_balances,
                committee_config=CommitteeConfig(config),
            )
            if len(attesting_validator_indices) > 0:
                total_attesting_balance = get_total_balance(
                    state.validator_balances,
                    attesting_validator_indices,
                    config.MAX_DEPOSIT_AMOUNT,
                )
                total_balance = get_total_balance(
                    state.validator_balances,
                    crosslink_committee,
                    config.MAX_DEPOSIT_AMOUNT,
                )
                if 3 * total_attesting_balance >= 2 * total_balance:
                    latest_crosslinks = update_tuple_item(
                        latest_crosslinks,
                        shard,
                        CrosslinkRecord(
                            epoch=slot_to_epoch(Slot(slot),
                                                config.SLOTS_PER_EPOCH),
                            crosslink_data_root=winning_root,
                        ),
                    )
    state = state.copy(latest_crosslinks=latest_crosslinks, )
    return state
Exemple #19
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
Exemple #20
0
def _process_rewards_and_penalties_for_crosslinks(
    state: BeaconState, config: BeaconConfig,
    previous_epoch_attestations: Iterable[PendingAttestationRecord],
    effective_balances: Dict[ValidatorIndex,
                             Gwei], base_rewards: Dict[ValidatorIndex, Gwei],
    old_rewards_received: Dict[ValidatorIndex, SignedGwei]
) -> Dict[ValidatorIndex, SignedGwei]:
    rewards_received = old_rewards_received.copy()
    previous_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    current_epoch_start_slot = get_epoch_start_slot(
        state.current_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    # Also need current epoch attestations to compute the winning root.
    current_epoch_attestations = get_current_epoch_attestations(
        state, config.SLOTS_PER_EPOCH)
    for slot in range(previous_epoch_start_slot, current_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            filtered_attestations = _filter_attestations_by_shard(
                previous_epoch_attestations + current_epoch_attestations,
                shard,
            )
            try:
                winning_root, total_attesting_balance = get_winning_root(
                    state=state,
                    shard=shard,
                    attestations=filtered_attestations,
                    max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
                    committee_config=CommitteeConfig(config),
                )
            except NoWinningRootError:
                # No winning shard block root found for this shard.
                # Hence no one is counted as attesting validator.
                attesting_validator_indices: Iterable[ValidatorIndex] = set()
            else:
                attesting_validator_indices = get_attester_indices_from_attesttion(
                    state=state,
                    attestations=(a for a in filtered_attestations
                                  if a.data.shard == shard and
                                  a.data.crosslink_data_root == winning_root),
                    committee_config=CommitteeConfig(config),
                )
            total_balance = get_total_balance_from_effective_balances(
                effective_balances,
                crosslink_committee,
            )
            for index in attesting_validator_indices:
                reward = base_rewards[
                    index] * total_attesting_balance // total_balance
                rewards_received[index] = SignedGwei(rewards_received[index] +
                                                     reward)
            for index in set(crosslink_committee).difference(
                    attesting_validator_indices):
                penalty = base_rewards[index]
                rewards_received[index] = SignedGwei(rewards_received[index] -
                                                     penalty)
    return rewards_received
Exemple #21
0
def _process_rewards_and_penalties_for_finality(
    state: BeaconState, config: BeaconConfig,
    previous_epoch_active_validator_indices: Set[ValidatorIndex],
    previous_total_balance: Gwei,
    previous_epoch_attestations: Sequence[Attestation],
    previous_epoch_attester_indices: Set[ValidatorIndex],
    inclusion_infos: Dict[ValidatorIndex, InclusionInfo],
    effective_balances: Dict[ValidatorIndex,
                             Gwei], base_rewards: Dict[ValidatorIndex, Gwei],
    old_rewards_received: Dict[ValidatorIndex, SignedGwei]
) -> Dict[ValidatorIndex, SignedGwei]:
    previous_epoch_boundary_attestations = (
        a for a in previous_epoch_attestations
        if a.data.epoch_boundary_root == get_block_root(
            state,
            get_epoch_start_slot(
                state.previous_epoch(config.SLOTS_PER_EPOCH,
                                     config.GENESIS_EPOCH),
                config.SLOTS_PER_EPOCH,
            ),
            config.LATEST_BLOCK_ROOTS_LENGTH,
        ))
    previous_epoch_boundary_attester_indices = get_attester_indices_from_attesttion(
        state=state,
        attestations=previous_epoch_boundary_attestations,
        committee_config=CommitteeConfig(config),
    )

    previous_epoch_head_attestations = get_previous_epoch_head_attestations(
        state,
        config.SLOTS_PER_EPOCH,
        config.GENESIS_EPOCH,
        config.LATEST_BLOCK_ROOTS_LENGTH,
    )
    previous_epoch_head_attester_indices = get_attester_indices_from_attesttion(
        state=state,
        attestations=previous_epoch_head_attestations,
        committee_config=CommitteeConfig(config),
    )

    rewards_received = {index: Gwei(0) for index in old_rewards_received}
    penalties_received = rewards_received.copy()
    epochs_since_finality = state.next_epoch(
        config.SLOTS_PER_EPOCH) - state.finalized_epoch
    if epochs_since_finality <= 4:
        # 1.1 Expected FFG source:
        previous_epoch_attesting_balance = get_total_balance_from_effective_balances(
            effective_balances,
            previous_epoch_attester_indices,
        )
        # Reward validators in `previous_epoch_attester_indices`
        # # Punish active validators not in `previous_epoch_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_attester_indices, )
        rewards = {
            index:
            Gwei(base_rewards[index] * previous_epoch_attesting_balance //
                 previous_total_balance)
            for index in previous_epoch_attester_indices
        }
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_attester_indices,
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # 1.2 Expected FFG target:
        previous_epoch_boundary_attesting_balance = get_total_balance_from_effective_balances(
            effective_balances,
            previous_epoch_boundary_attester_indices,
        )
        # Reward validators in `previous_epoch_boundary_attester_indices`
        # Punish active validators not in `previous_epoch_boundary_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_boundary_attester_indices, )
        rewards = {
            index: Gwei(base_rewards[index] *
                        previous_epoch_boundary_attesting_balance //
                        previous_total_balance)
            for index in previous_epoch_boundary_attester_indices
        }
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_boundary_attester_indices,
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # 1.3 Expected beacon chain head:
        previous_epoch_head_attesting_balance = get_total_balance_from_effective_balances(
            effective_balances,
            previous_epoch_head_attester_indices,
        )
        # Reward validators in `previous_epoch_head_attester_indices`
        # Punish active validators not in `previous_epoch_head_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_head_attester_indices, )
        rewards = {
            index:
            Gwei(base_rewards[index] * previous_epoch_head_attesting_balance //
                 previous_total_balance)
            for index in previous_epoch_head_attester_indices
        }
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_head_attester_indices,
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # 1.4 Inclusion distance:
        # Reward validators in `previous_epoch_attester_indices`
        rewards = {
            index: Gwei(base_rewards[index] *
                        config.MIN_ATTESTATION_INCLUSION_DELAY //
                        inclusion_infos[index].inclusion_distance)
            for index in previous_epoch_attester_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_attester_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

    # epochs_since_finality > 4
    else:
        # Punish active validators not in `previous_epoch_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_attester_indices, )
        inactivity_penalties = {
            index: base_rewards[index] +
            (effective_balances[index] * epochs_since_finality //
             config.INACTIVITY_PENALTY_QUOTIENT // 2)
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=inactivity_penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish active validators not in `previous_epoch_boundary_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_boundary_attester_indices, )
        inactivity_penalties = {
            index: base_rewards[index] +
            (effective_balances[index] * epochs_since_finality //
             config.INACTIVITY_PENALTY_QUOTIENT // 2)
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=inactivity_penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish active validators not in `previous_epoch_head_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_head_attester_indices, )
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish penalized active validators
        penalties = {
            index: 3 * base_rewards[index] + 2 *
            (effective_balances[index] * epochs_since_finality //
             config.INACTIVITY_PENALTY_QUOTIENT // 2)
            for index in previous_epoch_active_validator_indices
            if state.validator_registry[index].slashed is True
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=penalties,
                indices_to_penalize={index
                                     for index in penalties},
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish validators in `previous_epoch_attester_indices`
        penalties = {
            index: Gwei(base_rewards[index] -
                        (base_rewards[index] *
                         config.MIN_ATTESTATION_INCLUSION_DELAY //
                         inclusion_infos[index].inclusion_distance))
            for index in previous_epoch_attester_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=penalties,
                indices_to_penalize=previous_epoch_attester_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

    historical_rewards_received = old_rewards_received.copy()
    for index in rewards_received:
        historical_rewards_received = _update_rewards_or_penalies(
            index,
            rewards_received[index] - penalties_received[index],
            historical_rewards_received,
        )
    return historical_rewards_received