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 {
|
||||
crate::storable_accounts::StorableAccounts,
|
||||
crate::{append_vec::AppendVecStoredAccountMeta, storable_accounts::StorableAccounts},
|
||||
solana_sdk::{
|
||||
account::{Account, AccountSharedData, ReadableAccount},
|
||||
account::{AccountSharedData, ReadableAccount},
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
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
|
||||
/// (see `StoredAccountMeta::clone_account()`).
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct StoredAccountMeta<'a> {
|
||||
pub(crate) meta: &'a StoredMeta,
|
||||
/// 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,
|
||||
pub enum StoredAccountMeta<'a> {
|
||||
AppendVec(AppendVecStoredAccountMeta<'a>),
|
||||
}
|
||||
|
||||
impl<'a> StoredAccountMeta<'a> {
|
||||
/// Return a new Account by copying all the data referenced by the `StoredAccountMeta`.
|
||||
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(),
|
||||
})
|
||||
match self {
|
||||
Self::AppendVec(av) => av.clone_account(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pubkey(&self) -> &'a Pubkey {
|
||||
&self.meta.pubkey
|
||||
match self {
|
||||
Self::AppendVec(av) => av.pubkey(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hash(&self) -> &'a Hash {
|
||||
self.hash
|
||||
match self {
|
||||
Self::AppendVec(av) => av.hash(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stored_size(&self) -> usize {
|
||||
self.stored_size
|
||||
match self {
|
||||
Self::AppendVec(av) => av.stored_size(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
self.offset
|
||||
match self {
|
||||
Self::AppendVec(av) => av.offset(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &'a [u8] {
|
||||
self.data
|
||||
match self {
|
||||
Self::AppendVec(av) => av.data(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_len(&self) -> u64 {
|
||||
self.meta.data_len
|
||||
match self {
|
||||
Self::AppendVec(av) => av.data_len(),
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.sanitize_executable() && self.sanitize_lamports()
|
||||
}
|
||||
|
||||
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
|
||||
match self {
|
||||
Self::AppendVec(av) => av.sanitize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ReadableAccount for StoredAccountMeta<'a> {
|
||||
fn lamports(&self) -> u64 {
|
||||
self.account_meta.lamports
|
||||
match self {
|
||||
Self::AppendVec(av) => av.lamports(),
|
||||
}
|
||||
}
|
||||
fn data(&self) -> &[u8] {
|
||||
self.data()
|
||||
match self {
|
||||
Self::AppendVec(av) => av.data(),
|
||||
}
|
||||
}
|
||||
fn owner(&self) -> &Pubkey {
|
||||
&self.account_meta.owner
|
||||
match self {
|
||||
Self::AppendVec(av) => av.owner(),
|
||||
}
|
||||
}
|
||||
fn executable(&self) -> bool {
|
||||
self.account_meta.executable
|
||||
match self {
|
||||
Self::AppendVec(av) => av.executable(),
|
||||
}
|
||||
}
|
||||
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 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);
|
||||
if count == 0 {
|
||||
self.dirty_stores.insert(*slot, store.clone());
|
||||
|
@ -9454,7 +9454,7 @@ pub mod tests {
|
|||
tests::*, AccountIndex, AccountSecondaryIndexes,
|
||||
AccountSecondaryIndexesIncludeExclude, ReadAccountMapEntry, RefCount,
|
||||
},
|
||||
append_vec::test_utils::TempFile,
|
||||
append_vec::{test_utils::TempFile, AppendVecStoredAccountMeta},
|
||||
cache_hash_data_stats::CacheHashDataStats,
|
||||
inline_spl_token,
|
||||
secondary_index::MAX_NUM_LARGEST_INDEX_KEYS_RETURNED,
|
||||
|
@ -9664,7 +9664,7 @@ pub mod tests {
|
|||
pubkey,
|
||||
data_len: 43,
|
||||
};
|
||||
let account = StoredAccountMeta {
|
||||
let account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &stored_meta,
|
||||
/// account data
|
||||
account_meta: &account_meta,
|
||||
|
@ -9672,7 +9672,7 @@ pub mod tests {
|
|||
offset,
|
||||
stored_size: account_size,
|
||||
hash: &hash,
|
||||
};
|
||||
});
|
||||
let map = vec![&account];
|
||||
let alive_total_bytes = account.stored_size();
|
||||
let to_store = AccountsToStore::new(available_bytes, &map, alive_total_bytes, slot0);
|
||||
|
@ -9760,38 +9760,38 @@ pub mod tests {
|
|||
let offset = 99;
|
||||
let stored_size = 101;
|
||||
let hash = Hash::new_unique();
|
||||
let stored_account = StoredAccountMeta {
|
||||
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
};
|
||||
let stored_account2 = StoredAccountMeta {
|
||||
});
|
||||
let stored_account2 = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta2,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
};
|
||||
let stored_account3 = StoredAccountMeta {
|
||||
});
|
||||
let stored_account3 = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta3,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
};
|
||||
let stored_account4 = StoredAccountMeta {
|
||||
});
|
||||
let stored_account4 = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta4,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
};
|
||||
});
|
||||
let mut existing_ancient_pubkeys = HashSet::default();
|
||||
let accounts = [&stored_account];
|
||||
// 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 stored_size = 101;
|
||||
let hash = Hash::new_unique();
|
||||
let stored_account = StoredAccountMeta {
|
||||
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
};
|
||||
});
|
||||
assert!(accounts_equal(&account, &stored_account));
|
||||
}
|
||||
|
||||
|
@ -12426,14 +12426,14 @@ pub mod tests {
|
|||
let (slot, meta, account_meta, data, offset, hash): InputTuple =
|
||||
unsafe { std::mem::transmute::<InputBlob, InputTuple>(blob) };
|
||||
|
||||
let stored_account = StoredAccountMeta {
|
||||
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size: CACHE_VIRTUAL_STORED_SIZE as usize,
|
||||
hash: &hash,
|
||||
};
|
||||
});
|
||||
let account = stored_account.clone_account();
|
||||
|
||||
let expected_account_hash = if cfg!(debug_assertions) {
|
||||
|
|
|
@ -138,9 +138,9 @@ impl AccountsDb {
|
|||
// Passing 0 for everyone's write_version is sufficiently correct.
|
||||
let meta = StoredMeta {
|
||||
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");
|
||||
notifier.notify_account_restore_from_snapshot(slot, &account);
|
||||
measure_pure_notify.stop();
|
||||
|
|
|
@ -770,7 +770,7 @@ pub mod tests {
|
|||
},
|
||||
INCLUDE_SLOT_IN_HASH_TESTS,
|
||||
},
|
||||
append_vec::{aligned_stored_size, AppendVec},
|
||||
append_vec::{aligned_stored_size, AppendVec, AppendVecStoredAccountMeta},
|
||||
storable_accounts::StorableAccountsBySlot,
|
||||
},
|
||||
solana_sdk::{
|
||||
|
@ -1618,7 +1618,7 @@ pub mod tests {
|
|||
pubkey,
|
||||
data_len: 43,
|
||||
};
|
||||
let account = StoredAccountMeta {
|
||||
let account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &stored_meta,
|
||||
/// account data
|
||||
account_meta: &account_meta,
|
||||
|
@ -1626,7 +1626,7 @@ pub mod tests {
|
|||
offset,
|
||||
stored_size: account_size,
|
||||
hash: &hash,
|
||||
};
|
||||
});
|
||||
let map = vec![&account];
|
||||
for (selector, available_bytes) in [
|
||||
(StorageSelector::Primary, account_size),
|
||||
|
|
|
@ -8,13 +8,19 @@ use {
|
|||
crate::{
|
||||
account_storage::meta::{
|
||||
AccountMeta, StorableAccountsWithHashesAndWriteVersions, StoredAccountInfo,
|
||||
StoredAccountMeta, StoredMeta,
|
||||
StoredAccountMeta, StoredMeta, StoredMetaWriteVersion,
|
||||
},
|
||||
storable_accounts::StorableAccounts,
|
||||
},
|
||||
log::*,
|
||||
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::{
|
||||
borrow::Borrow,
|
||||
convert::TryFrom,
|
||||
|
@ -89,6 +95,108 @@ pub enum MatchAccountOwnerError {
|
|||
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
|
||||
/// 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
|
||||
|
@ -401,14 +509,14 @@ impl AppendVec {
|
|||
let (data, next) = self.get_slice(next, meta.data_len as usize)?;
|
||||
let stored_size = next - offset;
|
||||
Some((
|
||||
StoredAccountMeta {
|
||||
StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta,
|
||||
account_meta,
|
||||
data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash,
|
||||
},
|
||||
}),
|
||||
next,
|
||||
))
|
||||
}
|
||||
|
@ -450,7 +558,7 @@ impl AppendVec {
|
|||
offset: usize,
|
||||
) -> Option<(StoredMeta, solana_sdk::account::AccountSharedData)> {
|
||||
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()))
|
||||
}
|
||||
|
||||
|
@ -593,6 +701,14 @@ pub mod tests {
|
|||
}
|
||||
|
||||
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)]
|
||||
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
|
||||
|
@ -1071,7 +1187,7 @@ pub mod tests {
|
|||
av.append_account_test(&create_test_account(10)).unwrap();
|
||||
|
||||
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);
|
||||
assert_eq!(account.data_len(), crafted_data_len);
|
||||
|
||||
|
@ -1098,7 +1214,7 @@ pub mod tests {
|
|||
av.append_account_test(&create_test_account(10)).unwrap();
|
||||
|
||||
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);
|
||||
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[1].ref_executable_byte(), 1);
|
||||
|
||||
let account = &accounts[0];
|
||||
let StoredAccountMeta::AppendVec(account) = &accounts[0];
|
||||
let crafted_executable = u8::max_value() - 1;
|
||||
|
||||
account.set_executable_as_byte(crafted_executable);
|
||||
|
||||
// reload crafted accounts
|
||||
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
|
||||
assert!(!account.sanitize_executable());
|
||||
|
|
|
@ -306,6 +306,7 @@ pub mod tests {
|
|||
crate::{
|
||||
account_storage::meta::{AccountMeta, StoredAccountMeta, StoredMeta},
|
||||
accounts_db::INCLUDE_SLOT_IN_HASH_TESTS,
|
||||
append_vec::AppendVecStoredAccountMeta,
|
||||
},
|
||||
solana_sdk::{
|
||||
account::{accounts_equal, AccountSharedData, WritableAccount},
|
||||
|
@ -353,14 +354,14 @@ pub mod tests {
|
|||
let offset = 99;
|
||||
let stored_size = 101;
|
||||
let hash = Hash::new_unique();
|
||||
let stored_account = StoredAccountMeta {
|
||||
let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &meta,
|
||||
account_meta: &account_meta,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
};
|
||||
});
|
||||
|
||||
let test3 = (
|
||||
slot,
|
||||
|
@ -411,14 +412,14 @@ pub mod tests {
|
|||
for entry in 0..entries {
|
||||
let offset = 99;
|
||||
let stored_size = 101;
|
||||
raw2.push(StoredAccountMeta {
|
||||
raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &raw[entry as usize].3,
|
||||
account_meta: &raw[entry as usize].4,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hash,
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
let mut two = Vec::new();
|
||||
|
@ -508,14 +509,14 @@ pub mod tests {
|
|||
for entry in 0..entries {
|
||||
let offset = 99;
|
||||
let stored_size = 101;
|
||||
raw2.push(StoredAccountMeta {
|
||||
raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
|
||||
meta: &raw[entry as usize].2,
|
||||
account_meta: &raw[entry as usize].3,
|
||||
data: &data,
|
||||
offset,
|
||||
stored_size,
|
||||
hash: &hashes[entry as usize],
|
||||
});
|
||||
}));
|
||||
}
|
||||
let raw2_refs = raw2.iter().collect::<Vec<_>>();
|
||||
|
||||
|
|
Loading…
Reference in New Issue