diff --git a/core/src/accounts_hash_verifier.rs b/core/src/accounts_hash_verifier.rs index d75e0fd2ee..09aecc5203 100644 --- a/core/src/accounts_hash_verifier.rs +++ b/core/src/accounts_hash_verifier.rs @@ -9,7 +9,10 @@ use { solana_gossip::cluster_info::{ClusterInfo, MAX_SNAPSHOT_HASHES}, solana_measure::{measure::Measure, measure_us}, solana_runtime::{ - accounts_hash::{AccountsHashEnum, CalcAccountsHashConfig, HashStats}, + accounts_db::CalcAccountsHashFlavor, + accounts_hash::{ + AccountsHashEnum, CalcAccountsHashConfig, HashStats, IncrementalAccountsHash, + }, bank::BankIncrementalSnapshotPersistence, serde_snapshot::SerdeIncrementalAccountsHash, snapshot_config::SnapshotConfig, @@ -213,6 +216,22 @@ impl AccountsHashVerifier { /// returns calculated accounts hash fn calculate_and_verify_accounts_hash(accounts_package: &AccountsPackage) -> AccountsHashEnum { + let slot = accounts_package.slot; + let accounts_hash_calculation_flavor = match accounts_package.package_type { + AccountsPackageType::AccountsHashVerifier => CalcAccountsHashFlavor::Full, + AccountsPackageType::EpochAccountsHash => CalcAccountsHashFlavor::Full, + AccountsPackageType::Snapshot(snapshot_type) => match snapshot_type { + SnapshotType::FullSnapshot => CalcAccountsHashFlavor::Full, + SnapshotType::IncrementalSnapshot(_) => { + if accounts_package.is_incremental_accounts_hash_feature_enabled { + CalcAccountsHashFlavor::Incremental + } else { + CalcAccountsHashFlavor::Full + } + } + }, + }; + let mut measure_hash = Measure::start("hash"); let mut sort_time = Measure::start("sort_storages"); let sorted_storages = SortedStorages::new(&accounts_package.snapshot_storages); @@ -243,15 +262,28 @@ impl AccountsHashVerifier { ) .unwrap(); // unwrap here will never fail since check_hash = false - let old_accounts_hash = accounts_package - .accounts - .accounts_db - .set_accounts_hash(accounts_package.slot, (accounts_hash, lamports)); - if let Some(old_accounts_hash) = old_accounts_hash { - warn!( - "Accounts hash was already set for slot {}! old: {}, new: {}", - accounts_package.slot, &old_accounts_hash.0 .0, &accounts_hash.0 - ); + match accounts_hash_calculation_flavor { + CalcAccountsHashFlavor::Full => { + let old_accounts_hash = accounts_package + .accounts + .accounts_db + .set_accounts_hash(slot, (accounts_hash, lamports)); + if let Some(old_accounts_hash) = old_accounts_hash { + warn!("Accounts hash was already set for slot {slot}! old: {old_accounts_hash:?}, new: {accounts_hash:?}"); + } + } + CalcAccountsHashFlavor::Incremental => { + // Once we calculate incremental accounts hashes, we can use the calculation result + // directly. Until then, convert the full accounts hash into an incremental. + let incremental_accounts_hash = IncrementalAccountsHash(accounts_hash.0); + let old_incremental_accounts_hash = accounts_package + .accounts + .accounts_db + .set_incremental_accounts_hash(slot, (incremental_accounts_hash, lamports)); + if let Some(old_incremental_accounts_hash) = old_incremental_accounts_hash { + warn!("Incremental accounts hash was already set for slot {slot}! old: {old_incremental_accounts_hash:?}, new: {incremental_accounts_hash:?}"); + } + } } if accounts_package.expected_capitalization != lamports { @@ -265,14 +297,8 @@ impl AccountsHashVerifier { let result_with_index = accounts_package .accounts .accounts_db - .calculate_accounts_hash_from_index( - accounts_package.slot, - &calculate_accounts_hash_config, - ); - info!( - "hash calc with index: {}, {result_with_index:?}", - accounts_package.slot - ); + .calculate_accounts_hash_from_index(slot, &calculate_accounts_hash_config); + info!("hash calc with index: {slot}, {result_with_index:?}",); let calculate_accounts_hash_config = CalcAccountsHashConfig { // now that we've failed, store off the failing contents that produced a bad capitalization store_detailed_debug_info_on_failure: true, @@ -332,7 +358,7 @@ impl AccountsHashVerifier { if let Some(snapshot_info) = &accounts_package.snapshot_info { solana_runtime::serde_snapshot::reserialize_bank_with_new_accounts_hash( snapshot_info.snapshot_links.path(), - accounts_package.slot, + slot, &accounts_hash, bank_incremental_snapshot_persistence.as_ref(), ); @@ -344,7 +370,7 @@ impl AccountsHashVerifier { accounts_package .accounts .accounts_db - .purge_old_accounts_hashes(accounts_package.slot); + .purge_old_accounts_hashes(slot); } datapoint_info!( diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index bc93ea984c..67eddc542e 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -62,7 +62,7 @@ use { read_only_accounts_cache::ReadOnlyAccountsCache, rent_collector::RentCollector, rent_paying_accounts_by_partition::RentPayingAccountsByPartition, - serde_snapshot::{SerdeAccountsDeltaHash, SerdeAccountsHash}, + serde_snapshot::{SerdeAccountsDeltaHash, SerdeAccountsHash, SerdeIncrementalAccountsHash}, snapshot_utils::create_accounts_run_and_snapshot_dirs, sorted_storages::SortedStorages, storable_accounts::StorableAccounts, @@ -1416,9 +1416,11 @@ pub struct AccountsDb { pub thread_pool_clean: ThreadPool, + bank_hash_stats: Mutex>, accounts_delta_hashes: Mutex>, accounts_hashes: Mutex>, - bank_hash_stats: Mutex>, + incremental_accounts_hashes: + Mutex>, pub stats: AccountsStats, @@ -2422,9 +2424,10 @@ impl AccountsDb { .build() .unwrap(), thread_pool_clean: make_min_priority_thread_pool(), + bank_hash_stats: Mutex::new(bank_hash_stats), accounts_delta_hashes: Mutex::new(HashMap::new()), accounts_hashes: Mutex::new(HashMap::new()), - bank_hash_stats: Mutex::new(bank_hash_stats), + incremental_accounts_hashes: Mutex::new(HashMap::new()), external_purge_slots_stats: PurgeStats::default(), clean_accounts_stats: CleanAccountsStats::default(), shrink_stats: ShrinkStats::default(), @@ -7350,7 +7353,7 @@ impl AccountsDb { (accounts_hash, total_lamports) } - /// Set the accounts hash for `slot` in the `accounts_hashes` map + /// Set the accounts hash for `slot` /// /// returns the previous accounts hash for `slot` pub fn set_accounts_hash( @@ -7374,20 +7377,60 @@ impl AccountsDb { self.set_accounts_hash(slot, (accounts_hash.into(), capitalization)) } - /// Get the accounts hash for `slot` in the `accounts_hashes` map + /// Get the accounts hash for `slot` pub fn get_accounts_hash(&self, slot: Slot) -> Option<(AccountsHash, /*capitalization*/ u64)> { self.accounts_hashes.lock().unwrap().get(&slot).cloned() } + /// Set the incremental accounts hash for `slot` + /// + /// returns the previous incremental accounts hash for `slot` + pub fn set_incremental_accounts_hash( + &self, + slot: Slot, + incremental_accounts_hash: (IncrementalAccountsHash, /*capitalization*/ u64), + ) -> Option<(IncrementalAccountsHash, /*capitalization*/ u64)> { + self.incremental_accounts_hashes + .lock() + .unwrap() + .insert(slot, incremental_accounts_hash) + } + + /// After deserializing a snapshot, set the incremental accounts hash for the new AccountsDb + pub fn set_incremental_accounts_hash_from_snapshot( + &mut self, + slot: Slot, + incremental_accounts_hash: SerdeIncrementalAccountsHash, + capitalization: u64, + ) -> Option<(IncrementalAccountsHash, /*capitalization*/ u64)> { + self.set_incremental_accounts_hash(slot, (incremental_accounts_hash.into(), capitalization)) + } + + /// Get the incremental accounts hash for `slot` + pub fn get_incremental_accounts_hash( + &self, + slot: Slot, + ) -> Option<(IncrementalAccountsHash, /*capitalization*/ u64)> { + self.incremental_accounts_hashes + .lock() + .unwrap() + .get(&slot) + .cloned() + } + /// Purge accounts hashes that are older than `last_full_snapshot_slot` /// - /// Should only be called by AccountsHashVerifier, since it consumes `account_hashes` and knows - /// which ones are still needed. + /// Should only be called by AccountsHashVerifier, since it consumes the accounts hashes and + /// knows which ones are still needed. pub fn purge_old_accounts_hashes(&self, last_full_snapshot_slot: Slot) { self.accounts_hashes .lock() .unwrap() .retain(|&slot, _| slot >= last_full_snapshot_slot); + self.incremental_accounts_hashes + .lock() + .unwrap() + .retain(|&slot, _| slot >= last_full_snapshot_slot); } /// scan 'storages', return a vec of 'CacheHashDataFile', one per pass @@ -9322,8 +9365,8 @@ pub enum CalcAccountsHashDataSource { } /// Which accounts hash calculation is being performed? -#[derive(Debug)] -enum CalcAccountsHashFlavor { +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum CalcAccountsHashFlavor { Full, Incremental, }