mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-09 03:31:45 +00:00
Single-pass epoch processing and optimised block processing (#5279)
* Single-pass epoch processing (#4483, #4573) Co-authored-by: Michael Sproul <michael@sigmaprime.io> * Delete unused epoch processing code (#5170) * Delete unused epoch processing code * Compare total deltas * Remove unnecessary apply_pending * cargo fmt * Remove newline * Use epoch cache in block packing (#5223) * Remove progressive balances mode (#5224) * inline inactivity_penalty_quotient_for_state * drop previous_epoch_total_active_balance * fc lint * spec compliant process_sync_aggregate (#15) * spec compliant process_sync_aggregate * Update consensus/state_processing/src/per_block_processing/altair/sync_committee.rs Co-authored-by: Michael Sproul <micsproul@gmail.com> --------- Co-authored-by: Michael Sproul <micsproul@gmail.com> * Delete the participation cache (#16) * update help * Fix op_pool tests * Fix fork choice tests * Merge remote-tracking branch 'sigp/unstable' into epoch-single-pass * Simplify exit cache (#5280) * Fix clippy on exit cache * Clean up single-pass a bit (#5282) * Address Mark's review of single-pass (#5386) * Merge remote-tracking branch 'origin/unstable' into epoch-single-pass * Address Sean's review comments (#5414) * Address most of Sean's review comments * Simplify total balance cache building * Clean up unused junk * Merge remote-tracking branch 'origin/unstable' into epoch-single-pass * More self-review * Merge remote-tracking branch 'origin/unstable' into epoch-single-pass * Merge branch 'unstable' into epoch-single-pass * Fix imports for beta compiler * Fix tests, probably
This commit is contained in:
@@ -4,7 +4,9 @@ use crate::{signature_sets::sync_aggregate_signature_set, VerifySignatures};
|
||||
use safe_arith::SafeArith;
|
||||
use std::borrow::Cow;
|
||||
use types::consts::altair::{PROPOSER_WEIGHT, SYNC_REWARD_WEIGHT, WEIGHT_DENOMINATOR};
|
||||
use types::{BeaconState, ChainSpec, EthSpec, PublicKeyBytes, SyncAggregate, Unsigned};
|
||||
use types::{
|
||||
BeaconState, BeaconStateError, ChainSpec, EthSpec, PublicKeyBytes, SyncAggregate, Unsigned,
|
||||
};
|
||||
|
||||
pub fn process_sync_aggregate<E: EthSpec>(
|
||||
state: &mut BeaconState<E>,
|
||||
@@ -47,18 +49,34 @@ pub fn process_sync_aggregate<E: EthSpec>(
|
||||
// Apply participant and proposer rewards
|
||||
let committee_indices = state.get_sync_committee_indices(¤t_sync_committee)?;
|
||||
|
||||
let proposer_index = proposer_index as usize;
|
||||
let mut proposer_balance = *state
|
||||
.balances()
|
||||
.get(proposer_index)
|
||||
.ok_or(BeaconStateError::BalancesOutOfBounds(proposer_index))?;
|
||||
|
||||
for (participant_index, participation_bit) in committee_indices
|
||||
.into_iter()
|
||||
.zip(aggregate.sync_committee_bits.iter())
|
||||
{
|
||||
if participation_bit {
|
||||
increase_balance(state, participant_index, participant_reward)?;
|
||||
increase_balance(state, proposer_index as usize, proposer_reward)?;
|
||||
// Accumulate proposer rewards in a temp var in case the proposer has very low balance, is
|
||||
// part of the sync committee, does not participate and its penalties saturate.
|
||||
if participant_index == proposer_index {
|
||||
proposer_balance.safe_add_assign(participant_reward)?;
|
||||
} else {
|
||||
increase_balance(state, participant_index, participant_reward)?;
|
||||
}
|
||||
proposer_balance.safe_add_assign(proposer_reward)?;
|
||||
} else if participant_index == proposer_index {
|
||||
proposer_balance = proposer_balance.saturating_sub(participant_reward);
|
||||
} else {
|
||||
decrease_balance(state, participant_index, participant_reward)?;
|
||||
}
|
||||
}
|
||||
|
||||
*state.get_balance_mut(proposer_index)? = proposer_balance;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use super::signature_sets::Error as SignatureSetError;
|
||||
use crate::per_epoch_processing::altair::participation_cache;
|
||||
use crate::ContextError;
|
||||
use merkle_proof::MerkleTreeError;
|
||||
use participation_cache::Error as ParticipationCacheError;
|
||||
use safe_arith::ArithError;
|
||||
use ssz::DecodeError;
|
||||
use types::*;
|
||||
@@ -84,12 +82,12 @@ pub enum BlockProcessingError {
|
||||
},
|
||||
ExecutionInvalid,
|
||||
ConsensusContext(ContextError),
|
||||
EpochCacheError(EpochCacheError),
|
||||
WithdrawalsRootMismatch {
|
||||
expected: Hash256,
|
||||
found: Hash256,
|
||||
},
|
||||
WithdrawalCredentialsInvalid,
|
||||
ParticipationCacheError(ParticipationCacheError),
|
||||
}
|
||||
|
||||
impl From<BeaconStateError> for BlockProcessingError {
|
||||
@@ -134,6 +132,12 @@ impl From<ContextError> for BlockProcessingError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EpochCacheError> for BlockProcessingError {
|
||||
fn from(e: EpochCacheError) -> Self {
|
||||
BlockProcessingError::EpochCacheError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockOperationError<HeaderInvalid>> for BlockProcessingError {
|
||||
fn from(e: BlockOperationError<HeaderInvalid>) -> BlockProcessingError {
|
||||
match e {
|
||||
@@ -147,12 +151,6 @@ impl From<BlockOperationError<HeaderInvalid>> for BlockProcessingError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParticipationCacheError> for BlockProcessingError {
|
||||
fn from(e: ParticipationCacheError) -> Self {
|
||||
BlockProcessingError::ParticipationCacheError(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// A conversion that consumes `self` and adds an `index` variable to resulting struct.
|
||||
///
|
||||
/// Used here to allow converting an error into an upstream error that points to the object that
|
||||
@@ -328,9 +326,11 @@ pub enum AttestationInvalid {
|
||||
///
|
||||
/// `is_current` is `true` if the attestation was compared to the
|
||||
/// `state.current_justified_checkpoint`, `false` if compared to `state.previous_justified_checkpoint`.
|
||||
///
|
||||
/// Checkpoints have been boxed to keep the error size down and prevent clippy failures.
|
||||
WrongJustifiedCheckpoint {
|
||||
state: Checkpoint,
|
||||
attestation: Checkpoint,
|
||||
state: Box<Checkpoint>,
|
||||
attestation: Box<Checkpoint>,
|
||||
is_current: bool,
|
||||
},
|
||||
/// The aggregation bitfield length is not the smallest possible size to represent the committee.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use super::*;
|
||||
use crate::common::{
|
||||
altair::{get_base_reward, BaseRewardPerIncrement},
|
||||
get_attestation_participation_flag_indices, increase_balance, initiate_validator_exit,
|
||||
slash_validator,
|
||||
};
|
||||
@@ -54,8 +53,12 @@ pub mod base {
|
||||
ctxt: &mut ConsensusContext<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Ensure the previous epoch cache exists.
|
||||
// Ensure required caches are all built. These should be no-ops during regular operation.
|
||||
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
||||
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
||||
initialize_epoch_cache(state, spec)?;
|
||||
initialize_progressive_balances_cache(state, spec)?;
|
||||
state.build_slashings_cache()?;
|
||||
|
||||
let proposer_index = ctxt.get_proposer_index(state, spec)?;
|
||||
|
||||
@@ -97,7 +100,6 @@ pub mod base {
|
||||
pub mod altair_deneb {
|
||||
use super::*;
|
||||
use crate::common::update_progressive_balances_cache::update_progressive_balances_on_attestation;
|
||||
use types::consts::altair::TIMELY_TARGET_FLAG_INDEX;
|
||||
|
||||
pub fn process_attestations<E: EthSpec>(
|
||||
state: &mut BeaconState<E>,
|
||||
@@ -122,10 +124,9 @@ pub mod altair_deneb {
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
||||
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
||||
|
||||
let proposer_index = ctxt.get_proposer_index(state, spec)?;
|
||||
let previous_epoch = ctxt.previous_epoch;
|
||||
let current_epoch = ctxt.current_epoch;
|
||||
|
||||
let attesting_indices = &verify_attestation_for_block_inclusion(
|
||||
state,
|
||||
@@ -144,32 +145,36 @@ pub mod altair_deneb {
|
||||
get_attestation_participation_flag_indices(state, data, inclusion_delay, spec)?;
|
||||
|
||||
// Update epoch participation flags.
|
||||
let total_active_balance = state.get_total_active_balance()?;
|
||||
let base_reward_per_increment = BaseRewardPerIncrement::new(total_active_balance, spec)?;
|
||||
let mut proposer_reward_numerator = 0;
|
||||
for index in attesting_indices {
|
||||
let index = *index as usize;
|
||||
|
||||
let validator_effective_balance = state.epoch_cache().get_effective_balance(index)?;
|
||||
let validator_slashed = state.slashings_cache().is_slashed(index);
|
||||
|
||||
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))?;
|
||||
let epoch_participation = state.get_epoch_participation_mut(
|
||||
data.target.epoch,
|
||||
previous_epoch,
|
||||
current_epoch,
|
||||
)?;
|
||||
|
||||
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(
|
||||
get_base_reward(state, index, base_reward_per_increment, spec)?
|
||||
.safe_mul(weight)?,
|
||||
)?;
|
||||
if participation_flag_indices.contains(&flag_index) {
|
||||
let validator_participation = epoch_participation
|
||||
.get_mut(index)
|
||||
.ok_or(BeaconStateError::ParticipationOutOfBounds(index))?;
|
||||
|
||||
if !validator_participation.has_flag(flag_index)? {
|
||||
validator_participation.add_flag(flag_index)?;
|
||||
proposer_reward_numerator
|
||||
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
|
||||
|
||||
if flag_index == TIMELY_TARGET_FLAG_INDEX {
|
||||
update_progressive_balances_on_attestation(
|
||||
state,
|
||||
data.target.epoch,
|
||||
index,
|
||||
flag_index,
|
||||
validator_effective_balance,
|
||||
validator_slashed,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -197,6 +202,8 @@ pub fn process_proposer_slashings<E: EthSpec>(
|
||||
ctxt: &mut ConsensusContext<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
state.build_slashings_cache()?;
|
||||
|
||||
// Verify and apply proposer slashings in series.
|
||||
// We have to verify in series because an invalid block may contain multiple slashings
|
||||
// for the same validator, and we need to correctly detect and reject that.
|
||||
@@ -230,6 +237,8 @@ pub fn process_attester_slashings<E: EthSpec>(
|
||||
ctxt: &mut ConsensusContext<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
state.build_slashings_cache()?;
|
||||
|
||||
for (i, attester_slashing) in attester_slashings.iter().enumerate() {
|
||||
let slashable_indices =
|
||||
verify_attester_slashing(state, attester_slashing, verify_signatures, spec)
|
||||
|
||||
@@ -451,8 +451,8 @@ async fn invalid_attestation_wrong_justified_checkpoint() {
|
||||
Err(BlockProcessingError::AttestationInvalid {
|
||||
index: 0,
|
||||
reason: AttestationInvalid::WrongJustifiedCheckpoint {
|
||||
state: old_justified_checkpoint,
|
||||
attestation: new_justified_checkpoint,
|
||||
state: Box::new(old_justified_checkpoint),
|
||||
attestation: Box::new(new_justified_checkpoint),
|
||||
is_current: true,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -102,8 +102,8 @@ fn verify_casper_ffg_vote<E: EthSpec>(
|
||||
verify!(
|
||||
data.source == state.current_justified_checkpoint(),
|
||||
Invalid::WrongJustifiedCheckpoint {
|
||||
state: state.current_justified_checkpoint(),
|
||||
attestation: data.source,
|
||||
state: Box::new(state.current_justified_checkpoint()),
|
||||
attestation: Box::new(data.source),
|
||||
is_current: true,
|
||||
}
|
||||
);
|
||||
@@ -112,8 +112,8 @@ fn verify_casper_ffg_vote<E: EthSpec>(
|
||||
verify!(
|
||||
data.source == state.previous_justified_checkpoint(),
|
||||
Invalid::WrongJustifiedCheckpoint {
|
||||
state: state.previous_justified_checkpoint(),
|
||||
attestation: data.source,
|
||||
state: Box::new(state.previous_justified_checkpoint()),
|
||||
attestation: Box::new(data.source),
|
||||
is_current: false,
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user