def _update_shuffling_epoch(state: BeaconState, slots_per_epoch: int) -> BeaconState: """ Updates the ``current_shuffling_epoch`` to the ``state``'s next epoch. """ return state.copy( current_shuffling_epoch=state.next_epoch(slots_per_epoch), )
def process_final_updates(state: BeaconState, config: BeaconConfig) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) state = _update_latest_active_index_roots(state, CommitteeConfig(config)) state = state.copy( latest_slashed_balances=update_tuple_item( state.latest_slashed_balances, next_epoch % config.LATEST_SLASHED_EXIT_LENGTH, state.latest_slashed_balances[current_epoch % config.LATEST_SLASHED_EXIT_LENGTH], ), latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, next_epoch % config.LATEST_SLASHED_EXIT_LENGTH, get_randao_mix( state=state, epoch=current_epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), ), ) latest_attestations = tuple( filter( lambda attestation: (slot_to_epoch(attestation.data.slot, config.SLOTS_PER_EPOCH) >= current_epoch), state.latest_attestations)) state = state.copy(latest_attestations=latest_attestations, ) return state
def _determine_next_eth1_votes(state: BeaconState, config: Eth2Config) -> HashableList[Eth1Data]: if (state.next_epoch(config.SLOTS_PER_EPOCH) % config.EPOCHS_PER_ETH1_VOTING_PERIOD == 0): return HashableList.from_iterable((), state.eth1_data_votes.sedes) else: return state.eth1_data_votes
def get_committee_assignment( state: BeaconState, config: Eth2Config, epoch: Epoch, validator_index: ValidatorIndex, ) -> CommitteeAssignment: """ Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``. ``CommitteeAssignment.committee`` is the tuple array of validators in the committee ``CommitteeAssignment.committee_index`` is the index to which the committee is assigned ``CommitteeAssignment.slot`` is the slot at which the committee is assigned """ next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) if epoch > next_epoch: raise ValidationError( f"Epoch for committee assignment ({epoch}) must not be after next epoch {next_epoch}." ) for committee, committee_index, slot in iterate_committees_at_epoch( state, epoch, CommitteeConfig(config) ): if validator_index in committee: return CommitteeAssignment( committee, CommitteeIndex(committee_index), Slot(slot) ) raise NoCommitteeAssignment
def process_final_updates(state: BeaconState, config: BeaconConfig) -> BeaconState: current_epoch = state.current_epoch(config.EPOCH_LENGTH) next_epoch = state.next_epoch(config.EPOCH_LENGTH) state = state.copy( latest_penalized_balances=update_tuple_item( state.latest_penalized_balances, next_epoch % config.LATEST_PENALIZED_EXIT_LENGTH, state.latest_penalized_balances[ current_epoch % config.LATEST_PENALIZED_EXIT_LENGTH], ), latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, next_epoch % config.LATEST_PENALIZED_EXIT_LENGTH, get_randao_mix( state=state, epoch=current_epoch, epoch_length=config.EPOCH_LENGTH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), ), ) latest_attestations = tuple( filter( lambda attestation: (slot_to_epoch(attestation.data.slot, config. EPOCH_LENGTH) >= current_epoch), state.latest_attestations)) state = state.copy(latest_attestations=latest_attestations, ) return state
def _update_latest_index_roots(state: BeaconState, committee_config: CommitteeConfig) -> BeaconState: """ Return the BeaconState with updated `latest_index_roots`. """ next_epoch = state.next_epoch(committee_config.EPOCH_LENGTH) # TODO: chanege to hash_tree_root active_validator_indices = get_active_validator_indices( state.validator_registry, EpochNumber(next_epoch + committee_config.ENTRY_EXIT_DELAY), ) index_root = hash_eth2( b''.join( [ index.to_bytes(32, 'big') for index in active_validator_indices ] ) ) latest_index_roots = update_tuple_item( state.latest_index_roots, ( (next_epoch + committee_config.ENTRY_EXIT_DELAY) % committee_config.LATEST_INDEX_ROOTS_LENGTH ), index_root, ) return state.copy( latest_index_roots=latest_index_roots, )
def process_final_updates(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) state = _update_latest_active_index_roots(state, CommitteeConfig(config)) state = state.copy( latest_slashed_balances=update_tuple_item( state.latest_slashed_balances, next_epoch % config.LATEST_SLASHED_EXIT_LENGTH, state.latest_slashed_balances[current_epoch % config.LATEST_SLASHED_EXIT_LENGTH], ), latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, next_epoch % config.LATEST_RANDAO_MIXES_LENGTH, get_randao_mix( state=state, epoch=current_epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), ), ) state = _update_historical_roots(state, next_epoch, config) # Rotate current/previous epoch attestations state = state.copy( previous_epoch_attestations=state.current_epoch_attestations, current_epoch_attestations=(), ) return state
def process_eth1_data_votes(state: BeaconState, config: Eth2Config) -> BeaconState: next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) should_process = next_epoch % config.EPOCHS_PER_ETH1_VOTING_PERIOD == 0 if should_process: return _update_eth1_vote_if_exists(state, config) return state
def _compute_next_slashings(state: BeaconState, config: Eth2Config) -> Tuple[Gwei, ...]: next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) return update_tuple_item( state.slashings, next_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR, Gwei(0), )
def _compute_next_randao_mixes(state: BeaconState, config: Eth2Config) -> Tuple[Hash32, ...]: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) return state.randao_mixes.set( next_epoch % config.EPOCHS_PER_HISTORICAL_VECTOR, get_randao_mix(state, current_epoch, config.EPOCHS_PER_HISTORICAL_VECTOR), )
def _compute_next_historical_roots(state: BeaconState, config: Eth2Config) -> Tuple[Hash32, ...]: next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) new_historical_roots = state.historical_roots if next_epoch % (config.SLOTS_PER_HISTORICAL_ROOT // config.SLOTS_PER_EPOCH) == 0: historical_batch = HistoricalBatch( block_roots=state.block_roots, state_roots=state.state_roots, ) new_historical_roots = state.historical_roots + (historical_batch.root,) return new_historical_roots
def _compute_next_slashed_balances(state: BeaconState, config: Eth2Config) -> Tuple[Gwei, ...]: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) return update_tuple_item( state.slashed_balances, next_epoch % config.EPOCHS_PER_SLASHED_BALANCES_VECTOR, state.slashed_balances[ current_epoch % config.EPOCHS_PER_SLASHED_BALANCES_VECTOR ], )
def _compute_next_compact_committees_roots( state: BeaconState, config: Eth2Config ) -> Tuple[Hash32, ...]: next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) committee_root_position = next_epoch % config.EPOCHS_PER_HISTORICAL_VECTOR return update_tuple_item( state.compact_committees_roots, committee_root_position, get_compact_committees_root(state, next_epoch, CommitteeConfig(config)), )
def _compute_next_active_index_roots(state: BeaconState, config: Eth2Config) -> Tuple[Hash32, ...]: next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) index_root_position = (next_epoch + config.ACTIVATION_EXIT_DELAY ) % config.EPOCHS_PER_HISTORICAL_VECTOR validator_indices_for_new_active_index_root = get_active_validator_indices( state.validators, Epoch(next_epoch + config.ACTIVATION_EXIT_DELAY)) new_active_index_root = ssz.get_hash_tree_root( validator_indices_for_new_active_index_root, ssz.sedes.List(ssz.uint64, config.VALIDATOR_REGISTRY_LIMIT), ) return update_tuple_item(state.active_index_roots, index_root_position, new_active_index_root)
def get_committee_assignment( state: BeaconState, config: Eth2Config, epoch: Epoch, validator_index: ValidatorIndex, ) -> CommitteeAssignment: """ Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``. ``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. """ next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) if epoch > next_epoch: raise ValidationError( f"Epoch for committee assignment ({epoch}) must not be after next epoch {next_epoch}." ) active_validators = get_active_validator_indices(state.validators, epoch) committees_per_slot = ( get_committee_count( len(active_validators), config.SHARD_COUNT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ) // config.SLOTS_PER_EPOCH ) epoch_start_slot = compute_start_slot_of_epoch(epoch, config.SLOTS_PER_EPOCH) epoch_start_shard = get_start_shard(state, epoch, CommitteeConfig(config)) for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH): offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH) slot_start_shard = (epoch_start_shard + offset) % config.SHARD_COUNT for i in range(committees_per_slot): shard = Shard((slot_start_shard + i) % config.SHARD_COUNT) committee = get_crosslink_committee( state, epoch, shard, CommitteeConfig(config) ) if validator_index in committee: is_proposer = validator_index == get_beacon_proposer_index( state.copy(slot=slot), CommitteeConfig(config) ) return CommitteeAssignment( committee, Shard(shard), Slot(slot), is_proposer ) raise NoCommitteeAssignment
def get_start_shard(state: BeaconState, epoch: Epoch, config: CommitteeConfig) -> Shard: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) if epoch > next_epoch: raise ValidationError("Asking for start shard for an epoch after next") check_epoch = int(next_epoch) shard = (state.start_shard + get_shard_delta(state, current_epoch, config)) % config.SHARD_COUNT while check_epoch > epoch: check_epoch -= 1 shard = (shard + config.SHARD_COUNT - get_shard_delta( state, Epoch(check_epoch), config)) % config.SHARD_COUNT return shard
def _update_latest_index_roots(state: BeaconState, config: BeaconConfig) -> BeaconState: """ Return the BeaconState with updated `latest_index_roots`. """ next_epoch = state.next_epoch(config.EPOCH_LENGTH) # TODO: chanege to hash_tree_root active_validator_indices = get_active_validator_indices( state.validator_registry, # TODO: change to `per-epoch` version state.slot, ) index_root = hash_eth2(b''.join( [index.to_bytes(32, 'big') for index in active_validator_indices])) latest_index_roots = update_tuple_item( state.latest_index_roots, next_epoch % config.LATEST_INDEX_ROOTS_LENGTH, index_root, ) return state.copy(latest_index_roots=latest_index_roots, )
def _update_latest_active_index_roots( state: BeaconState, committee_config: CommitteeConfig) -> BeaconState: """ Return the BeaconState with updated `latest_active_index_roots`. """ next_epoch = state.next_epoch(committee_config.SLOTS_PER_EPOCH) active_validator_indices = get_active_validator_indices( state.validator_registry, Epoch(next_epoch + committee_config.ACTIVATION_EXIT_DELAY), ) index_root = ssz.hash_tree_root( active_validator_indices, ssz.sedes.List(ssz.uint64), ) latest_active_index_roots = update_tuple_item( state.latest_active_index_roots, ((next_epoch + committee_config.ACTIVATION_EXIT_DELAY) % committee_config.LATEST_ACTIVE_INDEX_ROOTS_LENGTH), index_root, ) return state.copy(latest_active_index_roots=latest_active_index_roots, )
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 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
def _process_rewards_and_penalties_for_finality( state: BeaconState, config: Eth2Config, previous_epoch_active_validator_indices: Sequence[ValidatorIndex], previous_total_balance: Gwei, previous_epoch_attestations: Sequence[Attestation], previous_epoch_attester_indices: Sequence[ValidatorIndex], inclusion_infos: Dict[ValidatorIndex, InclusionInfo], effective_balances: Dict[ValidatorIndex, Gwei], base_rewards: Dict[ValidatorIndex, Gwei] ) -> Tuple[Dict[ValidatorIndex, Gwei], Dict[ValidatorIndex, Gwei]]: # noqa: E501 previous_epoch_boundary_attestations = get_previous_epoch_boundary_attestations( state, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ) previous_epoch_boundary_attester_indices = get_attester_indices_from_attestations( state=state, attestations=previous_epoch_boundary_attestations, committee_config=CommitteeConfig(config), ) previous_epoch_head_attestations = get_previous_epoch_matching_head_attestations( state, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ) previous_epoch_head_attester_indices = get_attester_indices_from_attestations( state=state, attestations=previous_epoch_head_attestations, committee_config=CommitteeConfig(config), ) epochs_since_finality = state.next_epoch( config.SLOTS_PER_EPOCH) - state.finalized_epoch if epochs_since_finality <= 4: return _compute_normal_justification_and_finalization_deltas( state, config, previous_epoch_active_validator_indices, previous_total_balance, previous_epoch_attester_indices, previous_epoch_boundary_attester_indices, previous_epoch_head_attester_indices, inclusion_infos, effective_balances, base_rewards, ) # epochs_since_finality > 4 else: return _compute_inactivity_leak_deltas( state, config, previous_epoch_active_validator_indices, previous_epoch_attester_indices, previous_epoch_boundary_attester_indices, previous_epoch_head_attester_indices, inclusion_infos, effective_balances, base_rewards, epochs_since_finality, )
def process_validator_registry(state: BeaconState, config: BeaconConfig) -> BeaconState: state = state.copy( previous_calculation_epoch=state.current_calculation_epoch, previous_epoch_start_shard=state.current_epoch_start_shard, previous_epoch_seed=state.current_epoch_seed, ) need_to_update, num_shards_in_committees = _check_if_update_validator_registry(state, config) if need_to_update: state = update_validator_registry(state) # Update step-by-step since updated `state.current_calculation_epoch` # is used to calculate other value). Follow the spec tightly now. state = state.copy( current_calculation_epoch=state.next_epoch(config.EPOCH_LENGTH), ) state = state.copy( current_epoch_start_shard=( state.current_epoch_start_shard + num_shards_in_committees ) % config.SHARD_COUNT, ) # The `helpers.generate_seed` function is only present to provide an entry point # for mocking this out in tests. current_epoch_seed = helpers.generate_seed( state=state, epoch=state.current_calculation_epoch, epoch_length=config.EPOCH_LENGTH, seed_lookahead=config.SEED_LOOKAHEAD, entry_exit_delay=config.ENTRY_EXIT_DELAY, latest_index_roots_length=config.LATEST_INDEX_ROOTS_LENGTH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ) state = state.copy( current_epoch_seed=current_epoch_seed, ) else: epochs_since_last_registry_change = ( state.current_epoch(config.EPOCH_LENGTH) - state.validator_registry_update_epoch ) if is_power_of_two(epochs_since_last_registry_change): # Update step-by-step since updated `state.current_calculation_epoch` # is used to calculate other value). Follow the spec tightly now. state = state.copy( current_calculation_epoch=state.next_epoch(config.EPOCH_LENGTH), ) # The `helpers.generate_seed` function is only present to provide an entry point # for mocking this out in tests. current_epoch_seed = helpers.generate_seed( state=state, epoch=state.current_calculation_epoch, epoch_length=config.EPOCH_LENGTH, seed_lookahead=config.SEED_LOOKAHEAD, entry_exit_delay=config.ENTRY_EXIT_DELAY, latest_index_roots_length=config.LATEST_INDEX_ROOTS_LENGTH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ) state = state.copy( current_epoch_seed=current_epoch_seed, ) else: pass return state
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