Adds AccountHash newtype (#33597)
This commit is contained in:
parent
052677595c
commit
fc73813db2
|
@ -1,10 +1,12 @@
|
|||
use {
|
||||
crate::accounts_db::IncludeSlotInHash,
|
||||
crate::{
|
||||
accounts_db::{AccountsDb, IncludeSlotInHash},
|
||||
accounts_hash::AccountHash,
|
||||
},
|
||||
dashmap::DashMap,
|
||||
solana_sdk::{
|
||||
account::{AccountSharedData, ReadableAccount},
|
||||
clock::Slot,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
std::{
|
||||
|
@ -141,7 +143,7 @@ pub type CachedAccount = Arc<CachedAccountInner>;
|
|||
#[derive(Debug)]
|
||||
pub struct CachedAccountInner {
|
||||
pub account: AccountSharedData,
|
||||
hash: RwLock<Option<Hash>>,
|
||||
hash: RwLock<Option<AccountHash>>,
|
||||
slot: Slot,
|
||||
pubkey: Pubkey,
|
||||
/// temporarily here during feature activation
|
||||
|
@ -150,13 +152,13 @@ pub struct CachedAccountInner {
|
|||
}
|
||||
|
||||
impl CachedAccountInner {
|
||||
pub fn hash(&self) -> Hash {
|
||||
pub fn hash(&self) -> AccountHash {
|
||||
let hash = self.hash.read().unwrap();
|
||||
match *hash {
|
||||
Some(hash) => hash,
|
||||
None => {
|
||||
drop(hash);
|
||||
let hash = crate::accounts_db::AccountsDb::hash_account(
|
||||
let hash = AccountsDb::hash_account(
|
||||
self.slot,
|
||||
&self.account,
|
||||
&self.pubkey,
|
||||
|
|
|
@ -33,7 +33,7 @@ use {
|
|||
accounts_cache::{AccountsCache, CachedAccount, SlotCache},
|
||||
accounts_file::{AccountsFile, AccountsFileError},
|
||||
accounts_hash::{
|
||||
AccountsDeltaHash, AccountsHash, AccountsHashKind, AccountsHasher,
|
||||
AccountHash, AccountsDeltaHash, AccountsHash, AccountsHashKind, AccountsHasher,
|
||||
CalcAccountsHashConfig, CalculateHashIntermediate, HashStats, IncrementalAccountsHash,
|
||||
SerdeAccountsDeltaHash, SerdeAccountsHash, SerdeIncrementalAccountsHash,
|
||||
ZeroLamportAccounts,
|
||||
|
@ -894,9 +894,9 @@ pub enum LoadedAccount<'a> {
|
|||
}
|
||||
|
||||
impl<'a> LoadedAccount<'a> {
|
||||
pub fn loaded_hash(&self) -> Hash {
|
||||
pub fn loaded_hash(&self) -> AccountHash {
|
||||
match self {
|
||||
LoadedAccount::Stored(stored_account_meta) => *stored_account_meta.hash(),
|
||||
LoadedAccount::Stored(stored_account_meta) => AccountHash(*stored_account_meta.hash()),
|
||||
LoadedAccount::Cached(cached_account) => cached_account.hash(),
|
||||
}
|
||||
}
|
||||
|
@ -913,7 +913,7 @@ impl<'a> LoadedAccount<'a> {
|
|||
slot: Slot,
|
||||
pubkey: &Pubkey,
|
||||
include_slot: IncludeSlotInHash,
|
||||
) -> Hash {
|
||||
) -> AccountHash {
|
||||
match self {
|
||||
LoadedAccount::Stored(stored_account_meta) => AccountsDb::hash_account(
|
||||
slot,
|
||||
|
@ -2392,7 +2392,7 @@ impl<'a> AppendVecScan for ScanState<'a> {
|
|||
let balance = loaded_account.lamports();
|
||||
let mut loaded_hash = loaded_account.loaded_hash();
|
||||
|
||||
let hash_is_missing = loaded_hash == Hash::default();
|
||||
let hash_is_missing = loaded_hash == AccountHash(Hash::default());
|
||||
if (self.config.check_hash || hash_is_missing)
|
||||
&& !AccountsDb::is_filler_account_helper(pubkey, self.filler_account_suffix)
|
||||
{
|
||||
|
@ -2406,13 +2406,13 @@ impl<'a> AppendVecScan for ScanState<'a> {
|
|||
} else if self.config.check_hash && computed_hash != loaded_hash {
|
||||
info!(
|
||||
"hash mismatch found: computed: {}, loaded: {}, pubkey: {}",
|
||||
computed_hash, loaded_hash, pubkey
|
||||
computed_hash.0, loaded_hash.0, pubkey
|
||||
);
|
||||
self.mismatch_found.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
let source_item = CalculateHashIntermediate {
|
||||
hash: loaded_hash,
|
||||
hash: loaded_hash.0,
|
||||
lamports: balance,
|
||||
pubkey: *pubkey,
|
||||
};
|
||||
|
@ -2429,7 +2429,7 @@ impl<'a> AppendVecScan for ScanState<'a> {
|
|||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct PubkeyHashAccount {
|
||||
pub pubkey: Pubkey,
|
||||
pub hash: Hash,
|
||||
pub hash: AccountHash,
|
||||
pub account: AccountSharedData,
|
||||
}
|
||||
|
||||
|
@ -5567,7 +5567,7 @@ impl AccountsDb {
|
|||
pubkey: &Pubkey,
|
||||
max_root: Option<Slot>,
|
||||
load_hint: LoadHint,
|
||||
) -> Option<Hash> {
|
||||
) -> Option<AccountHash> {
|
||||
let (slot, storage_location, _maybe_account_accesor) =
|
||||
self.read_index_for_accessor_or_load_slow(ancestors, pubkey, max_root, false)?;
|
||||
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
||||
|
@ -6185,7 +6185,7 @@ impl AccountsDb {
|
|||
account: &T,
|
||||
pubkey: &Pubkey,
|
||||
include_slot: IncludeSlotInHash,
|
||||
) -> Hash {
|
||||
) -> AccountHash {
|
||||
Self::hash_account_data(
|
||||
slot,
|
||||
account.lamports(),
|
||||
|
@ -6207,9 +6207,9 @@ impl AccountsDb {
|
|||
data: &[u8],
|
||||
pubkey: &Pubkey,
|
||||
include_slot: IncludeSlotInHash,
|
||||
) -> Hash {
|
||||
) -> AccountHash {
|
||||
if lamports == 0 {
|
||||
return Hash::default();
|
||||
return AccountHash(Hash::default());
|
||||
}
|
||||
let mut hasher = blake3::Hasher::new();
|
||||
|
||||
|
@ -6239,7 +6239,7 @@ impl AccountsDb {
|
|||
hasher.update(owner.as_ref());
|
||||
hasher.update(pubkey.as_ref());
|
||||
|
||||
Hash::new_from_array(hasher.finalize().into())
|
||||
AccountHash(Hash::new_from_array(hasher.finalize().into()))
|
||||
}
|
||||
|
||||
fn bulk_assign_write_version(&self, count: usize) -> StoredMetaWriteVersion {
|
||||
|
@ -6560,7 +6560,7 @@ impl AccountsDb {
|
|||
}
|
||||
}
|
||||
|
||||
let (accounts, hashes): (Vec<(&Pubkey, &AccountSharedData)>, Vec<Hash>) = iter_items
|
||||
let (accounts, hashes): (Vec<(&Pubkey, &AccountSharedData)>, Vec<AccountHash>) = iter_items
|
||||
.iter()
|
||||
.filter_map(|iter_item| {
|
||||
let key = iter_item.key();
|
||||
|
@ -7025,7 +7025,7 @@ impl AccountsDb {
|
|||
|loaded_account| {
|
||||
let mut loaded_hash = loaded_account.loaded_hash();
|
||||
let balance = loaded_account.lamports();
|
||||
let hash_is_missing = loaded_hash == Hash::default();
|
||||
let hash_is_missing = loaded_hash == AccountHash(Hash::default());
|
||||
if (config.check_hash || hash_is_missing) && !self.is_filler_account(pubkey) {
|
||||
let computed_hash =
|
||||
loaded_account.compute_hash(*slot, pubkey, config.include_slot_in_hash);
|
||||
|
@ -7033,7 +7033,7 @@ impl AccountsDb {
|
|||
loaded_hash = computed_hash;
|
||||
}
|
||||
else if config.check_hash && computed_hash != loaded_hash {
|
||||
info!("hash mismatch found: computed: {}, loaded: {}, pubkey: {}", computed_hash, loaded_hash, pubkey);
|
||||
info!("hash mismatch found: computed: {}, loaded: {}, pubkey: {}", computed_hash.0, loaded_hash.0, pubkey);
|
||||
mismatch_found
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
return None;
|
||||
|
@ -7041,7 +7041,7 @@ impl AccountsDb {
|
|||
}
|
||||
|
||||
sum += balance as u128;
|
||||
Some(loaded_hash)
|
||||
Some(loaded_hash.0)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -7916,17 +7916,20 @@ impl AccountsDb {
|
|||
/// 1. pubkey, hash pairs for the slot
|
||||
/// 2. us spent scanning
|
||||
/// 3. Measure started when we began accumulating
|
||||
pub fn get_pubkey_hash_for_slot(&self, slot: Slot) -> (Vec<(Pubkey, Hash)>, u64, Measure) {
|
||||
pub fn get_pubkey_hash_for_slot(
|
||||
&self,
|
||||
slot: Slot,
|
||||
) -> (Vec<(Pubkey, AccountHash)>, u64, Measure) {
|
||||
let mut scan = Measure::start("scan");
|
||||
|
||||
let scan_result: ScanStorageResult<(Pubkey, Hash), DashMap<Pubkey, Hash>> = self
|
||||
.scan_account_storage(
|
||||
let scan_result: ScanStorageResult<(Pubkey, AccountHash), DashMap<Pubkey, AccountHash>> =
|
||||
self.scan_account_storage(
|
||||
slot,
|
||||
|loaded_account: LoadedAccount| {
|
||||
// Cache only has one version per key, don't need to worry about versioning
|
||||
Some((*loaded_account.pubkey(), loaded_account.loaded_hash()))
|
||||
},
|
||||
|accum: &DashMap<Pubkey, Hash>, loaded_account: LoadedAccount| {
|
||||
|accum: &DashMap<Pubkey, AccountHash>, loaded_account: LoadedAccount| {
|
||||
let loaded_hash = loaded_account.loaded_hash();
|
||||
accum.insert(*loaded_account.pubkey(), loaded_hash);
|
||||
},
|
||||
|
@ -7944,7 +7947,7 @@ impl AccountsDb {
|
|||
/// Return all of the accounts for a given slot
|
||||
pub fn get_pubkey_hash_account_for_slot(&self, slot: Slot) -> Vec<PubkeyHashAccount> {
|
||||
type ScanResult =
|
||||
ScanStorageResult<PubkeyHashAccount, DashMap<Pubkey, (Hash, AccountSharedData)>>;
|
||||
ScanStorageResult<PubkeyHashAccount, DashMap<Pubkey, (AccountHash, AccountSharedData)>>;
|
||||
let scan_result: ScanResult = self.scan_account_storage(
|
||||
slot,
|
||||
|loaded_account: LoadedAccount| {
|
||||
|
@ -7955,7 +7958,8 @@ impl AccountsDb {
|
|||
account: loaded_account.take_account(),
|
||||
})
|
||||
},
|
||||
|accum: &DashMap<Pubkey, (Hash, AccountSharedData)>, loaded_account: LoadedAccount| {
|
||||
|accum: &DashMap<Pubkey, (AccountHash, AccountSharedData)>,
|
||||
loaded_account: LoadedAccount| {
|
||||
// Storage may have duplicates so only keep the latest version for each key
|
||||
accum.insert(
|
||||
*loaded_account.pubkey(),
|
||||
|
@ -10482,10 +10486,10 @@ pub mod tests {
|
|||
];
|
||||
|
||||
let expected_hashes = [
|
||||
Hash::from_str("5K3NW73xFHwgTWVe4LyCg4QfQda8f88uZj2ypDx2kmmH").unwrap(),
|
||||
Hash::from_str("84ozw83MZ8oeSF4hRAg7SeW1Tqs9LMXagX1BrDRjtZEx").unwrap(),
|
||||
Hash::from_str("5XqtnEJ41CG2JWNp7MAg9nxkRUAnyjLxfsKsdrLxQUbC").unwrap(),
|
||||
Hash::from_str("DpvwJcznzwULYh19Zu5CuAA4AT6WTBe4H6n15prATmqj").unwrap(),
|
||||
AccountHash(Hash::from_str("5K3NW73xFHwgTWVe4LyCg4QfQda8f88uZj2ypDx2kmmH").unwrap()),
|
||||
AccountHash(Hash::from_str("84ozw83MZ8oeSF4hRAg7SeW1Tqs9LMXagX1BrDRjtZEx").unwrap()),
|
||||
AccountHash(Hash::from_str("5XqtnEJ41CG2JWNp7MAg9nxkRUAnyjLxfsKsdrLxQUbC").unwrap()),
|
||||
AccountHash(Hash::from_str("DpvwJcznzwULYh19Zu5CuAA4AT6WTBe4H6n15prATmqj").unwrap()),
|
||||
];
|
||||
|
||||
let mut raw_accounts = Vec::default();
|
||||
|
@ -10505,7 +10509,7 @@ pub mod tests {
|
|||
if slot == 1 && matches!(include_slot_in_hash, IncludeSlotInHash::IncludeSlot) {
|
||||
assert_eq!(hash, expected_hashes[i]);
|
||||
}
|
||||
raw_expected[i].hash = hash;
|
||||
raw_expected[i].hash = hash.0;
|
||||
}
|
||||
|
||||
let to_store = raw_accounts
|
||||
|
@ -12696,7 +12700,7 @@ pub mod tests {
|
|||
let account = stored_account.to_account_shared_data();
|
||||
|
||||
let expected_account_hash =
|
||||
Hash::from_str("6VeAL4x4PVkECKL1hD1avwPE1uMCRoWiZJzVMvVNYhTq").unwrap();
|
||||
AccountHash(Hash::from_str("6VeAL4x4PVkECKL1hD1avwPE1uMCRoWiZJzVMvVNYhTq").unwrap());
|
||||
|
||||
assert_eq!(
|
||||
AccountsDb::hash_account(
|
||||
|
@ -18161,7 +18165,7 @@ pub mod tests {
|
|||
// Ensure the zero-lamport accounts are NOT included in the full accounts hash.
|
||||
let full_account_hashes = [(2, 0), (3, 0), (4, 1)].into_iter().map(|(index, slot)| {
|
||||
let (pubkey, account) = &accounts[index];
|
||||
AccountsDb::hash_account(slot, account, pubkey, INCLUDE_SLOT_IN_HASH_TESTS)
|
||||
AccountsDb::hash_account(slot, account, pubkey, INCLUDE_SLOT_IN_HASH_TESTS).0
|
||||
});
|
||||
let expected_accounts_hash = AccountsHash(compute_merkle_root(full_account_hashes));
|
||||
assert_eq!(full_accounts_hash.0, expected_accounts_hash);
|
||||
|
@ -18243,6 +18247,7 @@ pub mod tests {
|
|||
Hash::new_from_array(hash.into())
|
||||
} else {
|
||||
AccountsDb::hash_account(slot, account, pubkey, INCLUDE_SLOT_IN_HASH_TESTS)
|
||||
.0
|
||||
}
|
||||
});
|
||||
let expected_accounts_hash =
|
||||
|
|
|
@ -740,14 +740,9 @@ impl<'a> AccountsHasher<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn accumulate_account_hashes(mut hashes: Vec<(Pubkey, Hash)>) -> Hash {
|
||||
Self::sort_hashes_by_pubkey(&mut hashes);
|
||||
|
||||
Self::compute_merkle_root_loop(hashes, MERKLE_FANOUT, |i| &i.1)
|
||||
}
|
||||
|
||||
pub fn sort_hashes_by_pubkey(hashes: &mut Vec<(Pubkey, Hash)>) {
|
||||
pub fn accumulate_account_hashes(mut hashes: Vec<(Pubkey, AccountHash)>) -> Hash {
|
||||
hashes.par_sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||
Self::compute_merkle_root_loop(hashes, MERKLE_FANOUT, |i| &i.1 .0)
|
||||
}
|
||||
|
||||
pub fn compare_two_hash_entries(
|
||||
|
@ -1206,6 +1201,21 @@ pub enum ZeroLamportAccounts {
|
|||
Included,
|
||||
}
|
||||
|
||||
/// Hash of an account
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Pod, Zeroable)]
|
||||
pub struct AccountHash(pub Hash);
|
||||
|
||||
// Ensure the newtype wrapper never changes size from the underlying Hash
|
||||
// This also ensures there are no padding bytes, which is requried to safely implement Pod
|
||||
const _: () = assert!(std::mem::size_of::<AccountHash>() == std::mem::size_of::<Hash>());
|
||||
|
||||
impl Borrow<Hash> for AccountHash {
|
||||
fn borrow(&self) -> &Hash {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Hash of accounts
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum AccountsHashKind {
|
||||
|
@ -2320,14 +2330,18 @@ mod tests {
|
|||
.collect();
|
||||
|
||||
let result = if pass == 0 {
|
||||
test_hashing_larger(input.clone(), fanout)
|
||||
test_hashing_larger(input, fanout)
|
||||
} else {
|
||||
// this sorts inside
|
||||
let early_result = AccountsHasher::accumulate_account_hashes(
|
||||
input.iter().map(|i| (i.0, i.1)).collect::<Vec<_>>(),
|
||||
input
|
||||
.iter()
|
||||
.map(|i| (i.0, AccountHash(i.1)))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
AccountsHasher::sort_hashes_by_pubkey(&mut input);
|
||||
let result = AccountsHasher::compute_merkle_root(input.clone(), fanout);
|
||||
|
||||
input.par_sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||
let result = AccountsHasher::compute_merkle_root(input, fanout);
|
||||
assert_eq!(early_result, result);
|
||||
result
|
||||
};
|
||||
|
|
|
@ -8,7 +8,10 @@ use {
|
|||
de::{self, Deserialize, Deserializer},
|
||||
ser::{Serialize, SerializeSeq, Serializer},
|
||||
},
|
||||
solana_accounts_db::{accounts_db::PubkeyHashAccount, accounts_hash::AccountsDeltaHash},
|
||||
solana_accounts_db::{
|
||||
accounts_db::PubkeyHashAccount,
|
||||
accounts_hash::{AccountHash, AccountsDeltaHash},
|
||||
},
|
||||
solana_sdk::{
|
||||
account::{Account, AccountSharedData, ReadableAccount},
|
||||
clock::{Epoch, Slot},
|
||||
|
@ -124,7 +127,7 @@ impl From<&PubkeyHashAccount> for SerdeAccount {
|
|||
} = pubkey_hash_account;
|
||||
Self {
|
||||
pubkey: pubkey.to_string(),
|
||||
hash: hash.to_string(),
|
||||
hash: hash.0.to_string(),
|
||||
owner: account.owner().to_string(),
|
||||
lamports: account.lamports(),
|
||||
rent_epoch: account.rent_epoch(),
|
||||
|
@ -139,7 +142,7 @@ impl TryFrom<SerdeAccount> for PubkeyHashAccount {
|
|||
|
||||
fn try_from(temp_account: SerdeAccount) -> Result<Self, Self::Error> {
|
||||
let pubkey = Pubkey::from_str(&temp_account.pubkey).map_err(|err| err.to_string())?;
|
||||
let hash = Hash::from_str(&temp_account.hash).map_err(|err| err.to_string())?;
|
||||
let hash = AccountHash(Hash::from_str(&temp_account.hash).map_err(|err| err.to_string())?);
|
||||
|
||||
let account = AccountSharedData::from(Account {
|
||||
lamports: temp_account.lamports,
|
||||
|
@ -244,7 +247,7 @@ pub mod tests {
|
|||
rent_epoch: 123,
|
||||
});
|
||||
let account_pubkey = Pubkey::new_unique();
|
||||
let account_hash = hash("account".as_bytes());
|
||||
let account_hash = AccountHash(hash("account".as_bytes()));
|
||||
let accounts = BankHashAccounts {
|
||||
accounts: vec![PubkeyHashAccount {
|
||||
pubkey: account_pubkey,
|
||||
|
|
Loading…
Reference in New Issue