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:
Yueh-Hsuan Chiang 2023-03-09 15:52:51 -08:00 committed by GitHub
parent b0112a5f43
commit 71b6370426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 211 additions and 85 deletions

View File

@ -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(),
}
} }
} }

View File

@ -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) {

View File

@ -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();

View File

@ -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),

View File

@ -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());

View File

@ -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<_>>();