Skip to content

Commit

Permalink
Snapshots use lattice-based accounts hash (solana-labs#4113)
Browse files Browse the repository at this point in the history
  • Loading branch information
brooksprumo authored Jan 2, 2025
1 parent 6269bfe commit ac22051
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 98 deletions.
22 changes: 22 additions & 0 deletions accounts-db/src/accounts_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ pub const ACCOUNTS_DB_CONFIG_FOR_TESTING: AccountsDbConfig = AccountsDbConfig {
scan_filter_for_shrinking: ScanFilter::OnlyAbnormalWithVerify,
enable_experimental_accumulator_hash: false,
verify_experimental_accumulator_hash: false,
snapshots_use_experimental_accumulator_hash: false,
num_clean_threads: None,
num_foreground_threads: None,
num_hash_threads: None,
Expand All @@ -540,6 +541,7 @@ pub const ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS: AccountsDbConfig = AccountsDbConfig
scan_filter_for_shrinking: ScanFilter::OnlyAbnormalWithVerify,
enable_experimental_accumulator_hash: false,
verify_experimental_accumulator_hash: false,
snapshots_use_experimental_accumulator_hash: false,
num_clean_threads: None,
num_foreground_threads: None,
num_hash_threads: None,
Expand Down Expand Up @@ -668,6 +670,7 @@ pub struct AccountsDbConfig {
pub scan_filter_for_shrinking: ScanFilter,
pub enable_experimental_accumulator_hash: bool,
pub verify_experimental_accumulator_hash: bool,
pub snapshots_use_experimental_accumulator_hash: bool,
/// Number of threads for background cleaning operations (`thread_pool_clean')
pub num_clean_threads: Option<NonZeroUsize>,
/// Number of threads for foreground operations (`thread_pool`)
Expand Down Expand Up @@ -1621,6 +1624,10 @@ pub struct AccountsDb {
/// (For R&D only)
pub verify_experimental_accumulator_hash: bool,

/// Flag to indicate if the experimental accounts lattice hash is used for snapshots.
/// (For R&D only; a feature-gate also exists to turn this on.)
pub snapshots_use_experimental_accumulator_hash: AtomicBool,

/// These are the ancient storages that could be valuable to
/// shrink, sorted by amount of dead bytes. The elements
/// are sorted from the largest dead bytes to the smallest.
Expand Down Expand Up @@ -2039,6 +2046,9 @@ impl AccountsDb {
.into(),
verify_experimental_accumulator_hash: accounts_db_config
.verify_experimental_accumulator_hash,
snapshots_use_experimental_accumulator_hash: accounts_db_config
.snapshots_use_experimental_accumulator_hash
.into(),
thread_pool,
thread_pool_clean,
thread_pool_hash,
Expand Down Expand Up @@ -2129,6 +2139,18 @@ impl AccountsDb {
.store(is_enabled, Ordering::Release);
}

/// Returns if snapshots use the experimental accounts lattice hash
pub fn snapshots_use_experimental_accumulator_hash(&self) -> bool {
self.snapshots_use_experimental_accumulator_hash
.load(Ordering::Acquire)
}

/// Sets if snapshots use the experimental accounts lattice hash
pub fn set_snapshots_use_experimental_accumulator_hash(&self, is_enabled: bool) {
self.snapshots_use_experimental_accumulator_hash
.store(is_enabled, Ordering::Release);
}

/// While scanning cleaning candidates obtain slots that can be
/// reclaimed for each pubkey. In addition, if the pubkey is
/// removed from the index, insert in pubkeys_removed_from_accounts_index.
Expand Down
9 changes: 9 additions & 0 deletions accounts-db/src/accounts_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,15 @@ pub const ZERO_LAMPORT_ACCOUNT_LT_HASH: AccountLtHash = AccountLtHash(LtHash::id
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct AccountsLtHash(pub LtHash);

/// Hash of accounts
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum MerkleOrLatticeAccountsHash {
/// Merkle-based hash of accounts
Merkle(AccountsHashKind),
/// Lattice-based hash of accounts
Lattice,
}

/// Hash of accounts
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AccountsHashKind {
Expand Down
51 changes: 38 additions & 13 deletions core/src/accounts_hash_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use {
accounts_db::CalcAccountsHashKind,
accounts_hash::{
AccountsHash, AccountsHashKind, CalcAccountsHashConfig, HashStats,
IncrementalAccountsHash,
IncrementalAccountsHash, MerkleOrLatticeAccountsHash,
},
sorted_storages::SortedStorages,
},
Expand All @@ -16,7 +16,8 @@ use {
serde_snapshot::BankIncrementalSnapshotPersistence,
snapshot_config::SnapshotConfig,
snapshot_package::{
self, AccountsPackage, AccountsPackageKind, SnapshotKind, SnapshotPackage,
self, AccountsHashAlgorithm, AccountsPackage, AccountsPackageKind, SnapshotKind,
SnapshotPackage,
},
snapshot_utils,
},
Expand Down Expand Up @@ -215,18 +216,18 @@ impl AccountsHashVerifier {
pending_snapshot_packages: &Mutex<PendingSnapshotPackages>,
snapshot_config: &SnapshotConfig,
) -> IoResult<()> {
let (accounts_hash_kind, bank_incremental_snapshot_persistence) =
let (merkle_or_lattice_accounts_hash, bank_incremental_snapshot_persistence) =
Self::calculate_and_verify_accounts_hash(&accounts_package, snapshot_config)?;

Self::save_epoch_accounts_hash(&accounts_package, accounts_hash_kind);
Self::save_epoch_accounts_hash(&accounts_package, &merkle_or_lattice_accounts_hash);

Self::purge_old_accounts_hashes(&accounts_package, snapshot_config);

Self::submit_for_packaging(
accounts_package,
pending_snapshot_packages,
snapshot_config,
accounts_hash_kind,
merkle_or_lattice_accounts_hash,
bank_incremental_snapshot_persistence,
);

Expand All @@ -237,7 +238,26 @@ impl AccountsHashVerifier {
fn calculate_and_verify_accounts_hash(
accounts_package: &AccountsPackage,
snapshot_config: &SnapshotConfig,
) -> IoResult<(AccountsHashKind, Option<BankIncrementalSnapshotPersistence>)> {
) -> IoResult<(
MerkleOrLatticeAccountsHash,
Option<BankIncrementalSnapshotPersistence>,
)> {
match accounts_package.accounts_hash_algorithm {
AccountsHashAlgorithm::Merkle => {
debug!(
"calculate_and_verify_accounts_hash(): snapshots lt hash is disabled, \
DO merkle-based accounts hash calculation",
);
}
AccountsHashAlgorithm::Lattice => {
debug!(
"calculate_and_verify_accounts_hash(): snapshots lt hash is enabled, \
SKIP merkle-based accounts hash calculation",
);
return Ok((MerkleOrLatticeAccountsHash::Lattice, None));
}
}

let accounts_hash_calculation_kind = match accounts_package.package_kind {
AccountsPackageKind::AccountsHashVerifier => CalcAccountsHashKind::Full,
AccountsPackageKind::EpochAccountsHash => CalcAccountsHashKind::Full,
Expand Down Expand Up @@ -297,7 +317,10 @@ impl AccountsHashVerifier {
}
};

Ok((accounts_hash_kind, bank_incremental_snapshot_persistence))
Ok((
MerkleOrLatticeAccountsHash::Merkle(accounts_hash_kind),
bank_incremental_snapshot_persistence,
))
}

fn _calculate_full_accounts_hash(
Expand Down Expand Up @@ -412,11 +435,13 @@ impl AccountsHashVerifier {

fn save_epoch_accounts_hash(
accounts_package: &AccountsPackage,
accounts_hash: AccountsHashKind,
merkle_or_lattice_accounts_hash: &MerkleOrLatticeAccountsHash,
) {
if accounts_package.package_kind == AccountsPackageKind::EpochAccountsHash {
let AccountsHashKind::Full(accounts_hash) = accounts_hash else {
panic!("EAH requires a full accounts hash!");
let MerkleOrLatticeAccountsHash::Merkle(AccountsHashKind::Full(accounts_hash)) =
merkle_or_lattice_accounts_hash
else {
panic!("EAH requires a full accounts hash, but was given {merkle_or_lattice_accounts_hash:?}");
};
info!(
"saving epoch accounts hash, slot: {}, hash: {}",
Expand All @@ -426,7 +451,7 @@ impl AccountsHashVerifier {
.accounts
.accounts_db
.epoch_accounts_hash_manager
.set_valid(accounts_hash.into(), accounts_package.slot);
.set_valid((*accounts_hash).into(), accounts_package.slot);
}
}

Expand Down Expand Up @@ -465,7 +490,7 @@ impl AccountsHashVerifier {
accounts_package: AccountsPackage,
pending_snapshot_packages: &Mutex<PendingSnapshotPackages>,
snapshot_config: &SnapshotConfig,
accounts_hash_kind: AccountsHashKind,
merkle_or_lattice_accounts_hash: MerkleOrLatticeAccountsHash,
bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
) {
if !snapshot_config.should_generate_snapshots()
Expand All @@ -479,7 +504,7 @@ impl AccountsHashVerifier {

let snapshot_package = SnapshotPackage::new(
accounts_package,
accounts_hash_kind,
merkle_or_lattice_accounts_hash,
bank_incremental_snapshot_persistence,
);
pending_snapshot_packages
Expand Down
11 changes: 10 additions & 1 deletion core/tests/snapshots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,17 +628,24 @@ enum VerifyAccountsKind {
Merkle,
Lattice,
}
#[derive(Debug, Eq, PartialEq)]
enum VerifySnapshotHashKind {
Merkle,
Lattice,
}

/// Spin up the background services fully then test taking & verifying snapshots
#[test_matrix(
V1_2_0,
[Development, Devnet, Testnet, MainnetBeta],
[VerifyAccountsKind::Merkle, VerifyAccountsKind::Lattice]
[VerifyAccountsKind::Merkle, VerifyAccountsKind::Lattice],
[VerifySnapshotHashKind::Merkle, VerifySnapshotHashKind::Lattice]
)]
fn test_snapshots_with_background_services(
snapshot_version: SnapshotVersion,
cluster_type: ClusterType,
verify_accounts_kind: VerifyAccountsKind,
verify_snapshot_hash_kind: VerifySnapshotHashKind,
) {
solana_logger::setup();

Expand Down Expand Up @@ -825,6 +832,8 @@ fn test_snapshots_with_background_services(
let (_tmp_dir, temporary_accounts_dir) = create_tmp_accounts_dir_for_tests();
let accounts_db_config = AccountsDbConfig {
enable_experimental_accumulator_hash: verify_accounts_kind == VerifyAccountsKind::Lattice,
snapshots_use_experimental_accumulator_hash: verify_snapshot_hash_kind
== VerifySnapshotHashKind::Lattice,
..ACCOUNTS_DB_CONFIG_FOR_TESTING
};
let (deserialized_bank, ..) = snapshot_bank_utils::bank_from_latest_snapshot_archives(
Expand Down
6 changes: 6 additions & 0 deletions ledger-tool/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ pub fn accounts_db_args<'a, 'b>() -> Box<[Arg<'a, 'b>]> {
.long("accounts-db-verify-experimental-accumulator-hash")
.help("Verifies the experimental accumulator hash")
.hidden(hidden_unless_forced()),
Arg::with_name("accounts_db_snapshots_use_experimental_accumulator_hash")
.long("accounts-db-snapshots-use-experimental-accumulator-hash")
.help("Snapshots use the experimental accumulator hash")
.hidden(hidden_unless_forced()),
Arg::with_name("accounts_db_hash_threads")
.long("accounts-db-hash-threads")
.value_name("NUM_THREADS")
Expand Down Expand Up @@ -387,6 +391,8 @@ pub fn get_accounts_db_config(
.is_present("accounts_db_experimental_accumulator_hash"),
verify_experimental_accumulator_hash: arg_matches
.is_present("accounts_db_verify_experimental_accumulator_hash"),
snapshots_use_experimental_accumulator_hash: arg_matches
.is_present("accounts_db_snapshots_use_experimental_accumulator_hash"),
num_hash_threads,
..AccountsDbConfig::default()
}
Expand Down
44 changes: 38 additions & 6 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use {
},
accounts_hash::{
AccountHash, AccountsHash, AccountsLtHash, CalcAccountsHashConfig, HashStats,
IncrementalAccountsHash,
IncrementalAccountsHash, MerkleOrLatticeAccountsHash,
},
accounts_index::{IndexKey, ScanConfig, ScanResult},
accounts_partition::{self, Partition, PartitionIndex},
Expand Down Expand Up @@ -5722,20 +5722,52 @@ impl Bank {
///
/// # Panics
///
/// Panics if there is both-or-neither of an `AccountsHash` and an `IncrementalAccountsHash`
/// for this bank's slot. There may only be one or the other.
/// If the snapshots lt hash feature is not enabled, panics if there is both-or-neither of an
/// `AccountsHash` and an `IncrementalAccountsHash` for this bank's slot. There may only be
/// one or the other.
pub fn get_snapshot_hash(&self) -> SnapshotHash {
if self.is_snapshots_lt_hash_enabled() {
self.get_lattice_snapshot_hash()
} else {
self.get_merkle_snapshot_hash()
}
}

/// Returns the merkle-based `SnapshotHash` for this bank's slot
///
/// This fn is used at startup to verify the bank was rebuilt correctly.
///
/// # Panics
///
/// If the snapshots lt hash feature is not enabled, panics if there is both-or-neither of an
/// `AccountsHash` and an `IncrementalAccountsHash` for this bank's slot. There may only be
/// one or the other.
pub fn get_merkle_snapshot_hash(&self) -> SnapshotHash {
let accounts_hash = self.get_accounts_hash();
let incremental_accounts_hash = self.get_incremental_accounts_hash();

let accounts_hash = match (accounts_hash, incremental_accounts_hash) {
let accounts_hash_kind = match (accounts_hash, incremental_accounts_hash) {
(Some(_), Some(_)) => panic!("Both full and incremental accounts hashes are present for slot {}; it is ambiguous which one to use for the snapshot hash!", self.slot()),
(Some(accounts_hash), None) => accounts_hash.into(),
(None, Some(incremental_accounts_hash)) => incremental_accounts_hash.into(),
(None, None) => panic!("accounts hash is required to get snapshot hash"),
};
let epoch_accounts_hash = self.get_epoch_accounts_hash_to_serialize();
SnapshotHash::new(&accounts_hash, epoch_accounts_hash.as_ref())
SnapshotHash::new(
&MerkleOrLatticeAccountsHash::Merkle(accounts_hash_kind),
epoch_accounts_hash.as_ref(),
None,
)
}

/// Returns the lattice-based `SnapshotHash` for this bank's slot
///
/// This fn is used at startup to verify the bank was rebuilt correctly.
pub fn get_lattice_snapshot_hash(&self) -> SnapshotHash {
SnapshotHash::new(
&MerkleOrLatticeAccountsHash::Lattice,
self.get_epoch_accounts_hash_to_serialize().as_ref(),
Some(self.accounts_lt_hash.lock().unwrap().0.checksum()),
)
}

pub fn load_account_into_read_cache(&self, key: &Pubkey) {
Expand Down
Loading

0 comments on commit ac22051

Please sign in to comment.