Abstract out StoredAccountMeta as an Enum (#30478)
#### Problem The existing StoredAccountMeta requires the file and in-memory layout of account metadata to match StoredMeta and AccountMeta. This limits the flexibility to implement different accounts storage file formats. #### Summary of Changes This PR abstracts out StoredAccountMeta as an Enum.
This commit is contained in:
parent
b0112a5f43
commit
71b6370426
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::storable_accounts::StorableAccounts,
|
crate::{append_vec::AppendVecStoredAccountMeta, storable_accounts::StorableAccounts},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{Account, AccountSharedData, ReadableAccount},
|
account::{AccountSharedData, ReadableAccount},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
stake_history::Epoch,
|
stake_history::Epoch,
|
||||||
|
@ -103,95 +103,104 @@ impl<'a: 'b, 'b, T: ReadableAccount + Sync + 'b, U: StorableAccounts<'a, T>, V:
|
||||||
/// References to account data stored elsewhere. Getting an `Account` requires cloning
|
/// References to account data stored elsewhere. Getting an `Account` requires cloning
|
||||||
/// (see `StoredAccountMeta::clone_account()`).
|
/// (see `StoredAccountMeta::clone_account()`).
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct StoredAccountMeta<'a> {
|
pub enum StoredAccountMeta<'a> {
|
||||||
pub(crate) meta: &'a StoredMeta,
|
AppendVec(AppendVecStoredAccountMeta<'a>),
|
||||||
/// account data
|
|
||||||
pub(crate) account_meta: &'a AccountMeta,
|
|
||||||
pub(crate) data: &'a [u8],
|
|
||||||
pub(crate) offset: usize,
|
|
||||||
pub(crate) stored_size: usize,
|
|
||||||
pub(crate) hash: &'a Hash,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StoredAccountMeta<'a> {
|
impl<'a> StoredAccountMeta<'a> {
|
||||||
/// Return a new Account by copying all the data referenced by the `StoredAccountMeta`.
|
/// Return a new Account by copying all the data referenced by the `StoredAccountMeta`.
|
||||||
pub fn clone_account(&self) -> AccountSharedData {
|
pub fn clone_account(&self) -> AccountSharedData {
|
||||||
AccountSharedData::from(Account {
|
match self {
|
||||||
lamports: self.account_meta.lamports,
|
Self::AppendVec(av) => av.clone_account(),
|
||||||
owner: self.account_meta.owner,
|
}
|
||||||
executable: self.account_meta.executable,
|
|
||||||
rent_epoch: self.account_meta.rent_epoch,
|
|
||||||
data: self.data.to_vec(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pubkey(&self) -> &'a Pubkey {
|
pub fn pubkey(&self) -> &'a Pubkey {
|
||||||
&self.meta.pubkey
|
match self {
|
||||||
|
Self::AppendVec(av) => av.pubkey(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(&self) -> &'a Hash {
|
pub fn hash(&self) -> &'a Hash {
|
||||||
self.hash
|
match self {
|
||||||
|
Self::AppendVec(av) => av.hash(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stored_size(&self) -> usize {
|
pub fn stored_size(&self) -> usize {
|
||||||
self.stored_size
|
match self {
|
||||||
|
Self::AppendVec(av) => av.stored_size(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(&self) -> usize {
|
pub fn offset(&self) -> usize {
|
||||||
self.offset
|
match self {
|
||||||
|
Self::AppendVec(av) => av.offset(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &'a [u8] {
|
pub fn data(&self) -> &'a [u8] {
|
||||||
self.data
|
match self {
|
||||||
|
Self::AppendVec(av) => av.data(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_len(&self) -> u64 {
|
pub fn data_len(&self) -> u64 {
|
||||||
self.meta.data_len
|
match self {
|
||||||
|
Self::AppendVec(av) => av.data_len(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_version(&self) -> StoredMetaWriteVersion {
|
pub fn write_version(&self) -> StoredMetaWriteVersion {
|
||||||
self.meta.write_version_obsolete
|
match self {
|
||||||
|
Self::AppendVec(av) => av.write_version(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn meta(&self) -> &StoredMeta {
|
||||||
|
match self {
|
||||||
|
Self::AppendVec(av) => av.meta(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_meta(&mut self, meta: &'a StoredMeta) {
|
||||||
|
match self {
|
||||||
|
Self::AppendVec(av) => av.set_meta(meta),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sanitize(&self) -> bool {
|
pub(crate) fn sanitize(&self) -> bool {
|
||||||
self.sanitize_executable() && self.sanitize_lamports()
|
match self {
|
||||||
|
Self::AppendVec(av) => av.sanitize(),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sanitize_executable(&self) -> bool {
|
|
||||||
// Sanitize executable to ensure higher 7-bits are cleared correctly.
|
|
||||||
self.ref_executable_byte() & !1 == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn sanitize_lamports(&self) -> bool {
|
|
||||||
// Sanitize 0 lamports to ensure to be same as AccountSharedData::default()
|
|
||||||
self.account_meta.lamports != 0 || self.clone_account() == AccountSharedData::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn ref_executable_byte(&self) -> &'a u8 {
|
|
||||||
// Use extra references to avoid value silently clamped to 1 (=true) and 0 (=false)
|
|
||||||
// Yes, this really happens; see test_new_from_file_crafted_executable
|
|
||||||
let executable_bool: &bool = &self.account_meta.executable;
|
|
||||||
// UNSAFE: Force to interpret mmap-backed bool as u8 to really read the actual memory content
|
|
||||||
let executable_byte: &u8 = unsafe { &*(executable_bool as *const bool as *const u8) };
|
|
||||||
executable_byte
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ReadableAccount for StoredAccountMeta<'a> {
|
impl<'a> ReadableAccount for StoredAccountMeta<'a> {
|
||||||
fn lamports(&self) -> u64 {
|
fn lamports(&self) -> u64 {
|
||||||
self.account_meta.lamports
|
match self {
|
||||||
|
Self::AppendVec(av) => av.lamports(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn data(&self) -> &[u8] {
|
fn data(&self) -> &[u8] {
|
||||||
self.data()
|
match self {
|
||||||
|
Self::AppendVec(av) => av.data(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn owner(&self) -> &Pubkey {
|
fn owner(&self) -> &Pubkey {
|
||||||
&self.account_meta.owner
|
match self {
|
||||||
|
Self::AppendVec(av) => av.owner(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn executable(&self) -> bool {
|
fn executable(&self) -> bool {
|
||||||
self.account_meta.executable
|
match self {
|
||||||
|
Self::AppendVec(av) => av.executable(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn rent_epoch(&self) -> Epoch {
|
fn rent_epoch(&self) -> Epoch {
|
||||||
self.account_meta.rent_epoch
|
match self {
|
||||||
|
Self::AppendVec(av) => av.rent_epoch(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7976,7 +7976,7 @@ impl AccountsDb {
|
||||||
);
|
);
|
||||||
let offset = account_info.offset();
|
let offset = account_info.offset();
|
||||||
let account = store.accounts.get_account(offset).unwrap();
|
let account = store.accounts.get_account(offset).unwrap();
|
||||||
let stored_size = account.0.stored_size;
|
let stored_size = account.0.stored_size();
|
||||||
let count = store.remove_account(stored_size, reset_accounts);
|
let count = store.remove_account(stored_size, reset_accounts);
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
self.dirty_stores.insert(*slot, store.clone());
|
self.dirty_stores.insert(*slot, store.clone());
|
||||||
|
@ -9454,7 +9454,7 @@ pub mod tests {
|
||||||
tests::*, AccountIndex, AccountSecondaryIndexes,
|
tests::*, AccountIndex, AccountSecondaryIndexes,
|
||||||
AccountSecondaryIndexesIncludeExclude, ReadAccountMapEntry, RefCount,
|
AccountSecondaryIndexesIncludeExclude, ReadAccountMapEntry, RefCount,
|
||||||
},
|
},
|
||||||
append_vec::test_utils::TempFile,
|
append_vec::{test_utils::TempFile, AppendVecStoredAccountMeta},
|
||||||
cache_hash_data_stats::CacheHashDataStats,
|
cache_hash_data_stats::CacheHashDataStats,
|
||||||
inline_spl_token,
|
inline_spl_token,
|
||||||
secondary_index::MAX_NUM_LARGEST_INDEX_KEYS_RETURNED,
|
secondary_index::MAX_NUM_LARGEST_INDEX_KEYS_RETURNED,
|
||||||
|
@ -9664,7 +9664,7 @@ pub mod tests {
|
||||||
pubkey,
|
pubkey,
|
||||||
data_len: 43,
|
data_len: 43,
|
||||||
};
|
};
|
||||||
let account = StoredAccountMeta {
|
let account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &stored_meta,
|
meta: &stored_meta,
|
||||||
/// account data
|
/// account data
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
|
@ -9672,7 +9672,7 @@ pub mod tests {
|
||||||
offset,
|
offset,
|
||||||
stored_size: account_size,
|
stored_size: account_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let map = vec![&account];
|
let map = vec![&account];
|
||||||
let alive_total_bytes = account.stored_size();
|
let alive_total_bytes = account.stored_size();
|
||||||
let to_store = AccountsToStore::new(available_bytes, &map, alive_total_bytes, slot0);
|
let to_store = AccountsToStore::new(available_bytes, &map, alive_total_bytes, slot0);
|
||||||
|
@ -9760,38 +9760,38 @@ pub mod tests {
|
||||||
let offset = 99;
|
let offset = 99;
|
||||||
let stored_size = 101;
|
let stored_size = 101;
|
||||||
let hash = Hash::new_unique();
|
let hash = Hash::new_unique();
|
||||||
let stored_account = StoredAccountMeta {
|
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta,
|
meta: &meta,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let stored_account2 = StoredAccountMeta {
|
let stored_account2 = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta2,
|
meta: &meta2,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let stored_account3 = StoredAccountMeta {
|
let stored_account3 = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta3,
|
meta: &meta3,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let stored_account4 = StoredAccountMeta {
|
let stored_account4 = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta4,
|
meta: &meta4,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let mut existing_ancient_pubkeys = HashSet::default();
|
let mut existing_ancient_pubkeys = HashSet::default();
|
||||||
let accounts = [&stored_account];
|
let accounts = [&stored_account];
|
||||||
// pubkey NOT in existing_ancient_pubkeys, so do NOT unref, but add to existing_ancient_pubkeys
|
// pubkey NOT in existing_ancient_pubkeys, so do NOT unref, but add to existing_ancient_pubkeys
|
||||||
|
@ -12382,14 +12382,14 @@ pub mod tests {
|
||||||
let offset = 99;
|
let offset = 99;
|
||||||
let stored_size = 101;
|
let stored_size = 101;
|
||||||
let hash = Hash::new_unique();
|
let hash = Hash::new_unique();
|
||||||
let stored_account = StoredAccountMeta {
|
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta,
|
meta: &meta,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
assert!(accounts_equal(&account, &stored_account));
|
assert!(accounts_equal(&account, &stored_account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12426,14 +12426,14 @@ pub mod tests {
|
||||||
let (slot, meta, account_meta, data, offset, hash): InputTuple =
|
let (slot, meta, account_meta, data, offset, hash): InputTuple =
|
||||||
unsafe { std::mem::transmute::<InputBlob, InputTuple>(blob) };
|
unsafe { std::mem::transmute::<InputBlob, InputTuple>(blob) };
|
||||||
|
|
||||||
let stored_account = StoredAccountMeta {
|
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta,
|
meta: &meta,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size: CACHE_VIRTUAL_STORED_SIZE as usize,
|
stored_size: CACHE_VIRTUAL_STORED_SIZE as usize,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let account = stored_account.clone_account();
|
let account = stored_account.clone_account();
|
||||||
|
|
||||||
let expected_account_hash = if cfg!(debug_assertions) {
|
let expected_account_hash = if cfg!(debug_assertions) {
|
||||||
|
|
|
@ -138,9 +138,9 @@ impl AccountsDb {
|
||||||
// Passing 0 for everyone's write_version is sufficiently correct.
|
// Passing 0 for everyone's write_version is sufficiently correct.
|
||||||
let meta = StoredMeta {
|
let meta = StoredMeta {
|
||||||
write_version_obsolete: local_write_version,
|
write_version_obsolete: local_write_version,
|
||||||
..*account.meta
|
..*account.meta()
|
||||||
};
|
};
|
||||||
account.meta = &meta;
|
account.set_meta(&meta);
|
||||||
let mut measure_pure_notify = Measure::start("accountsdb-plugin-notifying-accounts");
|
let mut measure_pure_notify = Measure::start("accountsdb-plugin-notifying-accounts");
|
||||||
notifier.notify_account_restore_from_snapshot(slot, &account);
|
notifier.notify_account_restore_from_snapshot(slot, &account);
|
||||||
measure_pure_notify.stop();
|
measure_pure_notify.stop();
|
||||||
|
|
|
@ -770,7 +770,7 @@ pub mod tests {
|
||||||
},
|
},
|
||||||
INCLUDE_SLOT_IN_HASH_TESTS,
|
INCLUDE_SLOT_IN_HASH_TESTS,
|
||||||
},
|
},
|
||||||
append_vec::{aligned_stored_size, AppendVec},
|
append_vec::{aligned_stored_size, AppendVec, AppendVecStoredAccountMeta},
|
||||||
storable_accounts::StorableAccountsBySlot,
|
storable_accounts::StorableAccountsBySlot,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
|
@ -1618,7 +1618,7 @@ pub mod tests {
|
||||||
pubkey,
|
pubkey,
|
||||||
data_len: 43,
|
data_len: 43,
|
||||||
};
|
};
|
||||||
let account = StoredAccountMeta {
|
let account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &stored_meta,
|
meta: &stored_meta,
|
||||||
/// account data
|
/// account data
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
|
@ -1626,7 +1626,7 @@ pub mod tests {
|
||||||
offset,
|
offset,
|
||||||
stored_size: account_size,
|
stored_size: account_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
let map = vec![&account];
|
let map = vec![&account];
|
||||||
for (selector, available_bytes) in [
|
for (selector, available_bytes) in [
|
||||||
(StorageSelector::Primary, account_size),
|
(StorageSelector::Primary, account_size),
|
||||||
|
|
|
@ -8,13 +8,19 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
account_storage::meta::{
|
account_storage::meta::{
|
||||||
AccountMeta, StorableAccountsWithHashesAndWriteVersions, StoredAccountInfo,
|
AccountMeta, StorableAccountsWithHashesAndWriteVersions, StoredAccountInfo,
|
||||||
StoredAccountMeta, StoredMeta,
|
StoredAccountMeta, StoredMeta, StoredMetaWriteVersion,
|
||||||
},
|
},
|
||||||
storable_accounts::StorableAccounts,
|
storable_accounts::StorableAccounts,
|
||||||
},
|
},
|
||||||
log::*,
|
log::*,
|
||||||
memmap2::MmapMut,
|
memmap2::MmapMut,
|
||||||
solana_sdk::{account::ReadableAccount, clock::Slot, hash::Hash, pubkey::Pubkey},
|
solana_sdk::{
|
||||||
|
account::{Account, AccountSharedData, ReadableAccount},
|
||||||
|
clock::Slot,
|
||||||
|
hash::Hash,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
stake_history::Epoch,
|
||||||
|
},
|
||||||
std::{
|
std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
|
@ -89,6 +95,108 @@ pub enum MatchAccountOwnerError {
|
||||||
UnableToLoad,
|
UnableToLoad,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// References to account data stored elsewhere. Getting an `Account` requires cloning
|
||||||
|
/// (see `StoredAccountMeta::clone_account()`).
|
||||||
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
pub struct AppendVecStoredAccountMeta<'a> {
|
||||||
|
pub meta: &'a StoredMeta,
|
||||||
|
/// account data
|
||||||
|
pub account_meta: &'a AccountMeta,
|
||||||
|
pub(crate) data: &'a [u8],
|
||||||
|
pub(crate) offset: usize,
|
||||||
|
pub(crate) stored_size: usize,
|
||||||
|
pub(crate) hash: &'a Hash,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AppendVecStoredAccountMeta<'a> {
|
||||||
|
pub fn clone_account(&self) -> AccountSharedData {
|
||||||
|
AccountSharedData::from(Account {
|
||||||
|
lamports: self.account_meta.lamports,
|
||||||
|
owner: self.account_meta.owner,
|
||||||
|
executable: self.account_meta.executable,
|
||||||
|
rent_epoch: self.account_meta.rent_epoch,
|
||||||
|
data: self.data.to_vec(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pubkey(&self) -> &'a Pubkey {
|
||||||
|
&self.meta.pubkey
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self) -> &'a Hash {
|
||||||
|
self.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stored_size(&self) -> usize {
|
||||||
|
self.stored_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self) -> usize {
|
||||||
|
self.offset
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data(&self) -> &'a [u8] {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_len(&self) -> u64 {
|
||||||
|
self.meta.data_len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_version(&self) -> StoredMetaWriteVersion {
|
||||||
|
self.meta.write_version_obsolete
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn meta(&self) -> &StoredMeta {
|
||||||
|
self.meta
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_meta(&mut self, meta: &'a StoredMeta) {
|
||||||
|
self.meta = meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sanitize(&self) -> bool {
|
||||||
|
self.sanitize_executable() && self.sanitize_lamports()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_executable(&self) -> bool {
|
||||||
|
// Sanitize executable to ensure higher 7-bits are cleared correctly.
|
||||||
|
self.ref_executable_byte() & !1 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_lamports(&self) -> bool {
|
||||||
|
// Sanitize 0 lamports to ensure to be same as AccountSharedData::default()
|
||||||
|
self.account_meta.lamports != 0 || self.clone_account() == AccountSharedData::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_executable_byte(&self) -> &u8 {
|
||||||
|
// Use extra references to avoid value silently clamped to 1 (=true) and 0 (=false)
|
||||||
|
// Yes, this really happens; see test_new_from_file_crafted_executable
|
||||||
|
let executable_bool: &bool = &self.account_meta.executable;
|
||||||
|
// UNSAFE: Force to interpret mmap-backed bool as u8 to really read the actual memory content
|
||||||
|
let executable_byte: &u8 = unsafe { &*(executable_bool as *const bool as *const u8) };
|
||||||
|
executable_byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ReadableAccount for AppendVecStoredAccountMeta<'a> {
|
||||||
|
fn lamports(&self) -> u64 {
|
||||||
|
self.account_meta.lamports
|
||||||
|
}
|
||||||
|
fn data(&self) -> &[u8] {
|
||||||
|
self.data()
|
||||||
|
}
|
||||||
|
fn owner(&self) -> &Pubkey {
|
||||||
|
&self.account_meta.owner
|
||||||
|
}
|
||||||
|
fn executable(&self) -> bool {
|
||||||
|
self.account_meta.executable
|
||||||
|
}
|
||||||
|
fn rent_epoch(&self) -> Epoch {
|
||||||
|
self.account_meta.rent_epoch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A thread-safe, file-backed block of memory used to store `Account` instances. Append operations
|
/// A thread-safe, file-backed block of memory used to store `Account` instances. Append operations
|
||||||
/// are serialized such that only one thread updates the internal `append_lock` at a time. No
|
/// are serialized such that only one thread updates the internal `append_lock` at a time. No
|
||||||
/// restrictions are placed on reading. That is, one may read items from one thread while another
|
/// restrictions are placed on reading. That is, one may read items from one thread while another
|
||||||
|
@ -401,14 +509,14 @@ impl AppendVec {
|
||||||
let (data, next) = self.get_slice(next, meta.data_len as usize)?;
|
let (data, next) = self.get_slice(next, meta.data_len as usize)?;
|
||||||
let stored_size = next - offset;
|
let stored_size = next - offset;
|
||||||
Some((
|
Some((
|
||||||
StoredAccountMeta {
|
StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta,
|
meta,
|
||||||
account_meta,
|
account_meta,
|
||||||
data,
|
data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash,
|
hash,
|
||||||
},
|
}),
|
||||||
next,
|
next,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -450,7 +558,7 @@ impl AppendVec {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
) -> Option<(StoredMeta, solana_sdk::account::AccountSharedData)> {
|
) -> Option<(StoredMeta, solana_sdk::account::AccountSharedData)> {
|
||||||
let (stored_account, _) = self.get_account(offset)?;
|
let (stored_account, _) = self.get_account(offset)?;
|
||||||
let meta = stored_account.meta.clone();
|
let meta = stored_account.meta().clone();
|
||||||
Some((meta, stored_account.clone_account()))
|
Some((meta, stored_account.clone_account()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,6 +701,14 @@ pub mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StoredAccountMeta<'a> {
|
impl<'a> StoredAccountMeta<'a> {
|
||||||
|
pub(crate) fn ref_executable_byte(&self) -> &u8 {
|
||||||
|
match self {
|
||||||
|
Self::AppendVec(av) => av.ref_executable_byte(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AppendVecStoredAccountMeta<'a> {
|
||||||
#[allow(clippy::cast_ref_to_mut)]
|
#[allow(clippy::cast_ref_to_mut)]
|
||||||
fn set_data_len_unsafe(&self, new_data_len: u64) {
|
fn set_data_len_unsafe(&self, new_data_len: u64) {
|
||||||
// UNSAFE: cast away & (= const ref) to &mut to force to mutate append-only (=read-only) AppendVec
|
// UNSAFE: cast away & (= const ref) to &mut to force to mutate append-only (=read-only) AppendVec
|
||||||
|
@ -1071,7 +1187,7 @@ pub mod tests {
|
||||||
av.append_account_test(&create_test_account(10)).unwrap();
|
av.append_account_test(&create_test_account(10)).unwrap();
|
||||||
|
|
||||||
let accounts = av.accounts(0);
|
let accounts = av.accounts(0);
|
||||||
let account = accounts.first().unwrap();
|
let StoredAccountMeta::AppendVec(account) = accounts.first().unwrap();
|
||||||
account.set_data_len_unsafe(crafted_data_len);
|
account.set_data_len_unsafe(crafted_data_len);
|
||||||
assert_eq!(account.data_len(), crafted_data_len);
|
assert_eq!(account.data_len(), crafted_data_len);
|
||||||
|
|
||||||
|
@ -1098,7 +1214,7 @@ pub mod tests {
|
||||||
av.append_account_test(&create_test_account(10)).unwrap();
|
av.append_account_test(&create_test_account(10)).unwrap();
|
||||||
|
|
||||||
let accounts = av.accounts(0);
|
let accounts = av.accounts(0);
|
||||||
let account = accounts.first().unwrap();
|
let StoredAccountMeta::AppendVec(account) = accounts.first().unwrap();
|
||||||
account.set_data_len_unsafe(too_large_data_len);
|
account.set_data_len_unsafe(too_large_data_len);
|
||||||
assert_eq!(account.data_len(), too_large_data_len);
|
assert_eq!(account.data_len(), too_large_data_len);
|
||||||
|
|
||||||
|
@ -1133,14 +1249,14 @@ pub mod tests {
|
||||||
assert_eq!(*accounts[0].ref_executable_byte(), 0);
|
assert_eq!(*accounts[0].ref_executable_byte(), 0);
|
||||||
assert_eq!(*accounts[1].ref_executable_byte(), 1);
|
assert_eq!(*accounts[1].ref_executable_byte(), 1);
|
||||||
|
|
||||||
let account = &accounts[0];
|
let StoredAccountMeta::AppendVec(account) = &accounts[0];
|
||||||
let crafted_executable = u8::max_value() - 1;
|
let crafted_executable = u8::max_value() - 1;
|
||||||
|
|
||||||
account.set_executable_as_byte(crafted_executable);
|
account.set_executable_as_byte(crafted_executable);
|
||||||
|
|
||||||
// reload crafted accounts
|
// reload crafted accounts
|
||||||
let accounts = av.accounts(0);
|
let accounts = av.accounts(0);
|
||||||
let account = accounts.first().unwrap();
|
let StoredAccountMeta::AppendVec(account) = accounts.first().unwrap();
|
||||||
|
|
||||||
// upper 7-bits are not 0, so sanitization should fail
|
// upper 7-bits are not 0, so sanitization should fail
|
||||||
assert!(!account.sanitize_executable());
|
assert!(!account.sanitize_executable());
|
||||||
|
|
|
@ -306,6 +306,7 @@ pub mod tests {
|
||||||
crate::{
|
crate::{
|
||||||
account_storage::meta::{AccountMeta, StoredAccountMeta, StoredMeta},
|
account_storage::meta::{AccountMeta, StoredAccountMeta, StoredMeta},
|
||||||
accounts_db::INCLUDE_SLOT_IN_HASH_TESTS,
|
accounts_db::INCLUDE_SLOT_IN_HASH_TESTS,
|
||||||
|
append_vec::AppendVecStoredAccountMeta,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{accounts_equal, AccountSharedData, WritableAccount},
|
account::{accounts_equal, AccountSharedData, WritableAccount},
|
||||||
|
@ -353,14 +354,14 @@ pub mod tests {
|
||||||
let offset = 99;
|
let offset = 99;
|
||||||
let stored_size = 101;
|
let stored_size = 101;
|
||||||
let hash = Hash::new_unique();
|
let hash = Hash::new_unique();
|
||||||
let stored_account = StoredAccountMeta {
|
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &meta,
|
meta: &meta,
|
||||||
account_meta: &account_meta,
|
account_meta: &account_meta,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
};
|
});
|
||||||
|
|
||||||
let test3 = (
|
let test3 = (
|
||||||
slot,
|
slot,
|
||||||
|
@ -411,14 +412,14 @@ pub mod tests {
|
||||||
for entry in 0..entries {
|
for entry in 0..entries {
|
||||||
let offset = 99;
|
let offset = 99;
|
||||||
let stored_size = 101;
|
let stored_size = 101;
|
||||||
raw2.push(StoredAccountMeta {
|
raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &raw[entry as usize].3,
|
meta: &raw[entry as usize].3,
|
||||||
account_meta: &raw[entry as usize].4,
|
account_meta: &raw[entry as usize].4,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hash,
|
hash: &hash,
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut two = Vec::new();
|
let mut two = Vec::new();
|
||||||
|
@ -508,14 +509,14 @@ pub mod tests {
|
||||||
for entry in 0..entries {
|
for entry in 0..entries {
|
||||||
let offset = 99;
|
let offset = 99;
|
||||||
let stored_size = 101;
|
let stored_size = 101;
|
||||||
raw2.push(StoredAccountMeta {
|
raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||||
meta: &raw[entry as usize].2,
|
meta: &raw[entry as usize].2,
|
||||||
account_meta: &raw[entry as usize].3,
|
account_meta: &raw[entry as usize].3,
|
||||||
data: &data,
|
data: &data,
|
||||||
offset,
|
offset,
|
||||||
stored_size,
|
stored_size,
|
||||||
hash: &hashes[entry as usize],
|
hash: &hashes[entry as usize],
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
let raw2_refs = raw2.iter().collect::<Vec<_>>();
|
let raw2_refs = raw2.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue