From a6d737d773b85c8bd252948d2123394f474af055 Mon Sep 17 00:00:00 2001 From: Brooks Prumo Date: Thu, 1 Sep 2022 12:11:07 -0400 Subject: [PATCH] Add EpochAccountsHash to AccountsDb (#27538) --- runtime/src/accounts_db.rs | 6 ++++ runtime/src/epoch_accounts_hash.rs | 58 ++++++++++++++++++++++++++++++ runtime/src/lib.rs | 1 + 3 files changed, 65 insertions(+) create mode 100644 runtime/src/epoch_accounts_hash.rs diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index 7ac56c1272..0cd4b1392e 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -45,6 +45,7 @@ use { bank::Rewrites, cache_hash_data::CacheHashData, contains::Contains, + epoch_accounts_hash::EpochAccountsHash, expected_rent_collection::{ExpectedRentCollection, SlotInfoInEpoch}, pubkey_bins::PubkeyBinCalculator24, read_only_accounts_cache::ReadOnlyAccountsCache, @@ -1182,6 +1183,10 @@ pub struct AccountsDb { /// Used to disable logging dead slots during removal. /// allow disabling noisy log pub(crate) log_dead_slots: AtomicBool, + + /// A special accounts hash that occurs once per epoch + #[allow(dead_code)] + pub(crate) epoch_accounts_hash: Mutex>, } #[derive(Debug, Default)] @@ -1979,6 +1984,7 @@ impl AccountsDb { filler_account_suffix: None, num_hash_scan_passes, log_dead_slots: AtomicBool::new(true), + epoch_accounts_hash: Mutex::new(None), } } diff --git a/runtime/src/epoch_accounts_hash.rs b/runtime/src/epoch_accounts_hash.rs new file mode 100644 index 0000000000..48c55c4301 --- /dev/null +++ b/runtime/src/epoch_accounts_hash.rs @@ -0,0 +1,58 @@ +//! The Epoch Accounts Hash (EAH) is a special hash of the whole accounts state that occurs once +//! per epoch. +//! +//! This hash is special because all nodes in the cluster will calculate the accounts hash at a +//! predetermined slot in the epoch and then save that result into a later Bank at a predetermined +//! slot. +//! +//! This results in all nodes effectively voting on the accounts state (at least) once per epoch. + +use { + crate::bank::Bank, + serde::{Deserialize, Serialize}, + solana_sdk::{clock::Slot, hash::Hash}, +}; + +/// The EpochAccountsHash holds the result after calculating the accounts hash once per epoch +#[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Copy)] +pub struct EpochAccountsHash(Hash); + +impl AsRef for EpochAccountsHash { + fn as_ref(&self) -> &Hash { + &self.0 + } +} + +/// Calculation of the EAH occurs once per epoch. All nodes in the cluster must agree on which +/// slot the EAH is based on. This slot will be at an offset into the epoch, and referred to as +/// the "start" slot for the EAH calculation. +#[must_use] +#[allow(dead_code)] +pub fn calculation_offset_start(bank: &Bank) -> Slot { + let slots_per_epoch = bank.epoch_schedule().slots_per_epoch; + slots_per_epoch / 4 +} + +/// Calculation of the EAH occurs once per epoch. All nodes in the cluster must agree on which +/// bank will hash the EAH into its `Bank::hash`. This slot will be at an offset into the epoch, +/// and referred to as the "stop" slot for the EAH calculation. All nodes must complete the EAH +/// calculation before this slot! +#[must_use] +#[allow(dead_code)] +pub fn calculation_offset_stop(bank: &Bank) -> Slot { + let slots_per_epoch = bank.epoch_schedule().slots_per_epoch; + slots_per_epoch / 4 * 3 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_calculation_offset_bounds() { + let bank = Bank::default_for_tests(); + let start = calculation_offset_start(&bank); + let stop = calculation_offset_stop(&bank); + assert!(start < stop); + } +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 15cc059f9a..247df17fe1 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -34,6 +34,7 @@ pub mod commitment; pub mod contains; pub mod cost_model; pub mod cost_tracker; +mod epoch_accounts_hash; pub mod epoch_stakes; pub mod execute_cost_table; mod expected_rent_collection;