use crate::{BeaconChain, BeaconChainError, BeaconChainTypes}; use eth2::lighthouse::StandardBlockReward; use operation_pool::RewardCache; use safe_arith::SafeArith; use slog::error; use state_processing::{ common::{ altair, get_attestation_participation_flag_indices, get_attesting_indices_from_state, }, per_block_processing::{ altair::sync_committee::compute_sync_aggregate_rewards, get_slashable_indices, }, }; use store::{ consts::altair::{PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, WEIGHT_DENOMINATOR}, RelativeEpoch, }; use types::{AbstractExecPayload, BeaconBlockRef, BeaconState, BeaconStateError, Hash256}; type BeaconBlockSubRewardValue = u64; impl BeaconChain { pub fn compute_beacon_block_reward>( &self, block: BeaconBlockRef<'_, T::EthSpec, Payload>, block_root: Hash256, state: &mut BeaconState, ) -> Result { if block.slot() != state.slot() { return Err(BeaconChainError::BlockRewardSlotError); } state.build_committee_cache(RelativeEpoch::Previous, &self.spec)?; state.build_committee_cache(RelativeEpoch::Current, &self.spec)?; let proposer_index = block.proposer_index(); let sync_aggregate_reward = self.compute_beacon_block_sync_aggregate_reward(block, state)?; let proposer_slashing_reward = self .compute_beacon_block_proposer_slashing_reward(block, state) .map_err(|e| { error!( self.log, "Error calculating proposer slashing reward"; "error" => ?e ); BeaconChainError::BlockRewardError })?; let attester_slashing_reward = self .compute_beacon_block_attester_slashing_reward(block, state) .map_err(|e| { error!( self.log, "Error calculating attester slashing reward"; "error" => ?e ); BeaconChainError::BlockRewardError })?; let block_attestation_reward = if let BeaconState::Base(_) = state { self.compute_beacon_block_attestation_reward_base(block, block_root, state) .map_err(|e| { error!( self.log, "Error calculating base block attestation reward"; "error" => ?e ); BeaconChainError::BlockRewardAttestationError })? } else { self.compute_beacon_block_attestation_reward_altair(block, state) .map_err(|e| { error!( self.log, "Error calculating altair block attestation reward"; "error" => ?e ); BeaconChainError::BlockRewardAttestationError })? }; let total_reward = sync_aggregate_reward .safe_add(proposer_slashing_reward)? .safe_add(attester_slashing_reward)? .safe_add(block_attestation_reward)?; Ok(StandardBlockReward { proposer_index, total: total_reward, attestations: block_attestation_reward, sync_aggregate: sync_aggregate_reward, proposer_slashings: proposer_slashing_reward, attester_slashings: attester_slashing_reward, }) } fn compute_beacon_block_sync_aggregate_reward>( &self, block: BeaconBlockRef<'_, T::EthSpec, Payload>, state: &BeaconState, ) -> Result { if let Ok(sync_aggregate) = block.body().sync_aggregate() { let (_, proposer_reward_per_bit) = compute_sync_aggregate_rewards(state, &self.spec) .map_err(|_| BeaconChainError::BlockRewardSyncError)?; Ok(sync_aggregate.sync_committee_bits.num_set_bits() as u64 * proposer_reward_per_bit) } else { Ok(0) } } fn compute_beacon_block_proposer_slashing_reward>( &self, block: BeaconBlockRef<'_, T::EthSpec, Payload>, state: &BeaconState, ) -> Result { let mut proposer_slashing_reward = 0; let proposer_slashings = block.body().proposer_slashings(); for proposer_slashing in proposer_slashings { proposer_slashing_reward.safe_add_assign( state .get_validator(proposer_slashing.proposer_index() as usize)? .effective_balance .safe_div(self.spec.whistleblower_reward_quotient)?, )?; } Ok(proposer_slashing_reward) } fn compute_beacon_block_attester_slashing_reward>( &self, block: BeaconBlockRef<'_, T::EthSpec, Payload>, state: &BeaconState, ) -> Result { let mut attester_slashing_reward = 0; let attester_slashings = block.body().attester_slashings(); for attester_slashing in attester_slashings { for attester_index in get_slashable_indices(state, attester_slashing)? { attester_slashing_reward.safe_add_assign( state .get_validator(attester_index as usize)? .effective_balance .safe_div(self.spec.whistleblower_reward_quotient)?, )?; } } Ok(attester_slashing_reward) } fn compute_beacon_block_attestation_reward_base>( &self, block: BeaconBlockRef<'_, T::EthSpec, Payload>, block_root: Hash256, state: &BeaconState, ) -> Result { // Call compute_block_reward in the base case // Since base does not have sync aggregate, we only grab attesation portion of the returned // value let mut reward_cache = RewardCache::default(); let block_attestation_reward = self .compute_block_reward(block, block_root, state, &mut reward_cache, true)? .attestation_rewards .total; Ok(block_attestation_reward) } fn compute_beacon_block_attestation_reward_altair>( &self, block: BeaconBlockRef<'_, T::EthSpec, Payload>, state: &mut BeaconState, ) -> Result { let total_active_balance = state.get_total_active_balance()?; let base_reward_per_increment = altair::BaseRewardPerIncrement::new(total_active_balance, &self.spec)?; let mut total_proposer_reward = 0; let proposer_reward_denominator = WEIGHT_DENOMINATOR .safe_sub(PROPOSER_WEIGHT)? .safe_mul(WEIGHT_DENOMINATOR)? .safe_div(PROPOSER_WEIGHT)?; for attestation in block.body().attestations() { let data = &attestation.data; let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64(); let participation_flag_indices = get_attestation_participation_flag_indices( state, data, inclusion_delay, &self.spec, )?; let attesting_indices = get_attesting_indices_from_state(state, attestation)?; let mut proposer_reward_numerator = 0; for index in attesting_indices { let index = index as usize; for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() { let epoch_participation = state.get_epoch_participation_mut(data.target.epoch)?; let validator_participation = epoch_participation .get_mut(index) .ok_or(BeaconStateError::ParticipationOutOfBounds(index))?; if participation_flag_indices.contains(&flag_index) && !validator_participation.has_flag(flag_index)? { validator_participation.add_flag(flag_index)?; proposer_reward_numerator.safe_add_assign( altair::get_base_reward( state, index, base_reward_per_increment, &self.spec, )? .safe_mul(weight)?, )?; } } } total_proposer_reward.safe_add_assign( proposer_reward_numerator.safe_div(proposer_reward_denominator)?, )?; } Ok(total_proposer_reward) } }