mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-17 03:42:46 +00:00
Merge branch 'deneb-free-blobs' of https://github.com/sigp/lighthouse into refactor-deneb-networking
This commit is contained in:
@@ -3,7 +3,8 @@ use eth2::lighthouse::attestation_rewards::{IdealAttestationRewards, TotalAttest
|
||||
use eth2::lighthouse::StandardAttestationRewards;
|
||||
use participation_cache::ParticipationCache;
|
||||
use safe_arith::SafeArith;
|
||||
use slog::{debug, Logger};
|
||||
use serde_utils::quoted_u64::Quoted;
|
||||
use slog::debug;
|
||||
use state_processing::{
|
||||
common::altair::BaseRewardPerIncrement,
|
||||
per_epoch_processing::altair::{participation_cache, rewards_and_penalties::get_flag_weight},
|
||||
@@ -15,32 +16,112 @@ use store::consts::altair::{
|
||||
};
|
||||
use types::consts::altair::WEIGHT_DENOMINATOR;
|
||||
|
||||
use types::{Epoch, EthSpec};
|
||||
use types::{BeaconState, Epoch, EthSpec};
|
||||
|
||||
use eth2::types::ValidatorId;
|
||||
use state_processing::common::base::get_base_reward_from_effective_balance;
|
||||
use state_processing::per_epoch_processing::base::rewards_and_penalties::{
|
||||
get_attestation_component_delta, get_attestation_deltas_all, get_attestation_deltas_subset,
|
||||
get_inactivity_penalty_delta, get_inclusion_delay_delta,
|
||||
};
|
||||
use state_processing::per_epoch_processing::base::validator_statuses::InclusionInfo;
|
||||
use state_processing::per_epoch_processing::base::{
|
||||
TotalBalances, ValidatorStatus, ValidatorStatuses,
|
||||
};
|
||||
|
||||
impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn compute_attestation_rewards(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
validators: Vec<ValidatorId>,
|
||||
log: Logger,
|
||||
) -> Result<StandardAttestationRewards, BeaconChainError> {
|
||||
debug!(log, "computing attestation rewards"; "epoch" => epoch, "validator_count" => validators.len());
|
||||
debug!(self.log, "computing attestation rewards"; "epoch" => epoch, "validator_count" => validators.len());
|
||||
|
||||
// Get state
|
||||
let spec = &self.spec;
|
||||
|
||||
let state_slot = (epoch + 1).end_slot(T::EthSpec::slots_per_epoch());
|
||||
|
||||
let state_root = self
|
||||
.state_root_at_slot(state_slot)?
|
||||
.ok_or(BeaconChainError::NoStateForSlot(state_slot))?;
|
||||
|
||||
let mut state = self
|
||||
let state = self
|
||||
.get_state(&state_root, Some(state_slot))?
|
||||
.ok_or(BeaconChainError::MissingBeaconState(state_root))?;
|
||||
|
||||
match state {
|
||||
BeaconState::Base(_) => self.compute_attestation_rewards_base(state, validators),
|
||||
BeaconState::Altair(_)
|
||||
| BeaconState::Merge(_)
|
||||
| BeaconState::Capella(_)
|
||||
| BeaconState::Deneb(_) => self.compute_attestation_rewards_altair(state, validators),
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_attestation_rewards_base(
|
||||
&self,
|
||||
mut state: BeaconState<T::EthSpec>,
|
||||
validators: Vec<ValidatorId>,
|
||||
) -> Result<StandardAttestationRewards, BeaconChainError> {
|
||||
let spec = &self.spec;
|
||||
let mut validator_statuses = ValidatorStatuses::new(&state, spec)?;
|
||||
validator_statuses.process_attestations(&state)?;
|
||||
|
||||
let ideal_rewards =
|
||||
self.compute_ideal_rewards_base(&state, &validator_statuses.total_balances)?;
|
||||
|
||||
let indices_to_attestation_delta = if validators.is_empty() {
|
||||
get_attestation_deltas_all(&state, &validator_statuses, spec)?
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.collect()
|
||||
} else {
|
||||
let validator_indices = Self::validators_ids_to_indices(&mut state, validators)?;
|
||||
get_attestation_deltas_subset(&state, &validator_statuses, &validator_indices, spec)?
|
||||
};
|
||||
|
||||
let mut total_rewards = vec![];
|
||||
|
||||
for (index, delta) in indices_to_attestation_delta.into_iter() {
|
||||
let head_delta = delta.head_delta;
|
||||
let head = (head_delta.rewards as i64).safe_sub(head_delta.penalties as i64)?;
|
||||
|
||||
let target_delta = delta.target_delta;
|
||||
let target = (target_delta.rewards as i64).safe_sub(target_delta.penalties as i64)?;
|
||||
|
||||
let source_delta = delta.source_delta;
|
||||
let source = (source_delta.rewards as i64).safe_sub(source_delta.penalties as i64)?;
|
||||
|
||||
// No penalties associated with inclusion delay
|
||||
let inclusion_delay = delta.inclusion_delay_delta.rewards;
|
||||
let inactivity = delta.inactivity_penalty_delta.penalties.wrapping_neg() as i64;
|
||||
|
||||
let rewards = TotalAttestationRewards {
|
||||
validator_index: index as u64,
|
||||
head,
|
||||
target,
|
||||
source,
|
||||
inclusion_delay: Some(Quoted {
|
||||
value: inclusion_delay,
|
||||
}),
|
||||
inactivity,
|
||||
};
|
||||
|
||||
total_rewards.push(rewards);
|
||||
}
|
||||
|
||||
Ok(StandardAttestationRewards {
|
||||
ideal_rewards,
|
||||
total_rewards,
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_attestation_rewards_altair(
|
||||
&self,
|
||||
mut state: BeaconState<T::EthSpec>,
|
||||
validators: Vec<ValidatorId>,
|
||||
) -> Result<StandardAttestationRewards, BeaconChainError> {
|
||||
let spec = &self.spec;
|
||||
|
||||
// Calculate ideal_rewards
|
||||
let participation_cache = ParticipationCache::new(&state, spec)?;
|
||||
|
||||
@@ -71,7 +152,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let base_reward_per_increment =
|
||||
BaseRewardPerIncrement::new(total_active_balance, spec)?;
|
||||
|
||||
for effective_balance_eth in 0..=32 {
|
||||
for effective_balance_eth in 1..=self.max_effective_balance_increment_steps()? {
|
||||
let effective_balance =
|
||||
effective_balance_eth.safe_mul(spec.effective_balance_increment)?;
|
||||
let base_reward =
|
||||
@@ -101,20 +182,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let validators = if validators.is_empty() {
|
||||
participation_cache.eligible_validator_indices().to_vec()
|
||||
} else {
|
||||
validators
|
||||
.into_iter()
|
||||
.map(|validator| match validator {
|
||||
ValidatorId::Index(i) => Ok(i as usize),
|
||||
ValidatorId::PublicKey(pubkey) => state
|
||||
.get_validator_index(&pubkey)?
|
||||
.ok_or(BeaconChainError::ValidatorPubkeyUnknown(pubkey)),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
Self::validators_ids_to_indices(&mut state, validators)?
|
||||
};
|
||||
|
||||
for validator_index in &validators {
|
||||
let eligible = state.is_eligible_validator(previous_epoch, *validator_index)?;
|
||||
let mut head_reward = 0u64;
|
||||
let mut head_reward = 0i64;
|
||||
let mut target_reward = 0i64;
|
||||
let mut source_reward = 0i64;
|
||||
|
||||
@@ -132,7 +205,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
|
||||
if voted_correctly {
|
||||
if flag_index == TIMELY_HEAD_FLAG_INDEX {
|
||||
head_reward += ideal_reward;
|
||||
head_reward += *ideal_reward as i64;
|
||||
} else if flag_index == TIMELY_TARGET_FLAG_INDEX {
|
||||
target_reward += *ideal_reward as i64;
|
||||
} else if flag_index == TIMELY_SOURCE_FLAG_INDEX {
|
||||
@@ -152,6 +225,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
head: head_reward,
|
||||
target: target_reward,
|
||||
source: source_reward,
|
||||
inclusion_delay: None,
|
||||
// TODO: altair calculation logic needs to be updated to include inactivity penalty
|
||||
inactivity: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -173,6 +249,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
head: 0,
|
||||
target: 0,
|
||||
source: 0,
|
||||
inclusion_delay: None,
|
||||
// TODO: altair calculation logic needs to be updated to include inactivity penalty
|
||||
inactivity: 0,
|
||||
});
|
||||
match *flag_index {
|
||||
TIMELY_SOURCE_FLAG_INDEX => entry.source += ideal_reward,
|
||||
@@ -192,4 +271,126 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
total_rewards,
|
||||
})
|
||||
}
|
||||
|
||||
fn max_effective_balance_increment_steps(&self) -> Result<u64, BeaconChainError> {
|
||||
let spec = &self.spec;
|
||||
let max_steps = spec
|
||||
.max_effective_balance
|
||||
.safe_div(spec.effective_balance_increment)?;
|
||||
Ok(max_steps)
|
||||
}
|
||||
|
||||
fn validators_ids_to_indices(
|
||||
state: &mut BeaconState<T::EthSpec>,
|
||||
validators: Vec<ValidatorId>,
|
||||
) -> Result<Vec<usize>, BeaconChainError> {
|
||||
let indices = validators
|
||||
.into_iter()
|
||||
.map(|validator| match validator {
|
||||
ValidatorId::Index(i) => Ok(i as usize),
|
||||
ValidatorId::PublicKey(pubkey) => state
|
||||
.get_validator_index(&pubkey)?
|
||||
.ok_or(BeaconChainError::ValidatorPubkeyUnknown(pubkey)),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(indices)
|
||||
}
|
||||
|
||||
fn compute_ideal_rewards_base(
|
||||
&self,
|
||||
state: &BeaconState<T::EthSpec>,
|
||||
total_balances: &TotalBalances,
|
||||
) -> Result<Vec<IdealAttestationRewards>, BeaconChainError> {
|
||||
let spec = &self.spec;
|
||||
let previous_epoch = state.previous_epoch();
|
||||
let finality_delay = previous_epoch
|
||||
.safe_sub(state.finalized_checkpoint().epoch)?
|
||||
.as_u64();
|
||||
|
||||
let ideal_validator_status = ValidatorStatus {
|
||||
is_previous_epoch_attester: true,
|
||||
is_slashed: false,
|
||||
inclusion_info: Some(InclusionInfo {
|
||||
delay: 1,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut ideal_attestation_rewards_list = Vec::new();
|
||||
|
||||
for effective_balance_step in 1..=self.max_effective_balance_increment_steps()? {
|
||||
let effective_balance =
|
||||
effective_balance_step.safe_mul(spec.effective_balance_increment)?;
|
||||
let base_reward = get_base_reward_from_effective_balance::<T::EthSpec>(
|
||||
effective_balance,
|
||||
total_balances.current_epoch(),
|
||||
spec,
|
||||
)?;
|
||||
|
||||
// compute ideal head rewards
|
||||
let head = get_attestation_component_delta(
|
||||
true,
|
||||
total_balances.previous_epoch_attesters(),
|
||||
total_balances,
|
||||
base_reward,
|
||||
finality_delay,
|
||||
spec,
|
||||
)?
|
||||
.rewards;
|
||||
|
||||
// compute ideal target rewards
|
||||
let target = get_attestation_component_delta(
|
||||
true,
|
||||
total_balances.previous_epoch_target_attesters(),
|
||||
total_balances,
|
||||
base_reward,
|
||||
finality_delay,
|
||||
spec,
|
||||
)?
|
||||
.rewards;
|
||||
|
||||
// compute ideal source rewards
|
||||
let source = get_attestation_component_delta(
|
||||
true,
|
||||
total_balances.previous_epoch_head_attesters(),
|
||||
total_balances,
|
||||
base_reward,
|
||||
finality_delay,
|
||||
spec,
|
||||
)?
|
||||
.rewards;
|
||||
|
||||
// compute ideal inclusion delay rewards
|
||||
let inclusion_delay =
|
||||
get_inclusion_delay_delta(&ideal_validator_status, base_reward, spec)?
|
||||
.0
|
||||
.rewards;
|
||||
|
||||
// compute inactivity penalty
|
||||
let inactivity = get_inactivity_penalty_delta(
|
||||
&ideal_validator_status,
|
||||
base_reward,
|
||||
finality_delay,
|
||||
spec,
|
||||
)?
|
||||
.penalties
|
||||
.wrapping_neg() as i64;
|
||||
|
||||
let ideal_attestation_rewards = IdealAttestationRewards {
|
||||
effective_balance,
|
||||
head,
|
||||
target,
|
||||
source,
|
||||
inclusion_delay: Some(Quoted {
|
||||
value: inclusion_delay,
|
||||
}),
|
||||
inactivity,
|
||||
};
|
||||
|
||||
ideal_attestation_rewards_list.push(ideal_attestation_rewards);
|
||||
}
|
||||
|
||||
Ok(ideal_attestation_rewards_list)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,7 +850,6 @@ impl ssz::Decode for OverflowKey {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use crate::{
|
||||
blob_verification::{
|
||||
validate_blob_sidecar_for_gossip, verify_kzg_for_blob, GossipVerifiedBlob,
|
||||
@@ -859,31 +858,20 @@ mod test {
|
||||
eth1_finalization_cache::Eth1FinalizationData,
|
||||
test_utils::{BaseHarnessType, BeaconChainHarness, DiskHarnessType},
|
||||
};
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use execution_layer::test_utils::DEFAULT_TERMINAL_BLOCK;
|
||||
use fork_choice::PayloadVerificationStatus;
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use logging::test_logger;
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use slog::{info, Logger};
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use state_processing::ConsensusContext;
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use std::collections::{BTreeMap, HashMap, VecDeque};
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use std::ops::AddAssign;
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use store::{HotColdDB, ItemStore, LevelDB, StoreConfig};
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use tempfile::{tempdir, TempDir};
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use types::beacon_state::ssz_tagged_beacon_state;
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
use types::{ChainSpec, ExecPayload, MinimalEthSpec};
|
||||
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
const LOW_VALIDATOR_COUNT: usize = 32;
|
||||
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
fn get_store_with_spec<E: EthSpec>(
|
||||
db_path: &TempDir,
|
||||
spec: ChainSpec,
|
||||
@@ -906,7 +894,6 @@ mod test {
|
||||
}
|
||||
|
||||
// get a beacon chain harness advanced to just before deneb fork
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn get_deneb_chain<E: EthSpec>(
|
||||
log: Logger,
|
||||
db_path: &TempDir,
|
||||
@@ -994,7 +981,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn ssz_tagged_beacon_state_encode_decode_equality() {
|
||||
type E = MinimalEthSpec;
|
||||
let altair_fork_epoch = Epoch::new(1);
|
||||
@@ -1011,6 +997,13 @@ mod test {
|
||||
spec.bellatrix_fork_epoch = Some(bellatrix_fork_epoch);
|
||||
spec.capella_fork_epoch = Some(capella_fork_epoch);
|
||||
spec.deneb_fork_epoch = Some(deneb_fork_epoch);
|
||||
let genesis_block = execution_layer::test_utils::generate_genesis_block(
|
||||
spec.terminal_total_difficulty,
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
)
|
||||
.unwrap();
|
||||
spec.terminal_block_hash = genesis_block.block_hash;
|
||||
spec.terminal_block_hash_activation_epoch = bellatrix_fork_epoch;
|
||||
|
||||
let harness = BeaconChainHarness::builder(E::default())
|
||||
.spec(spec)
|
||||
@@ -1069,7 +1062,6 @@ mod test {
|
||||
assert_eq!(state, decoded, "Encoded and decoded states should be equal");
|
||||
}
|
||||
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn availability_pending_block<E, Hot, Cold>(
|
||||
harness: &BeaconChainHarness<BaseHarnessType<E, Hot, Cold>>,
|
||||
log: Logger,
|
||||
@@ -1162,7 +1154,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn overflow_cache_test_insert_components() {
|
||||
type E = MinimalEthSpec;
|
||||
type T = DiskHarnessType<E>;
|
||||
@@ -1283,7 +1274,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn overflow_cache_test_overflow() {
|
||||
type E = MinimalEthSpec;
|
||||
type T = DiskHarnessType<E>;
|
||||
@@ -1443,7 +1433,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn overflow_cache_test_maintenance() {
|
||||
type E = MinimalEthSpec;
|
||||
type T = DiskHarnessType<E>;
|
||||
@@ -1595,7 +1584,6 @@ mod test {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg(feature = "spec-minimal")]
|
||||
async fn overflow_cache_test_persist_recover() {
|
||||
type E = MinimalEthSpec;
|
||||
type T = DiskHarnessType<E>;
|
||||
|
||||
@@ -26,7 +26,7 @@ use state_processing::{
|
||||
},
|
||||
signature_sets::Error as SignatureSetError,
|
||||
state_advance::Error as StateAdvanceError,
|
||||
BlockProcessingError, BlockReplayError, SlotProcessingError,
|
||||
BlockProcessingError, BlockReplayError, EpochProcessingError, SlotProcessingError,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use task_executor::ShutdownReason;
|
||||
@@ -62,6 +62,7 @@ pub enum BeaconChainError {
|
||||
MissingBeaconBlock(Hash256),
|
||||
MissingBeaconState(Hash256),
|
||||
SlotProcessingError(SlotProcessingError),
|
||||
EpochProcessingError(EpochProcessingError),
|
||||
StateAdvanceError(StateAdvanceError),
|
||||
UnableToAdvanceState(String),
|
||||
NoStateForAttestation {
|
||||
@@ -221,6 +222,7 @@ pub enum BeaconChainError {
|
||||
}
|
||||
|
||||
easy_from_to!(SlotProcessingError, BeaconChainError);
|
||||
easy_from_to!(EpochProcessingError, BeaconChainError);
|
||||
easy_from_to!(AttestationValidationError, BeaconChainError);
|
||||
easy_from_to!(SyncCommitteeMessageValidationError, BeaconChainError);
|
||||
easy_from_to!(ExitValidationError, BeaconChainError);
|
||||
|
||||
Reference in New Issue
Block a user