Exemplo n.º 1
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)
Exemplo n.º 2
0
def test_process_rewards_and_penalties_for_crosslinks(
        genesis_state, config, slots_per_epoch, target_committee_size,
        shard_count, current_slot, num_attesting_validators,
        max_effective_balance, min_attestation_inclusion_delay,
        sample_attestation_data_params,
        sample_pending_attestation_record_params):
    state = genesis_state.copy(slot=current_slot, )
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)

    prev_epoch_start_slot = compute_start_slot_of_epoch(
        previous_epoch, slots_per_epoch)
    prev_epoch_crosslink_committees = [
        get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )[0] for slot in range(prev_epoch_start_slot, prev_epoch_start_slot +
                               slots_per_epoch)
    ]

    # Record which validators attest during each slot for reward collation.
    each_slot_attestion_validators_list = []

    epoch_start_shard = get_start_shard(
        state,
        previous_epoch,
        CommitteeConfig(config),
    )
    shard_delta = get_shard_delta(
        state,
        previous_epoch,
        CommitteeConfig(config),
    )

    a = epoch_start_shard
    b = epoch_start_shard + shard_delta
    if a > b:
        valid_shards_for_epoch = range(b, a)
    else:
        valid_shards_for_epoch = range(a, b)

    indices_to_check = set()

    previous_epoch_attestations = []
    for committee, shard in prev_epoch_crosslink_committees:
        if shard not in valid_shards_for_epoch:
            continue
        for index in committee:
            indices_to_check.add(index)
        # Randomly sample `num_attesting_validators` validators
        # from the committee to attest in this slot.
        crosslink_attesting_validators = random.sample(
            committee,
            num_attesting_validators,
        )
        each_slot_attestion_validators_list.append(
            crosslink_attesting_validators)
        participants_bitfield = get_empty_bitfield(len(committee))
        for index in crosslink_attesting_validators:
            participants_bitfield = set_voted(participants_bitfield,
                                              committee.index(index))
        previous_epoch_attestations.append(
            PendingAttestation(
                **sample_pending_attestation_record_params).copy(
                    aggregation_bits=participants_bitfield,
                    data=AttestationData(
                        **sample_attestation_data_params).copy(
                            target=Checkpoint(epoch=previous_epoch, ),
                            crosslink=Crosslink(
                                shard=shard,
                                parent_root=Crosslink().hash_tree_root,
                            ),
                        ),
                ))
    state = state.copy(
        previous_epoch_attestations=tuple(previous_epoch_attestations), )

    rewards_received, penalties_received = get_crosslink_deltas(
        state,
        config,
    )

    expected_rewards_received = {
        index: 0
        for index in range(len(state.validators))
    }
    validator_balance = max_effective_balance
    for i in range(slots_per_epoch):
        crosslink_committee, shard = prev_epoch_crosslink_committees[i]
        if shard not in valid_shards_for_epoch:
            continue
        attesting_validators = each_slot_attestion_validators_list[i]
        total_attesting_balance = len(attesting_validators) * validator_balance
        total_committee_balance = len(crosslink_committee) * validator_balance
        for index in crosslink_committee:
            if index in attesting_validators:
                reward = get_base_reward(
                    state=state,
                    index=index,
                    config=config,
                ) * total_attesting_balance // total_committee_balance
                expected_rewards_received[index] += reward
            else:
                penalty = get_base_reward(
                    state=state,
                    index=index,
                    config=config,
                )
                expected_rewards_received[index] -= penalty

    # Check the rewards/penalties match
    for index in range(len(state.validators)):
        if index not in indices_to_check:
            continue
        assert (rewards_received[index] -
                penalties_received[index] == expected_rewards_received[index])
Exemplo n.º 3
0
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),
    )
Exemplo n.º 4
0
def get_proposer_reward(state: BeaconState, attesting_index: ValidatorIndex,
                        config: Eth2Config) -> Gwei:
    return Gwei(
        get_base_reward(state, attesting_index, config) //
        config.PROPOSER_REWARD_QUOTIENT)
Exemplo n.º 5
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
    )
def test_get_base_reward(genesis_state, config):
    assert get_base_reward(genesis_state, 0, config) == 905097
Exemplo 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
def test_process_rewards_and_penalties_for_crosslinks(
        random,
        n_validators_state,
        config,
        slots_per_epoch,
        target_committee_size,
        shard_count,
        current_slot,
        num_attesting_validators,
        max_deposit_amount,
        min_attestation_inclusion_delay,
        sample_attestation_data_params,
        sample_pending_attestation_record_params):
    previous_epoch = current_slot // slots_per_epoch - 1
    state = n_validators_state.copy(
        slot=current_slot,
    )
    # Compute previous epoch committees
    prev_epoch_start_slot = get_epoch_start_slot(previous_epoch, slots_per_epoch)
    prev_epoch_crosslink_committees = [
        get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )[0] for slot in range(prev_epoch_start_slot, prev_epoch_start_slot + slots_per_epoch)
    ]

    # Record which validators attest during each slot for reward collation.
    each_slot_attestion_validators_list = []

    previous_epoch_attestations = []
    for i in range(slots_per_epoch):
        committee, shard = prev_epoch_crosslink_committees[i]
        # Randomly sample `num_attesting_validators` validators
        # from the committee to attest in this slot.
        crosslink_data_root_attesting_validators = random.sample(
            committee,
            num_attesting_validators,
        )
        each_slot_attestion_validators_list.append(crosslink_data_root_attesting_validators)
        participants_bitfield = get_empty_bitfield(target_committee_size)
        for index in crosslink_data_root_attesting_validators:
            participants_bitfield = set_voted(participants_bitfield, committee.index(index))
        data_slot = i + previous_epoch * slots_per_epoch
        previous_epoch_attestations.append(
            PendingAttestationRecord(**sample_pending_attestation_record_params).copy(
                data=AttestationData(**sample_attestation_data_params).copy(
                    slot=data_slot,
                    shard=shard,
                ),
                aggregation_bitfield=participants_bitfield,
                slot_included=(data_slot + min_attestation_inclusion_delay),
            )
        )

    active_validators = set(
        [
            i for i in range(len(state.validator_registry))
        ]
    )

    effective_balances = {
        index: get_effective_balance(
            state.validator_balances,
            index,
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in active_validators
    }

    validator_balance = max_deposit_amount
    total_active_balance = len(active_validators) * validator_balance

    _base_reward_quotient = (
        integer_squareroot(total_active_balance) // config.BASE_REWARD_QUOTIENT
    )
    base_rewards = {
        index: get_base_reward(
            state=state,
            index=index,
            base_reward_quotient=_base_reward_quotient,
            max_deposit_amount=max_deposit_amount,
        )
        for index in active_validators
    }

    rewards_received = {
        index: 0
        for index in range(len(state.validator_registry))
    }

    rewards_received = _process_rewards_and_penalties_for_crosslinks(
        state,
        config,
        tuple(previous_epoch_attestations),
        effective_balances,
        base_rewards,
        rewards_received,
    )

    expected_rewards_received = {
        index: 0
        for index in range(len(state.validator_registry))
    }
    for i in range(slots_per_epoch):
        crosslink_committee, shard = prev_epoch_crosslink_committees[i]
        attesting_validators = each_slot_attestion_validators_list[i]
        total_attesting_balance = len(attesting_validators) * validator_balance
        total_committee_balance = len(crosslink_committee) * validator_balance
        _base_reward_quotient = (
            integer_squareroot(total_active_balance) // config.BASE_REWARD_QUOTIENT
        )
        for index in attesting_validators:
            reward = get_base_reward(
                state=state,
                index=index,
                base_reward_quotient=_base_reward_quotient,
                max_deposit_amount=max_deposit_amount,
            ) * total_attesting_balance // total_committee_balance
            expected_rewards_received[index] += reward
        for index in set(crosslink_committee).difference(attesting_validators):
            penalty = get_base_reward(
                state=state,
                index=index,
                base_reward_quotient=_base_reward_quotient,
                max_deposit_amount=max_deposit_amount,
            )
            expected_rewards_received[index] -= penalty

    # Check the rewards/penalties match
    for index, reward_received in rewards_received.items():
        assert rewards_received[index] == expected_rewards_received[index]
Exemplo n.º 9
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