Improve crosslink reward processing
This commit is contained in:
parent
6f919e6f7d
commit
a319144835
@ -227,11 +227,11 @@ fn bench_epoch_processing(c: &mut Criterion, state: &BeaconState, spec: &ChainSp
|
|||||||
&format!("{}/epoch_processing", desc),
|
&format!("{}/epoch_processing", desc),
|
||||||
Benchmark::new("process_rewards_and_penalties", move |b| {
|
Benchmark::new("process_rewards_and_penalties", move |b| {
|
||||||
b.iter_batched(
|
b.iter_batched(
|
||||||
|| state_clone.clone(),
|
|| (state_clone.clone(), attesters.clone()),
|
||||||
|mut state| {
|
|(mut state, mut attesters)| {
|
||||||
process_rewards_and_penalities(
|
process_rewards_and_penalities(
|
||||||
&mut state,
|
&mut state,
|
||||||
&attesters,
|
&mut attesters,
|
||||||
previous_total_balance,
|
previous_total_balance,
|
||||||
&winning_root_for_shards,
|
&winning_root_for_shards,
|
||||||
&spec_clone,
|
&spec_clone,
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
use attesters::Attesters;
|
use attesters::Attesters;
|
||||||
use errors::EpochProcessingError as Error;
|
use errors::EpochProcessingError as Error;
|
||||||
use fnv::FnvHashSet;
|
|
||||||
use integer_sqrt::IntegerSquareRoot;
|
use integer_sqrt::IntegerSquareRoot;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use ssz::TreeHash;
|
use ssz::TreeHash;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::FromIterator;
|
|
||||||
use types::{validator_registry::get_active_validator_indices, *};
|
use types::{validator_registry::get_active_validator_indices, *};
|
||||||
use winning_root::{winning_root, WinningRoot};
|
use winning_root::{winning_root, WinningRoot};
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result
|
|||||||
spec,
|
spec,
|
||||||
);
|
);
|
||||||
|
|
||||||
let attesters = calculate_attester_sets(&state, &active_validator_indices, spec)?;
|
let mut attesters = calculate_attester_sets(&state, &active_validator_indices, spec)?;
|
||||||
|
|
||||||
process_eth1_data(state, spec);
|
process_eth1_data(state, spec);
|
||||||
|
|
||||||
@ -63,7 +61,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result
|
|||||||
// Rewards and Penalities
|
// Rewards and Penalities
|
||||||
process_rewards_and_penalities(
|
process_rewards_and_penalities(
|
||||||
state,
|
state,
|
||||||
&attesters,
|
&mut attesters,
|
||||||
previous_total_balance,
|
previous_total_balance,
|
||||||
&winning_root_for_shards,
|
&winning_root_for_shards,
|
||||||
spec,
|
spec,
|
||||||
@ -286,21 +284,13 @@ pub fn process_crosslinks(
|
|||||||
/// Spec v0.4.0
|
/// Spec v0.4.0
|
||||||
pub fn process_rewards_and_penalities(
|
pub fn process_rewards_and_penalities(
|
||||||
state: &mut BeaconState,
|
state: &mut BeaconState,
|
||||||
attesters: &Attesters,
|
attesters: &mut Attesters,
|
||||||
previous_total_balance: u64,
|
previous_total_balance: u64,
|
||||||
winning_root_for_shards: &WinningRootHashSet,
|
winning_root_for_shards: &WinningRootHashSet,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let next_epoch = state.next_epoch(spec);
|
let next_epoch = state.next_epoch(spec);
|
||||||
|
|
||||||
/*
|
|
||||||
let previous_epoch_attestations: Vec<&PendingAttestation> = state
|
|
||||||
.latest_attestations
|
|
||||||
.par_iter()
|
|
||||||
.filter(|a| a.data.slot.epoch(spec.slots_per_epoch) == state.previous_epoch(spec))
|
|
||||||
.collect();
|
|
||||||
*/
|
|
||||||
|
|
||||||
let base_reward_quotient = previous_total_balance.integer_sqrt() / spec.base_reward_quotient;
|
let base_reward_quotient = previous_total_balance.integer_sqrt() / spec.base_reward_quotient;
|
||||||
|
|
||||||
if base_reward_quotient == 0 {
|
if base_reward_quotient == 0 {
|
||||||
@ -310,29 +300,7 @@ pub fn process_rewards_and_penalities(
|
|||||||
return Err(Error::PreviousTotalBalanceIsZero);
|
return Err(Error::PreviousTotalBalanceIsZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
attesters.process_winning_roots(state, winning_root_for_shards, spec)?;
|
||||||
// Map is ValidatorIndex -> ProposerIndex
|
|
||||||
let mut inclusion_slots: FnvHashMap<usize, (Slot, usize)> = FnvHashMap::default();
|
|
||||||
for a in &previous_epoch_attestations {
|
|
||||||
let participants =
|
|
||||||
state.get_attestation_participants(&a.data, &a.aggregation_bitfield, spec)?;
|
|
||||||
let inclusion_distance = (a.inclusion_slot - a.data.slot).as_u64();
|
|
||||||
for participant in participants {
|
|
||||||
if let Some((existing_distance, _)) = inclusion_slots.get(&participant) {
|
|
||||||
if *existing_distance <= inclusion_distance {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let proposer_index = state
|
|
||||||
.get_beacon_proposer_index(a.data.slot, spec)
|
|
||||||
.map_err(|_| Error::UnableToDetermineProducer)?;
|
|
||||||
inclusion_slots.insert(
|
|
||||||
participant,
|
|
||||||
(Slot::from(inclusion_distance), proposer_index),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Justification and finalization
|
// Justification and finalization
|
||||||
|
|
||||||
@ -345,10 +313,9 @@ pub fn process_rewards_and_penalities(
|
|||||||
.map(|(index, &balance)| {
|
.map(|(index, &balance)| {
|
||||||
let mut balance = balance;
|
let mut balance = balance;
|
||||||
let status = &attesters.statuses[index];
|
let status = &attesters.statuses[index];
|
||||||
|
|
||||||
if epochs_since_finality <= 4 {
|
|
||||||
let base_reward = state.base_reward(index, base_reward_quotient, spec);
|
let base_reward = state.base_reward(index, base_reward_quotient, spec);
|
||||||
|
|
||||||
|
if epochs_since_finality <= 4 {
|
||||||
// Expected FFG source
|
// Expected FFG source
|
||||||
if status.is_previous_epoch {
|
if status.is_previous_epoch {
|
||||||
safe_add_assign!(
|
safe_add_assign!(
|
||||||
@ -406,6 +373,17 @@ pub fn process_rewards_and_penalities(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crosslinks
|
||||||
|
|
||||||
|
if let Some(ref info) = status.winning_root_info {
|
||||||
|
safe_add_assign!(
|
||||||
|
balance,
|
||||||
|
base_reward * info.total_attesting_balance / info.total_committee_balance
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
safe_sub_assign!(balance, base_reward);
|
||||||
|
}
|
||||||
|
|
||||||
balance
|
balance
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -431,57 +409,6 @@ pub fn process_rewards_and_penalities(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Crosslinks
|
|
||||||
|
|
||||||
for slot in state.previous_epoch(spec).slot_iter(spec.slots_per_epoch) {
|
|
||||||
// Clone removes the borrow which becomes an issue when mutating `state.balances`.
|
|
||||||
let crosslink_committees_at_slot =
|
|
||||||
state.get_crosslink_committees_at_slot(slot, spec)?.clone();
|
|
||||||
|
|
||||||
for (crosslink_committee, shard) in crosslink_committees_at_slot {
|
|
||||||
let shard = shard as u64;
|
|
||||||
|
|
||||||
// Note: I'm a little uncertain of the logic here -- I am waiting for spec v0.5.0 to
|
|
||||||
// clear it up.
|
|
||||||
//
|
|
||||||
// What happens here is:
|
|
||||||
//
|
|
||||||
// - If there was some crosslink root elected by the super-majority of this committee,
|
|
||||||
// then we reward all who voted for that root and penalize all that did not.
|
|
||||||
// - However, if there _was not_ some super-majority-voted crosslink root, then penalize
|
|
||||||
// all the validators.
|
|
||||||
//
|
|
||||||
// I'm not quite sure that the second case (no super-majority crosslink) is correct.
|
|
||||||
if let Some(winning_root) = winning_root_for_shards.get(&shard) {
|
|
||||||
// Hash set de-dedups and (hopefully) offers a speed improvement from faster
|
|
||||||
// lookups.
|
|
||||||
let attesting_validator_indices: FnvHashSet<usize> =
|
|
||||||
FnvHashSet::from_iter(winning_root.attesting_validator_indices.iter().cloned());
|
|
||||||
|
|
||||||
for &index in &crosslink_committee {
|
|
||||||
let base_reward = state.base_reward(index, base_reward_quotient, spec);
|
|
||||||
|
|
||||||
let total_balance = state.get_total_balance(&crosslink_committee, spec);
|
|
||||||
|
|
||||||
if attesting_validator_indices.contains(&index) {
|
|
||||||
safe_add_assign!(
|
|
||||||
state.validator_balances[index],
|
|
||||||
base_reward * winning_root.total_attesting_balance / total_balance
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
safe_sub_assign!(state.validator_balances[index], base_reward);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for &index in &crosslink_committee {
|
|
||||||
let base_reward = state.base_reward(index, base_reward_quotient, spec);
|
|
||||||
|
|
||||||
safe_sub_assign!(state.validator_balances[index], base_reward);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::WinningRootHashSet;
|
||||||
use types::*;
|
use types::*;
|
||||||
|
|
||||||
macro_rules! set_self_if_other_is_true {
|
macro_rules! set_self_if_other_is_true {
|
||||||
@ -6,6 +7,12 @@ macro_rules! set_self_if_other_is_true {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct WinningRootInfo {
|
||||||
|
pub total_committee_balance: u64,
|
||||||
|
pub total_attesting_balance: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct InclusionInfo {
|
pub struct InclusionInfo {
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
@ -44,6 +51,7 @@ pub struct AttesterStatus {
|
|||||||
pub is_previous_epoch_head: bool,
|
pub is_previous_epoch_head: bool,
|
||||||
|
|
||||||
pub inclusion_info: InclusionInfo,
|
pub inclusion_info: InclusionInfo,
|
||||||
|
pub winning_root_info: Option<WinningRootInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttesterStatus {
|
impl AttesterStatus {
|
||||||
@ -70,6 +78,7 @@ pub struct TotalBalances {
|
|||||||
pub previous_epoch_head: u64,
|
pub previous_epoch_head: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Attesters {
|
pub struct Attesters {
|
||||||
pub statuses: Vec<AttesterStatus>,
|
pub statuses: Vec<AttesterStatus>,
|
||||||
pub balances: TotalBalances,
|
pub balances: TotalBalances,
|
||||||
@ -147,6 +156,38 @@ impl Attesters {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process_winning_roots(
|
||||||
|
&mut self,
|
||||||
|
state: &BeaconState,
|
||||||
|
winning_roots: &WinningRootHashSet,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> Result<(), BeaconStateError> {
|
||||||
|
// Loop through each slot in the previous epoch.
|
||||||
|
for slot in state.previous_epoch(spec).slot_iter(spec.slots_per_epoch) {
|
||||||
|
let crosslink_committees_at_slot =
|
||||||
|
state.get_crosslink_committees_at_slot(slot, spec)?;
|
||||||
|
|
||||||
|
// Loop through each committee in the slot.
|
||||||
|
for (crosslink_committee, shard) in crosslink_committees_at_slot {
|
||||||
|
// If there was some winning crosslink root for the committee's shard.
|
||||||
|
if let Some(winning_root) = winning_roots.get(&shard) {
|
||||||
|
let total_committee_balance =
|
||||||
|
state.get_total_balance(&crosslink_committee, spec);
|
||||||
|
for &validator_index in &winning_root.attesting_validator_indices {
|
||||||
|
// Take note of the balance information for the winning root, it will be
|
||||||
|
// used later to calculate rewards for that validator.
|
||||||
|
self.statuses[validator_index].winning_root_info = Some(WinningRootInfo {
|
||||||
|
total_committee_balance,
|
||||||
|
total_attesting_balance: winning_root.total_attesting_balance,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inclusion_distance(a: &PendingAttestation) -> Slot {
|
fn inclusion_distance(a: &PendingAttestation) -> Slot {
|
||||||
|
Loading…
Reference in New Issue
Block a user