More progress

This commit is contained in:
dapplion
2025-04-04 03:02:01 -03:00
parent 63a4e378ce
commit 614c01698d
20 changed files with 464 additions and 91 deletions

View File

@@ -141,6 +141,7 @@ pub const BEACON_CHAIN_DB_KEY: Hash256 = Hash256::ZERO;
pub const OP_POOL_DB_KEY: Hash256 = Hash256::ZERO;
pub const ETH1_CACHE_DB_KEY: Hash256 = Hash256::ZERO;
pub const FORK_CHOICE_DB_KEY: Hash256 = Hash256::ZERO;
pub const LOCAL_INDICES_DB_KEY: Hash256 = Hash256::ZERO;
/// Defines how old a block can be before it's no longer a candidate for the early attester cache.
const EARLY_ATTESTER_CACHE_HISTORIC_SLOTS: u64 = 4;
@@ -712,6 +713,17 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Ok(())
}
pub fn persist_local_indices(&self) -> Result<(), Error> {
let persisted_local_validators = self
.validator_monitor
.read()
.to_persisted_local_validators()?;
self.store
.put_item(&LOCAL_INDICES_DB_KEY, &persisted_local_validators)?;
Ok(())
}
/// Returns the slot _right now_ according to `self.slot_clock`. Returns `Err` if the slot is
/// unavailable.
///
@@ -7151,6 +7163,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
)
}
/// Register a local validator that has connected to the Beacon REST API
pub fn register_local_validator(&self, validator_index: u64) {
// TODO(das): persist `last_seen_local_validators` to disk on shutdown and once in a while
self.validator_monitor
.write()
.auto_register_local_validator(validator_index);
}
pub fn metrics(&self) -> BeaconChainMetrics {
BeaconChainMetrics {
reqresp_pre_import_cache_len: self.reqresp_pre_import_cache.read().len(),
@@ -7210,7 +7230,8 @@ impl<T: BeaconChainTypes> Drop for BeaconChain<T> {
let drop = || -> Result<(), Error> {
self.persist_head_and_fork_choice()?;
self.persist_op_pool()?;
self.persist_eth1_cache()
self.persist_eth1_cache()?;
self.persist_local_indices()
};
if let Err(e) = drop() {

View File

@@ -1,5 +1,6 @@
use crate::beacon_chain::{
CanonicalHead, LightClientProducerEvent, BEACON_CHAIN_DB_KEY, ETH1_CACHE_DB_KEY, OP_POOL_DB_KEY,
CanonicalHead, LightClientProducerEvent, BEACON_CHAIN_DB_KEY, ETH1_CACHE_DB_KEY,
LOCAL_INDICES_DB_KEY, OP_POOL_DB_KEY,
};
use crate::beacon_proposer_cache::BeaconProposerCache;
use crate::data_availability_checker::DataAvailabilityChecker;
@@ -15,7 +16,7 @@ use crate::migrate::{BackgroundMigrator, MigratorConfig};
use crate::observed_data_sidecars::ObservedDataSidecars;
use crate::persisted_beacon_chain::PersistedBeaconChain;
use crate::shuffling_cache::{BlockShufflingIds, ShufflingCache};
use crate::validator_monitor::{ValidatorMonitor, ValidatorMonitorConfig};
use crate::validator_monitor::{PersistedLocalIndices, ValidatorMonitor, ValidatorMonitorConfig};
use crate::validator_pubkey_cache::ValidatorPubkeyCache;
use crate::ChainConfig;
use crate::{
@@ -732,8 +733,16 @@ where
let head_tracker = Arc::new(self.head_tracker.unwrap_or_default());
let beacon_proposer_cache: Arc<Mutex<BeaconProposerCache>> = <_>::default();
let mut validator_monitor =
ValidatorMonitor::new(validator_monitor_config, beacon_proposer_cache.clone());
let persisted_local_indices = store
.get_item::<PersistedLocalIndices>(&LOCAL_INDICES_DB_KEY)
.map_err(|e| format!("DB error whilst reading persisted local indices: {e:?}"))?
.unwrap_or_default();
let mut validator_monitor = ValidatorMonitor::new(
validator_monitor_config,
beacon_proposer_cache.clone(),
persisted_local_indices,
);
let current_slot = if slot_clock
.is_prior_to_genesis()

View File

@@ -10,6 +10,8 @@ use parking_lot::{Mutex, RwLock};
use serde::{Deserialize, Serialize};
use slot_clock::SlotClock;
use smallvec::SmallVec;
use ssz::{Decode, Encode};
use ssz_derive::{Decode, Encode};
use state_processing::common::get_attestation_participation_flag_indices;
use state_processing::per_epoch_processing::{
errors::EpochProcessingError, EpochProcessingSummary,
@@ -20,16 +22,17 @@ use std::marker::PhantomData;
use std::str::Utf8Error;
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use store::AbstractExecPayload;
use store::{AbstractExecPayload, DBColumn, Error as StoreError, StoreItem};
use tracing::{debug, error, info, instrument, warn};
use types::consts::altair::{
TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX,
};
use types::typenum::U524288;
use types::{
Attestation, AttestationData, AttesterSlashingRef, BeaconBlockRef, BeaconState,
BeaconStateError, ChainSpec, Epoch, EthSpec, Hash256, IndexedAttestation,
IndexedAttestationRef, ProposerSlashing, PublicKeyBytes, SignedAggregateAndProof,
SignedContributionAndProof, Slot, SyncCommitteeMessage, VoluntaryExit,
SignedContributionAndProof, Slot, SyncCommitteeMessage, VariableList, VoluntaryExit,
};
/// Used for Prometheus labels.
///
@@ -388,6 +391,9 @@ pub struct ValidatorMonitor<E: EthSpec> {
validators: HashMap<PublicKeyBytes, MonitoredValidator>,
/// A map of validator index (state.validators) to a validator public key.
indices: HashMap<u64, PublicKeyBytes>,
/// Additional map to indices that bypasses `auto_register` config and tracks the time a
/// validator was last seen as a UNIX timestamp
last_seen_local_validators: HashMap<u64, Duration>,
/// If true, allow the automatic registration of validators.
auto_register: bool,
/// Once the number of monitored validators goes above this threshold, we
@@ -413,6 +419,7 @@ impl<E: EthSpec> ValidatorMonitor<E> {
pub fn new(
config: ValidatorMonitorConfig,
beacon_proposer_cache: Arc<Mutex<BeaconProposerCache>>,
persisted_local_indices: PersistedLocalIndices,
) -> Self {
let ValidatorMonitorConfig {
auto_register,
@@ -423,6 +430,12 @@ impl<E: EthSpec> ValidatorMonitor<E> {
let mut s = Self {
validators: <_>::default(),
indices: <_>::default(),
last_seen_local_validators: HashMap::from_iter(
persisted_local_indices
.indices
.iter()
.map(|e| (e.index, Duration::from_secs(e.last_seen_timestamp_sec))),
),
auto_register,
individual_tracking_threshold,
missed_blocks: <_>::default(),
@@ -449,6 +462,34 @@ impl<E: EthSpec> ValidatorMonitor<E> {
self.validators.len() <= self.individual_tracking_threshold
}
/// Prunes all validators not seen for longer than `ttl` (time to live)
pub fn prune_registered_local_validators(&mut self, ttl: Duration) {
let now = timestamp_now();
// Prune expired keys
self.last_seen_local_validators
.retain(|_, last_seen| now - *last_seen < ttl);
}
/// Returns an iterator over registered local validators indices
pub fn get_registered_local_validators(&self) -> impl Iterator<Item = &u64> {
self.last_seen_local_validators.keys()
}
/// Returns local indices to persist to the DB
pub fn to_persisted_local_validators(&self) -> Result<PersistedLocalIndices, ssz_types::Error> {
Ok(PersistedLocalIndices {
indices: VariableList::new(
self.last_seen_local_validators
.iter()
.map(|(index, last_seen)| PersistedLocalIndex {
index: *index,
last_seen_timestamp_sec: last_seen.as_secs(),
})
.collect::<Vec<_>>(),
)?,
})
}
/// Add some validators to `self` for additional monitoring.
#[instrument(parent = None,
level = "info",
@@ -1198,6 +1239,9 @@ impl<E: EthSpec> ValidatorMonitor<E> {
skip_all
)]
pub fn auto_register_local_validator(&mut self, validator_index: u64) {
self.last_seen_local_validators
.insert(validator_index, timestamp_now());
if !self.auto_register {
return;
}
@@ -2404,3 +2448,29 @@ fn min_opt<T: Ord>(a: Option<T>, b: Option<T>) -> Option<T> {
_ => None,
}
}
// Using 524288 as a really high limit that's never meant to be reached
#[derive(Encode, Decode, Default)]
pub struct PersistedLocalIndices {
indices: VariableList<PersistedLocalIndex, U524288>,
}
#[derive(Encode, Decode)]
pub struct PersistedLocalIndex {
index: u64,
last_seen_timestamp_sec: u64,
}
impl StoreItem for PersistedLocalIndices {
fn db_column() -> DBColumn {
DBColumn::LocalIndices
}
fn as_store_bytes(&self) -> Vec<u8> {
self.as_ssz_bytes()
}
fn from_store_bytes(bytes: &[u8]) -> Result<Self, StoreError> {
Self::from_ssz_bytes(bytes).map_err(Into::into)
}
}