Skip to content
Snippets Groups Projects
Commit 6cb220f3 authored by Wei Tang's avatar Wei Tang
Browse files

beacon: process rewards

parent 12aac56c
Branches
No related merge requests found
mod helpers;
mod justification;
mod crosslink;
mod reward;
use crate::primitives::*;
use crate::{Config, BeaconState, Error, utils, consts};
impl<C: Config> BeaconState<C> {
fn base_reward(&self, index: ValidatorIndex) -> Gwei {
let total_balance = self.total_active_balance();
let effective_balance =
self.validators[index as usize].effective_balance;
effective_balance * C::base_reward_factor() /
utils::integer_squareroot(total_balance) /
consts::BASE_REWARDS_PER_EPOCH
}
fn attestation_deltas(&self) -> Result<(Vec<Gwei>, Vec<Gwei>), Error> {
let previous_epoch = self.previous_epoch();
let total_balance = self.total_active_balance();
let mut rewards = (0..self.validators.len())
.map(|_| 0).collect::<Vec<_>>();
let mut penalties = (0..self.validators.len())
.map(|_| 0).collect::<Vec<_>>();
let eligible_validator_indices = self.validators.iter()
.enumerate()
.filter(|(_, v)| {
v.is_active(previous_epoch) ||
(v.slashed && previous_epoch + 1 < v.withdrawable_epoch)
})
.map(|(i, _)| i as u64)
.collect::<Vec<_>>();
// Micro-incentives for matching FFG source, FFG target, and head
let matching_source_attestations =
self.matching_source_attestations(previous_epoch)?;
let matching_target_attestations =
self.matching_target_attestations(previous_epoch)?;
let matching_head_attestations =
self.matching_head_attestations(previous_epoch)?;
for attestations in &[&matching_source_attestations,
&matching_target_attestations,
&matching_head_attestations]
{
let unslashed_attesting_indices =
self.unslashed_attesting_indices(attestations)?;
let attesting_balance = self.total_balance(&unslashed_attesting_indices);
for index in &eligible_validator_indices {
if unslashed_attesting_indices.contains(index) {
rewards[*index as usize] += self.base_reward(*index) *
attesting_balance / total_balance;
} else {
penalties[*index as usize] += self.base_reward(*index);
}
}
}
// Proposer and inclusion delay micro-rewards
for index in self.unslashed_attesting_indices(&matching_source_attestations)? {
let attestation = matching_source_attestations.iter()
.map(|a| Ok((
a,
self.attesting_indices(&a.data, &a.aggregation_bits)?
.contains(&index)
)))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.filter(|(_, c)| *c)
.map(|(a, _)| a)
.fold(matching_source_attestations[0].clone(), |a, b| {
if a.inclusion_delay < b.inclusion_delay { a } else { b.clone() }
});
let proposer_reward = self.base_reward(index) / C::proposer_reward_quotient();
rewards[attestation.proposer_index as usize] += proposer_reward;
let max_attester_reward = self.base_reward(index) - proposer_reward;
rewards[index as usize] += max_attester_reward *
(C::slots_per_epoch() + C::min_attestation_inclusion_delay() -
attestation.inclusion_delay) /
C::slots_per_epoch();
}
// Inactivity penalty
let finality_delay = previous_epoch - self.finalized_checkpoint.epoch;
if finality_delay > C::min_epochs_to_inactivity_penalty() {
let matching_target_attesting_indices =
self.unslashed_attesting_indices(&matching_target_attestations)?;
for index in &eligible_validator_indices {
penalties[*index as usize] += consts::BASE_REWARDS_PER_EPOCH *
self.base_reward(*index);
if !matching_target_attesting_indices.contains(index) {
penalties[*index as usize] +=
self.validators[*index as usize].effective_balance *
finality_delay / C::inactivity_penalty_quotient();
}
}
}
Ok((rewards, penalties))
}
fn crosslink_deltas(&self) -> Result<(Vec<Gwei>, Vec<Gwei>), Error> {
let mut rewards = (0..self.validators.len())
.map(|_| 0).collect::<Vec<_>>();
let mut penalties = (0..self.validators.len())
.map(|_| 0).collect::<Vec<_>>();
let epoch = self.previous_epoch();
for offset in 0..self.committee_count(epoch) {
let shard = (self.start_shard(epoch)? + offset) % C::shard_count();
let crosslink_committee = self.crosslink_committee(epoch, shard)?;
let (_winning_crosslink, attesting_indices) =
self.winning_crosslink_and_attesting_indices(epoch, shard)?;
let attesting_balance = self.total_balance(&attesting_indices);
let committee_balance = self.total_balance(&crosslink_committee);
for index in crosslink_committee {
let base_reward = self.base_reward(index);
if attesting_indices.contains(&index) {
rewards[index as usize] += base_reward * attesting_balance /
committee_balance;
} else {
penalties[index as usize] += base_reward;
}
}
}
Ok((rewards, penalties))
}
/// Process rewards and penalties
pub fn process_rewards_and_penalties(&mut self) -> Result<(), Error> {
if self.current_epoch() == C::genesis_epoch() {
return Ok(())
}
let (rewards1, penalties1) = self.attestation_deltas()?;
let (rewards2, penalties2) = self.crosslink_deltas()?;
for i in 0..self.validators.len() {
self.increase_balance(i as u64, rewards1[i] + rewards2[i]);
self.decrease_balance(i as u64, penalties1[i] + penalties2[i]);
}
Ok(())
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment