Implement activation queue cache

This commit is contained in:
Michael Sproul
2023-07-03 12:03:14 +10:00
parent f631b515f6
commit b414c323f8
6 changed files with 95 additions and 17 deletions

View File

@@ -0,0 +1,38 @@
use crate::{ChainSpec, Epoch, Validator};
use std::collections::BTreeSet;
/// Activation queue computed during epoch processing for use in the *next* epoch.
#[derive(Debug, PartialEq, Eq, Default, Clone, arbitrary::Arbitrary)]
pub struct ActivationQueue {
/// Validators represented by `(activation_eligibility_epoch, index)` in sorted order.
queue: BTreeSet<(Epoch, usize)>,
}
impl ActivationQueue {
pub fn add_if_could_be_eligible_for_activation(
&mut self,
index: usize,
validator: &Validator,
next_epoch: Epoch,
spec: &ChainSpec,
) {
if validator.could_be_eligible_for_activation_at(next_epoch, spec) {
self.queue
.insert((validator.activation_eligibility_epoch(), index));
}
}
pub fn get_validators_eligible_for_activation(
&self,
finalized_epoch: Epoch,
churn_limit: usize,
) -> BTreeSet<usize> {
self.queue
.iter()
.filter_map(|&(eligibility_epoch, index)| {
(eligibility_epoch <= finalized_epoch).then_some(index)
})
.take(churn_limit)
.collect()
}
}

View File

@@ -1,4 +1,4 @@
use crate::{BeaconStateError, Epoch, EthSpec, Hash256, Slot};
use crate::{ActivationQueue, BeaconStateError, Epoch, EthSpec, Hash256, Slot};
use safe_arith::ArithError;
use std::sync::Arc;
@@ -20,6 +20,8 @@ struct Inner {
key: EpochCacheKey,
/// Base reward for every validator in this epoch.
base_rewards: Vec<u64>,
/// Validator activation queue.
activation_queue: ActivationQueue,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, arbitrary::Arbitrary)]
@@ -52,9 +54,17 @@ impl From<ArithError> for EpochCacheError {
}
impl EpochCache {
pub fn new(key: EpochCacheKey, base_rewards: Vec<u64>) -> EpochCache {
pub fn new(
key: EpochCacheKey,
base_rewards: Vec<u64>,
activation_queue: ActivationQueue,
) -> EpochCache {
Self {
inner: Some(Arc::new(Inner { key, base_rewards })),
inner: Some(Arc::new(Inner {
key,
base_rewards,
activation_queue,
})),
}
}
@@ -92,4 +102,12 @@ impl EpochCache {
.copied()
.ok_or(EpochCacheError::ValidatorIndexOutOfBounds { validator_index })
}
pub fn activation_queue(&self) -> Result<&ActivationQueue, EpochCacheError> {
let inner = self
.inner
.as_ref()
.ok_or(EpochCacheError::CacheNotInitialized)?;
Ok(&inner.activation_queue)
}
}

View File

@@ -73,6 +73,7 @@ pub mod validator_subscription;
pub mod voluntary_exit;
#[macro_use]
pub mod slot_epoch_macros;
pub mod activation_queue;
pub mod config_and_preset;
pub mod execution_block_header;
pub mod fork_context;
@@ -99,6 +100,7 @@ pub mod sqlite;
use ethereum_types::{H160, H256};
pub use crate::activation_queue::ActivationQueue;
pub use crate::aggregate_and_proof::AggregateAndProof;
pub use crate::attestation::{Attestation, Error as AttestationError};
pub use crate::attestation_data::AttestationData;

View File

@@ -159,10 +159,26 @@ impl Validator {
state: &BeaconState<E>,
spec: &ChainSpec,
) -> bool {
// Has not yet been activated
self.activation_epoch() == spec.far_future_epoch &&
// Placement in queue is finalized
self.activation_eligibility_epoch() <= state.finalized_checkpoint().epoch
}
/// Returns `true` if the validator *could* be eligible for activation at `epoch`.
///
/// Eligibility depends on finalization, so we assume best-possible finalization. This function
/// returning true is a necessary but *not sufficient* condition for a validator to activate in
/// the epoch transition at the end of `epoch`.
pub fn could_be_eligible_for_activation_at(&self, epoch: Epoch, spec: &ChainSpec) -> bool {
// Has not yet been activated
&& self.activation_epoch() == spec.far_future_epoch
self.activation_epoch() == spec.far_future_epoch
// Placement in queue could be finalized.
//
// NOTE: it's +1 rather than +2 because we consider the activations that occur at the *end*
// of `epoch`, after `process_justification_and_finalization` has already updated the
// state's checkpoint.
&& self.activation_eligibility_epoch() + 1 <= epoch
}
fn tree_hash_root_internal(&self) -> Result<Hash256, tree_hash::Error> {