1use {
8 crate::storable_accounts::StorableAccounts,
9 log::*,
10 memmap2::MmapMut,
11 serde::{Deserialize, Serialize},
12 solana_sdk::{
13 account::{Account, AccountSharedData, ReadableAccount},
14 clock::{Epoch, Slot},
15 hash::Hash,
16 pubkey::Pubkey,
17 },
18 std::{
19 borrow::Borrow,
20 convert::TryFrom,
21 fs::{remove_file, OpenOptions},
22 io::{self, Seek, SeekFrom, Write},
23 marker::PhantomData,
24 mem,
25 path::{Path, PathBuf},
26 sync::{
27 atomic::{AtomicU64, AtomicUsize, Ordering},
28 Mutex,
29 },
30 },
31 thiserror::Error,
32};
33
34pub mod test_utils;
35
36pub const ALIGN_BOUNDARY_OFFSET: usize = mem::size_of::<u64>();
39macro_rules! u64_align {
40 ($addr: expr) => {
41 ($addr + (ALIGN_BOUNDARY_OFFSET - 1)) & !(ALIGN_BOUNDARY_OFFSET - 1)
42 };
43}
44
45pub const STORE_META_OVERHEAD: usize = 136;
48
49pub fn aligned_stored_size(data_len: usize) -> usize {
53 u64_align!(STORE_META_OVERHEAD + data_len)
54}
55
56pub const MAXIMUM_APPEND_VEC_FILE_SIZE: u64 = 16 * 1024 * 1024 * 1024; pub type StoredMetaWriteVersion = u64;
59
60pub struct StorableAccountsWithHashesAndWriteVersions<
66 'a: 'b,
67 'b,
68 T: ReadableAccount + Sync + 'b,
69 U: StorableAccounts<'a, T>,
70 V: Borrow<Hash>,
71> {
72 accounts: &'b U,
76 hashes_and_write_versions: Option<(Vec<V>, Vec<StoredMetaWriteVersion>)>,
78 _phantom: PhantomData<&'a T>,
79}
80
81impl<'a: 'b, 'b, T: ReadableAccount + Sync + 'b, U: StorableAccounts<'a, T>, V: Borrow<Hash>>
82 StorableAccountsWithHashesAndWriteVersions<'a, 'b, T, U, V>
83{
84 pub fn new(accounts: &'b U) -> Self {
86 assert!(accounts.has_hash_and_write_version());
87 Self {
88 accounts,
89 hashes_and_write_versions: None,
90 _phantom: PhantomData,
91 }
92 }
93 pub fn new_with_hashes_and_write_versions(
96 accounts: &'b U,
97 hashes: Vec<V>,
98 write_versions: Vec<StoredMetaWriteVersion>,
99 ) -> Self {
100 assert!(!accounts.has_hash_and_write_version());
101 assert_eq!(accounts.len(), hashes.len());
102 assert_eq!(write_versions.len(), hashes.len());
103 Self {
104 accounts,
105 hashes_and_write_versions: Some((hashes, write_versions)),
106 _phantom: PhantomData,
107 }
108 }
109
110 pub fn get(&self, index: usize) -> (Option<&T>, &Pubkey, &Hash, StoredMetaWriteVersion) {
112 let account = self.accounts.account_default_if_zero_lamport(index);
113 let pubkey = self.accounts.pubkey(index);
114 let (hash, write_version) = if self.accounts.has_hash_and_write_version() {
115 (
116 self.accounts.hash(index),
117 self.accounts.write_version(index),
118 )
119 } else {
120 let item = self.hashes_and_write_versions.as_ref().unwrap();
121 (item.0[index].borrow(), item.1[index])
122 };
123 (account, pubkey, hash, write_version)
124 }
125
126 pub fn account(&self, index: usize) -> Option<&T> {
130 self.accounts.account_default_if_zero_lamport(index)
131 }
132
133 pub fn len(&self) -> usize {
135 self.accounts.len()
136 }
137
138 pub fn is_empty(&self) -> bool {
139 self.len() == 0
140 }
141}
142
143#[derive(Clone, PartialEq, Eq, Debug)]
147#[repr(C)]
148pub struct StoredMeta {
149 pub write_version_obsolete: StoredMetaWriteVersion,
154 pub data_len: u64,
155 pub pubkey: Pubkey,
157}
158
159#[derive(Clone, Debug, Default, Eq, PartialEq)]
162#[repr(C)]
163pub struct AccountMeta {
164 pub lamports: u64,
166 pub rent_epoch: Epoch,
168 pub owner: Pubkey,
170 pub executable: bool,
172}
173
174impl<'a, T: ReadableAccount> From<&'a T> for AccountMeta {
175 fn from(account: &'a T) -> Self {
176 Self {
177 lamports: account.lamports(),
178 owner: *account.owner(),
179 executable: account.executable(),
180 rent_epoch: account.rent_epoch(),
181 }
182 }
183}
184
185impl<'a, T: ReadableAccount> From<Option<&'a T>> for AccountMeta {
186 fn from(account: Option<&'a T>) -> Self {
187 match account {
188 Some(account) => AccountMeta::from(account),
189 None => AccountMeta::default(),
190 }
191 }
192}
193pub struct StoredAccountMetaClone<'a> {
194 pub meta: StoredMeta,
195 pub account_meta: AccountMeta,
197 pub data: &'a [u8],
198 pub offset: usize,
199 pub stored_size: usize,
200 pub hash: Hash,
201}
202#[derive(PartialEq, Eq, Debug)]
205pub struct StoredAccountMeta<'a> {
206 pub meta: &'a StoredMeta,
207 pub account_meta: &'a AccountMeta,
209 pub data: &'a [u8],
210 pub offset: usize,
211 pub stored_size: usize,
212 pub hash: &'a Hash,
213}
214
215impl<'a> StoredAccountMeta<'a> {
216 pub fn clone_account(&self) -> AccountSharedData {
218 AccountSharedData::from(Account {
219 lamports: self.account_meta.lamports,
220 owner: self.account_meta.owner,
221 executable: self.account_meta.executable,
222 rent_epoch: self.account_meta.rent_epoch,
223 data: self.data.to_vec(),
224 })
225 }
226
227 pub fn pubkey(&self) -> &Pubkey {
228 &self.meta.pubkey
229 }
230
231 fn sanitize(&self) -> bool {
232 self.sanitize_executable() && self.sanitize_lamports()
233 }
234
235 fn sanitize_executable(&self) -> bool {
236 self.ref_executable_byte() & !1 == 0
238 }
239
240 fn sanitize_lamports(&self) -> bool {
241 self.account_meta.lamports != 0 || self.clone_account() == AccountSharedData::default()
243 }
244
245 fn ref_executable_byte(&self) -> &u8 {
246 let executable_bool: &bool = &self.account_meta.executable;
249 let executable_byte: &u8 = unsafe { &*(executable_bool as *const bool as *const u8) };
251 executable_byte
252 }
253}
254
255pub struct AppendVecAccountsIter<'a> {
256 append_vec: &'a AppendVec,
257 offset: usize,
258}
259
260impl<'a> AppendVecAccountsIter<'a> {
261 pub fn new(append_vec: &'a AppendVec) -> Self {
262 Self {
263 append_vec,
264 offset: 0,
265 }
266 }
267}
268
269impl<'a> Iterator for AppendVecAccountsIter<'a> {
270 type Item = StoredAccountMeta<'a>;
271
272 fn next(&mut self) -> Option<Self::Item> {
273 if let Some((account, next_offset)) = self.append_vec.get_account(self.offset) {
274 self.offset = next_offset;
275 Some(account)
276 } else {
277 None
278 }
279 }
280}
281
282#[derive(Error, Debug, PartialEq, Eq)]
283pub enum MatchAccountOwnerError {
284 #[error("The account owner does not match with the provided list")]
285 NoMatch,
286 #[error("Unable to load the account")]
287 UnableToLoad,
288}
289
290#[derive(Debug, AbiExample)]
295pub struct AppendVec {
296 path: PathBuf,
298
299 map: MmapMut,
301
302 append_lock: Mutex<()>,
304
305 current_len: AtomicUsize,
307
308 file_size: u64,
310
311 remove_on_drop: bool,
313}
314
315lazy_static! {
316 pub static ref APPEND_VEC_MMAPPED_FILES_OPEN: AtomicU64 = AtomicU64::default();
317}
318
319impl Drop for AppendVec {
320 fn drop(&mut self) {
321 if self.remove_on_drop {
322 APPEND_VEC_MMAPPED_FILES_OPEN.fetch_sub(1, Ordering::Relaxed);
323 if let Err(_e) = remove_file(&self.path) {
324 inc_new_counter_info!("append_vec_drop_fail", 1);
329 }
330 }
331 }
332}
333
334impl AppendVec {
335 pub fn new(file: &Path, create: bool, size: usize) -> Self {
336 let initial_len = 0;
337 AppendVec::sanitize_len_and_size(initial_len, size).unwrap();
338
339 if create {
340 let _ignored = remove_file(file);
341 }
342
343 let mut data = OpenOptions::new()
344 .read(true)
345 .write(true)
346 .create(create)
347 .open(file)
348 .map_err(|e| {
349 panic!(
350 "Unable to {} data file {} in current dir({:?}): {:?}",
351 if create { "create" } else { "open" },
352 file.display(),
353 std::env::current_dir(),
354 e
355 );
356 })
357 .unwrap();
358
359 data.seek(SeekFrom::Start((size - 1) as u64)).unwrap();
363 data.write_all(&[0]).unwrap();
364 data.rewind().unwrap();
365 data.flush().unwrap();
366
367 let map = unsafe { MmapMut::map_mut(&data) };
369 let map = map.unwrap_or_else(|e| {
370 error!(
371 "Failed to map the data file (size: {}): {}.\n
372 Please increase sysctl vm.max_map_count or equivalent for your platform.",
373 size, e
374 );
375 std::process::exit(1);
376 });
377 APPEND_VEC_MMAPPED_FILES_OPEN.fetch_add(1, Ordering::Relaxed);
378
379 AppendVec {
380 path: file.to_path_buf(),
381 map,
382 append_lock: Mutex::new(()),
385 current_len: AtomicUsize::new(initial_len),
386 file_size: size as u64,
387 remove_on_drop: true,
388 }
389 }
390
391 pub fn set_no_remove_on_drop(&mut self) {
392 self.remove_on_drop = false;
393 }
394
395 fn sanitize_len_and_size(current_len: usize, file_size: usize) -> io::Result<()> {
396 if file_size == 0 {
397 Err(std::io::Error::new(
398 std::io::ErrorKind::Other,
399 format!("too small file size {file_size} for AppendVec"),
400 ))
401 } else if usize::try_from(MAXIMUM_APPEND_VEC_FILE_SIZE)
402 .map(|max| file_size > max)
403 .unwrap_or(true)
404 {
405 Err(std::io::Error::new(
406 std::io::ErrorKind::Other,
407 format!("too large file size {file_size} for AppendVec"),
408 ))
409 } else if current_len > file_size {
410 Err(std::io::Error::new(
411 std::io::ErrorKind::Other,
412 format!("current_len is larger than file size ({file_size})"),
413 ))
414 } else {
415 Ok(())
416 }
417 }
418
419 pub fn flush(&self) -> io::Result<()> {
420 self.map.flush()
421 }
422
423 pub fn reset(&self) {
424 let _lock = self.append_lock.lock().unwrap();
427 self.current_len.store(0, Ordering::Release);
428 }
429
430 pub fn remaining_bytes(&self) -> u64 {
432 (self.capacity()).saturating_sub(self.len() as u64)
433 }
434
435 pub fn len(&self) -> usize {
436 self.current_len.load(Ordering::Acquire)
437 }
438
439 pub fn is_empty(&self) -> bool {
440 self.len() == 0
441 }
442
443 pub fn capacity(&self) -> u64 {
444 self.file_size
445 }
446
447 pub fn file_name(slot: Slot, id: impl std::fmt::Display) -> String {
448 format!("{slot}.{id}")
449 }
450
451 pub fn new_from_file<P: AsRef<Path>>(path: P, current_len: usize) -> io::Result<(Self, usize)> {
452 let new = Self::new_from_file_unchecked(&path, current_len)?;
453
454 let (sanitized, num_accounts) = new.sanitize_layout_and_length();
455 if !sanitized {
456 let err_msg = format!(
459 "incorrect layout/length/data in the appendvec at path {}",
460 path.as_ref().display()
461 );
462 return Err(std::io::Error::new(std::io::ErrorKind::Other, err_msg));
463 }
464
465 Ok((new, num_accounts))
466 }
467
468 pub fn new_from_file_unchecked<P: AsRef<Path>>(
470 path: P,
471 current_len: usize,
472 ) -> io::Result<Self> {
473 let file_size = std::fs::metadata(&path)?.len();
474 Self::sanitize_len_and_size(current_len, file_size as usize)?;
475
476 let data = OpenOptions::new()
477 .read(true)
478 .write(true)
479 .create(false)
480 .open(&path)?;
481
482 let map = unsafe {
483 let result = MmapMut::map_mut(&data);
484 if result.is_err() {
485 info!("memory map error: {:?}. This may be because vm.max_map_count is not set correctly.", result);
487 }
488 result?
489 };
490 APPEND_VEC_MMAPPED_FILES_OPEN.fetch_add(1, Ordering::Relaxed);
491
492 Ok(AppendVec {
493 path: path.as_ref().to_path_buf(),
494 map,
495 append_lock: Mutex::new(()),
496 current_len: AtomicUsize::new(current_len),
497 file_size,
498 remove_on_drop: true,
499 })
500 }
501
502 fn sanitize_layout_and_length(&self) -> (bool, usize) {
503 let mut offset = 0;
504
505 let mut num_accounts = 0;
511 while let Some((account, next_offset)) = self.get_account(offset) {
512 if !account.sanitize() {
513 return (false, num_accounts);
514 }
515 offset = next_offset;
516 num_accounts += 1;
517 }
518 let aligned_current_len = u64_align!(self.current_len.load(Ordering::Acquire));
519
520 (offset == aligned_current_len, num_accounts)
521 }
522
523 fn get_slice(&self, offset: usize, size: usize) -> Option<(&[u8], usize)> {
528 let (next, overflow) = offset.overflowing_add(size);
529 if overflow || next > self.len() {
530 return None;
531 }
532 let data = &self.map[offset..next];
533 let next = u64_align!(next);
534
535 Some((
536 unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, size) },
539 next,
540 ))
541 }
542
543 fn append_ptr(&self, offset: &mut usize, src: *const u8, len: usize) {
546 let pos = u64_align!(*offset);
547 let data = &self.map[pos..(pos + len)];
548 unsafe {
552 let dst = data.as_ptr() as *mut u8;
553 std::ptr::copy(src, dst, len);
554 };
555 *offset = pos + len;
556 }
557
558 fn append_ptrs_locked(&self, offset: &mut usize, vals: &[(*const u8, usize)]) -> Option<usize> {
563 let mut end = *offset;
564 for val in vals {
565 end = u64_align!(end);
566 end += val.1;
567 }
568
569 if (self.file_size as usize) < end {
570 return None;
571 }
572
573 let pos = u64_align!(*offset);
574 for val in vals {
575 self.append_ptr(offset, val.0, val.1)
576 }
577 self.current_len.store(*offset, Ordering::Release);
578 Some(pos)
579 }
580
581 fn get_type<'a, T>(&self, offset: usize) -> Option<(&'a T, usize)> {
585 let (data, next) = self.get_slice(offset, mem::size_of::<T>())?;
586 let ptr: *const T = data.as_ptr() as *const T;
587 Some((unsafe { &*ptr }, next))
590 }
591
592 pub fn get_account<'a>(&'a self, offset: usize) -> Option<(StoredAccountMeta<'a>, usize)> {
596 let (meta, next): (&'a StoredMeta, _) = self.get_type(offset)?;
597 let (account_meta, next): (&'a AccountMeta, _) = self.get_type(next)?;
598 let (hash, next): (&'a Hash, _) = self.get_type(next)?;
599 let (data, next) = self.get_slice(next, meta.data_len as usize)?;
600 let stored_size = next - offset;
601 Some((
602 StoredAccountMeta {
603 meta,
604 account_meta,
605 data,
606 offset,
607 stored_size,
608 hash,
609 },
610 next,
611 ))
612 }
613
614 fn get_account_meta<'a>(&self, offset: usize) -> Option<&'a AccountMeta> {
615 let offset = offset.checked_add(mem::size_of::<StoredMeta>())?;
617 offset.checked_add(ALIGN_BOUNDARY_OFFSET - 1)?;
619 let (account_meta, _): (&AccountMeta, _) = self.get_type(u64_align!(offset))?;
620 Some(account_meta)
621 }
622
623 pub fn account_matches_owners(
628 &self,
629 offset: usize,
630 owners: &[&Pubkey],
631 ) -> Result<usize, MatchAccountOwnerError> {
632 let account_meta = self
633 .get_account_meta(offset)
634 .ok_or(MatchAccountOwnerError::UnableToLoad)?;
635 if account_meta.lamports == 0 {
636 Err(MatchAccountOwnerError::NoMatch)
637 } else {
638 owners
639 .iter()
640 .position(|entry| &&account_meta.owner == entry)
641 .ok_or(MatchAccountOwnerError::NoMatch)
642 }
643 }
644
645 #[cfg(test)]
646 pub fn get_account_test(&self, offset: usize) -> Option<(StoredMeta, AccountSharedData)> {
647 let (stored_account, _) = self.get_account(offset)?;
648 let meta = stored_account.meta.clone();
649 Some((meta, stored_account.clone_account()))
650 }
651
652 pub fn get_path(&self) -> PathBuf {
653 self.path.clone()
654 }
655
656 pub fn account_iter(&self) -> AppendVecAccountsIter {
658 AppendVecAccountsIter::new(self)
659 }
660
661 pub fn accounts(&self, mut offset: usize) -> Vec<StoredAccountMeta> {
663 let mut accounts = vec![];
664 while let Some((account, next)) = self.get_account(offset) {
665 accounts.push(account);
666 offset = next;
667 }
668 accounts
669 }
670
671 pub fn append_accounts<
679 'a,
680 'b,
681 T: ReadableAccount + Sync,
682 U: StorableAccounts<'a, T>,
683 V: Borrow<Hash>,
684 >(
685 &self,
686 accounts: &StorableAccountsWithHashesAndWriteVersions<'a, 'b, T, U, V>,
687 skip: usize,
688 ) -> Option<Vec<usize>> {
689 let _lock = self.append_lock.lock().unwrap();
690 let mut offset = self.len();
691
692 let len = accounts.accounts.len();
693 let mut rv = Vec::with_capacity(len);
694 for i in skip..len {
695 let (account, pubkey, hash, write_version_obsolete) = accounts.get(i);
696 let account_meta = account
697 .map(|account| AccountMeta {
698 lamports: account.lamports(),
699 owner: *account.owner(),
700 rent_epoch: account.rent_epoch(),
701 executable: account.executable(),
702 })
703 .unwrap_or_default();
704
705 let stored_meta = StoredMeta {
706 pubkey: *pubkey,
707 data_len: account
708 .map(|account| account.data().len())
709 .unwrap_or_default() as u64,
710 write_version_obsolete,
711 };
712 let meta_ptr = &stored_meta as *const StoredMeta;
713 let account_meta_ptr = &account_meta as *const AccountMeta;
714 let data_len = stored_meta.data_len as usize;
715 let data_ptr = account
716 .map(|account| account.data())
717 .unwrap_or_default()
718 .as_ptr();
719 let hash_ptr = hash.as_ref().as_ptr();
720 let ptrs = [
721 (meta_ptr as *const u8, mem::size_of::<StoredMeta>()),
722 (account_meta_ptr as *const u8, mem::size_of::<AccountMeta>()),
723 (hash_ptr as *const u8, mem::size_of::<Hash>()),
724 (data_ptr, data_len),
725 ];
726 if let Some(res) = self.append_ptrs_locked(&mut offset, &ptrs) {
727 rv.push(res)
728 } else {
729 break;
730 }
731 }
732
733 if rv.is_empty() {
734 None
735 } else {
736 rv.push(u64_align!(offset));
739
740 Some(rv)
741 }
742 }
743}
744
745#[cfg(test)]
746pub mod tests {
747 use {
748 super::{test_utils::*, *},
749 crate::accounts_db::INCLUDE_SLOT_IN_HASH_TESTS,
750 assert_matches::assert_matches,
751 memoffset::offset_of,
752 rand::{thread_rng, Rng},
753 solana_sdk::{
754 account::{accounts_equal, WritableAccount},
755 timing::duration_as_ms,
756 },
757 std::time::Instant,
758 };
759
760 impl AppendVec {
761 pub(crate) fn set_current_len_for_tests(&self, len: usize) {
762 self.current_len.store(len, Ordering::Release);
763 }
764
765 fn append_account_test(&self, data: &(StoredMeta, AccountSharedData)) -> Option<usize> {
766 let slot_ignored = Slot::MAX;
767 let accounts = [(&data.0.pubkey, &data.1)];
768 let slice = &accounts[..];
769 let account_data = (slot_ignored, slice);
770 let hash = Hash::default();
771 let storable_accounts =
772 StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions(
773 &account_data,
774 vec![&hash],
775 vec![data.0.write_version_obsolete],
776 );
777
778 self.append_accounts(&storable_accounts, 0)
779 .map(|res| res[0])
780 }
781 }
782
783 impl<'a> StoredAccountMeta<'a> {
784 #[allow(clippy::cast_ref_to_mut)]
785 fn set_data_len_unsafe(&self, new_data_len: u64) {
786 unsafe {
788 *(&self.meta.data_len as *const u64 as *mut u64) = new_data_len;
789 }
790 }
791
792 fn get_executable_byte(&self) -> u8 {
793 let executable_bool: bool = self.account_meta.executable;
794 let executable_byte: u8 = unsafe { std::mem::transmute::<bool, u8>(executable_bool) };
796 executable_byte
797 }
798
799 #[allow(clippy::cast_ref_to_mut)]
800 fn set_executable_as_byte(&self, new_executable_byte: u8) {
801 unsafe {
803 *(&self.account_meta.executable as *const bool as *mut u8) = new_executable_byte;
804 }
805 }
806 }
807
808 static_assertions::const_assert_eq!(
809 STORE_META_OVERHEAD,
810 std::mem::size_of::<StoredMeta>()
811 + std::mem::size_of::<AccountMeta>()
812 + std::mem::size_of::<Hash>()
813 );
814
815 static_assertions::assert_eq_align!(u64, StoredMeta, AccountMeta);
817
818 #[test]
819 #[should_panic(expected = "assertion failed: accounts.has_hash_and_write_version()")]
820 fn test_storable_accounts_with_hashes_and_write_versions_new() {
821 let account = AccountSharedData::default();
822 let slot = 0 as Slot;
824 let pubkey = Pubkey::default();
825 StorableAccountsWithHashesAndWriteVersions::<'_, '_, _, _, &Hash>::new(&(
826 slot,
827 &[(&pubkey, &account)][..],
828 INCLUDE_SLOT_IN_HASH_TESTS,
829 ));
830 }
831
832 fn test_mismatch(correct_hashes: bool, correct_write_versions: bool) {
833 let account = AccountSharedData::default();
834 let slot = 0 as Slot;
836 let pubkey = Pubkey::default();
837 let mut hashes = Vec::default();
839 if correct_hashes {
840 hashes.push(Hash::default());
841 }
842 let mut write_versions = Vec::default();
843 if correct_write_versions {
844 write_versions.push(0);
845 }
846 StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions(
847 &(slot, &[(&pubkey, &account)][..], INCLUDE_SLOT_IN_HASH_TESTS),
848 hashes,
849 write_versions,
850 );
851 }
852
853 #[test]
854 #[should_panic(expected = "assertion failed:")]
855 fn test_storable_accounts_with_hashes_and_write_versions_new2() {
856 test_mismatch(false, false);
857 }
858
859 #[test]
860 #[should_panic(expected = "assertion failed:")]
861 fn test_storable_accounts_with_hashes_and_write_versions_new3() {
862 test_mismatch(false, true);
863 }
864
865 #[test]
866 #[should_panic(expected = "assertion failed:")]
867 fn test_storable_accounts_with_hashes_and_write_versions_new4() {
868 test_mismatch(true, false);
869 }
870
871 #[test]
872 fn test_storable_accounts_with_hashes_and_write_versions_empty() {
873 let account = AccountSharedData::default();
875 let slot = 0 as Slot;
876 let pubkeys = vec![Pubkey::default()];
877 let hashes = Vec::<Hash>::default();
878 let write_versions = Vec::default();
879 let mut accounts = vec![(&pubkeys[0], &account)];
880 accounts.clear();
881 let accounts2 = (slot, &accounts[..], INCLUDE_SLOT_IN_HASH_TESTS);
882 let storable =
883 StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions(
884 &accounts2,
885 hashes,
886 write_versions,
887 );
888 assert_eq!(storable.len(), 0);
889 assert!(storable.is_empty());
890 }
891
892 #[test]
893 fn test_storable_accounts_with_hashes_and_write_versions_hash_and_write_version() {
894 let account = AccountSharedData::default();
896 let slot = 0 as Slot;
897 let pubkeys = vec![Pubkey::from([5; 32]), Pubkey::from([6; 32])];
898 let hashes = vec![Hash::new(&[3; 32]), Hash::new(&[4; 32])];
899 let write_versions = vec![42, 43];
900 let accounts = vec![(&pubkeys[0], &account), (&pubkeys[1], &account)];
901 let accounts2 = (slot, &accounts[..], INCLUDE_SLOT_IN_HASH_TESTS);
902 let storable =
903 StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions(
904 &accounts2,
905 hashes.clone(),
906 write_versions.clone(),
907 );
908 assert_eq!(storable.len(), pubkeys.len());
909 assert!(!storable.is_empty());
910 (0..2).for_each(|i| {
911 let (_, pubkey, hash, write_version) = storable.get(i);
912 assert_eq!(hash, &hashes[i]);
913 assert_eq!(write_version, write_versions[i]);
914 assert_eq!(pubkey, &pubkeys[i]);
915 });
916 }
917
918 #[test]
919 fn test_storable_accounts_with_hashes_and_write_versions_default() {
920 let account = Account {
922 data: vec![0],
923 ..Account::default()
924 }
925 .to_account_shared_data();
926 let slot = 0 as Slot;
928 let pubkey = Pubkey::default();
929 let hashes = vec![Hash::default()];
930 let write_versions = vec![0];
931 let accounts = vec![(&pubkey, &account)];
932 let accounts2 = (slot, &accounts[..], INCLUDE_SLOT_IN_HASH_TESTS);
933 let storable =
934 StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions(
935 &accounts2,
936 hashes.clone(),
937 write_versions.clone(),
938 );
939 let get_account = storable.account(0);
940 assert!(get_account.is_none());
941
942 let account = Account {
944 lamports: 1,
945 data: vec![0],
946 ..Account::default()
947 }
948 .to_account_shared_data();
949 let accounts = vec![(&pubkey, &account)];
951 let accounts2 = (slot, &accounts[..], INCLUDE_SLOT_IN_HASH_TESTS);
952 let storable =
953 StorableAccountsWithHashesAndWriteVersions::new_with_hashes_and_write_versions(
954 &accounts2,
955 hashes,
956 write_versions,
957 );
958 let get_account = storable.account(0);
959 assert!(accounts_equal(&account, get_account.unwrap()));
960 }
961
962 #[test]
963 fn test_account_meta_default() {
964 let def1 = AccountMeta::default();
965 let def2 = AccountMeta::from(&Account::default());
966 assert_eq!(&def1, &def2);
967 let def2 = AccountMeta::from(&AccountSharedData::default());
968 assert_eq!(&def1, &def2);
969 let def2 = AccountMeta::from(Some(&AccountSharedData::default()));
970 assert_eq!(&def1, &def2);
971 let none: Option<&AccountSharedData> = None;
972 let def2 = AccountMeta::from(none);
973 assert_eq!(&def1, &def2);
974 }
975
976 #[test]
977 fn test_account_meta_non_default() {
978 let def1 = AccountMeta {
979 lamports: 1,
980 owner: Pubkey::new_unique(),
981 executable: true,
982 rent_epoch: 3,
983 };
984 let def2_account = Account {
985 lamports: def1.lamports,
986 owner: def1.owner,
987 executable: def1.executable,
988 rent_epoch: def1.rent_epoch,
989 data: Vec::new(),
990 };
991 let def2 = AccountMeta::from(&def2_account);
992 assert_eq!(&def1, &def2);
993 let def2 = AccountMeta::from(&AccountSharedData::from(def2_account.clone()));
994 assert_eq!(&def1, &def2);
995 let def2 = AccountMeta::from(Some(&AccountSharedData::from(def2_account)));
996 assert_eq!(&def1, &def2);
997 }
998
999 #[test]
1000 #[should_panic(expected = "too small file size 0 for AppendVec")]
1001 fn test_append_vec_new_bad_size() {
1002 let path = get_append_vec_path("test_append_vec_new_bad_size");
1003 let _av = AppendVec::new(&path.path, true, 0);
1004 }
1005
1006 #[test]
1007 fn test_append_vec_new_from_file_bad_size() {
1008 let file = get_append_vec_path("test_append_vec_new_from_file_bad_size");
1009 let path = &file.path;
1010
1011 let _data = OpenOptions::new()
1012 .read(true)
1013 .write(true)
1014 .create(true)
1015 .open(path)
1016 .expect("create a test file for mmap");
1017
1018 let result = AppendVec::new_from_file(path, 0);
1019 assert_matches!(result, Err(ref message) if message.to_string() == *"too small file size 0 for AppendVec");
1020 }
1021
1022 #[test]
1023 fn test_append_vec_sanitize_len_and_size_too_small() {
1024 const LEN: usize = 0;
1025 const SIZE: usize = 0;
1026 let result = AppendVec::sanitize_len_and_size(LEN, SIZE);
1027 assert_matches!(result, Err(ref message) if message.to_string() == *"too small file size 0 for AppendVec");
1028 }
1029
1030 #[test]
1031 fn test_append_vec_sanitize_len_and_size_maximum() {
1032 const LEN: usize = 0;
1033 const SIZE: usize = 16 * 1024 * 1024 * 1024;
1034 let result = AppendVec::sanitize_len_and_size(LEN, SIZE);
1035 assert_matches!(result, Ok(_));
1036 }
1037
1038 #[test]
1039 fn test_append_vec_sanitize_len_and_size_too_large() {
1040 const LEN: usize = 0;
1041 const SIZE: usize = 16 * 1024 * 1024 * 1024 + 1;
1042 let result = AppendVec::sanitize_len_and_size(LEN, SIZE);
1043 assert_matches!(result, Err(ref message) if message.to_string() == *"too large file size 17179869185 for AppendVec");
1044 }
1045
1046 #[test]
1047 fn test_append_vec_sanitize_len_and_size_full_and_same_as_current_len() {
1048 const LEN: usize = 1024 * 1024;
1049 const SIZE: usize = 1024 * 1024;
1050 let result = AppendVec::sanitize_len_and_size(LEN, SIZE);
1051 assert_matches!(result, Ok(_));
1052 }
1053
1054 #[test]
1055 fn test_append_vec_sanitize_len_and_size_larger_current_len() {
1056 const LEN: usize = 1024 * 1024 + 1;
1057 const SIZE: usize = 1024 * 1024;
1058 let result = AppendVec::sanitize_len_and_size(LEN, SIZE);
1059 assert_matches!(result, Err(ref message) if message.to_string() == *"current_len is larger than file size (1048576)");
1060 }
1061
1062 #[test]
1063 fn test_append_vec_one() {
1064 let path = get_append_vec_path("test_append");
1065 let av = AppendVec::new(&path.path, true, 1024 * 1024);
1066 let account = create_test_account(0);
1067 let index = av.append_account_test(&account).unwrap();
1068 assert_eq!(av.get_account_test(index).unwrap(), account);
1069 }
1070
1071 #[test]
1072 fn test_remaining_bytes() {
1073 let path = get_append_vec_path("test_append");
1074 let sz = 1024 * 1024;
1075 let sz64 = sz as u64;
1076 let av = AppendVec::new(&path.path, true, sz);
1077 assert_eq!(av.capacity(), sz64);
1078 assert_eq!(av.remaining_bytes(), sz64);
1079 let account = create_test_account(0);
1080 av.append_account_test(&account).unwrap();
1081 assert_eq!(av.capacity(), sz64);
1082 assert_eq!(av.remaining_bytes(), sz64 - (STORE_META_OVERHEAD as u64));
1083 }
1084
1085 #[test]
1086 fn test_append_vec_data() {
1087 let path = get_append_vec_path("test_append_data");
1088 let av = AppendVec::new(&path.path, true, 1024 * 1024);
1089 let account = create_test_account(5);
1090 let index = av.append_account_test(&account).unwrap();
1091 assert_eq!(av.get_account_test(index).unwrap(), account);
1092 let account1 = create_test_account(6);
1093 let index1 = av.append_account_test(&account1).unwrap();
1094 assert_eq!(av.get_account_test(index).unwrap(), account);
1095 assert_eq!(av.get_account_test(index1).unwrap(), account1);
1096 }
1097
1098 #[test]
1099 fn test_account_matches_owners() {
1100 let path = get_append_vec_path("test_append_data");
1101 let av = AppendVec::new(&path.path, true, 1024 * 1024);
1102 let owners: Vec<Pubkey> = (0..2).map(|_| Pubkey::new_unique()).collect();
1103 let owners_refs: Vec<&Pubkey> = owners.iter().collect();
1104
1105 let mut account = create_test_account(5);
1106 account.1.set_owner(owners[0]);
1107 let index = av.append_account_test(&account).unwrap();
1108 assert_eq!(av.account_matches_owners(index, &owners_refs), Ok(0));
1109
1110 let mut account1 = create_test_account(6);
1111 account1.1.set_owner(owners[1]);
1112 let index1 = av.append_account_test(&account1).unwrap();
1113 assert_eq!(av.account_matches_owners(index1, &owners_refs), Ok(1));
1114 assert_eq!(av.account_matches_owners(index, &owners_refs), Ok(0));
1115
1116 let mut account2 = create_test_account(6);
1117 account2.1.set_owner(Pubkey::new_unique());
1118 let index2 = av.append_account_test(&account2).unwrap();
1119 assert_eq!(
1120 av.account_matches_owners(index2, &owners_refs),
1121 Err(MatchAccountOwnerError::NoMatch)
1122 );
1123
1124 assert_eq!(
1126 av.account_matches_owners(usize::MAX - mem::size_of::<StoredMeta>(), &owners_refs),
1127 Err(MatchAccountOwnerError::UnableToLoad)
1128 );
1129
1130 assert_eq!(
1131 av.account_matches_owners(
1132 usize::MAX - mem::size_of::<StoredMeta>() - mem::size_of::<AccountMeta>() + 1,
1133 &owners_refs
1134 ),
1135 Err(MatchAccountOwnerError::UnableToLoad)
1136 );
1137 }
1138
1139 #[test]
1140 fn test_append_vec_append_many() {
1141 let path = get_append_vec_path("test_append_many");
1142 let av = AppendVec::new(&path.path, true, 1024 * 1024);
1143 let size = 1000;
1144 let mut indexes = vec![];
1145 let now = Instant::now();
1146 for sample in 0..size {
1147 let account = create_test_account(sample);
1148 let pos = av.append_account_test(&account).unwrap();
1149 assert_eq!(av.get_account_test(pos).unwrap(), account);
1150 indexes.push(pos)
1151 }
1152 trace!("append time: {} ms", duration_as_ms(&now.elapsed()),);
1153
1154 let now = Instant::now();
1155 for _ in 0..size {
1156 let sample = thread_rng().gen_range(0, indexes.len());
1157 let account = create_test_account(sample);
1158 assert_eq!(av.get_account_test(indexes[sample]).unwrap(), account);
1159 }
1160 trace!("random read time: {} ms", duration_as_ms(&now.elapsed()),);
1161
1162 let now = Instant::now();
1163 assert_eq!(indexes.len(), size);
1164 assert_eq!(indexes[0], 0);
1165 let mut accounts = av.accounts(indexes[0]);
1166 assert_eq!(accounts.len(), size);
1167 for (sample, v) in accounts.iter_mut().enumerate() {
1168 let account = create_test_account(sample);
1169 let recovered = v.clone_account();
1170 assert_eq!(recovered, account.1)
1171 }
1172 trace!(
1173 "sequential read time: {} ms",
1174 duration_as_ms(&now.elapsed()),
1175 );
1176 }
1177
1178 #[test]
1179 fn test_new_from_file_crafted_zero_lamport_account() {
1180 let file = get_append_vec_path("test_append_bytes");
1224 let path = &file.path;
1225
1226 let accounts_len = 139;
1227 {
1228 let append_vec_data = [
1229 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 192, 118, 150, 1, 185, 209, 118,
1230 82, 154, 222, 172, 202, 110, 26, 218, 140, 143, 96, 61, 43, 212, 73, 203, 7, 190,
1231 88, 80, 222, 110, 114, 67, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1238 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1239 ];
1240
1241 let f = std::fs::File::create(path).unwrap();
1242 let mut writer = std::io::BufWriter::new(f);
1243 writer.write_all(append_vec_data.as_slice()).unwrap();
1244 }
1245
1246 let result = AppendVec::new_from_file(path, accounts_len);
1247 assert_matches!(result, Err(ref message) if message.to_string().starts_with("incorrect layout/length/data"));
1248 }
1249
1250 #[test]
1251 fn test_new_from_file_crafted_data_len() {
1252 let file = get_append_vec_path("test_new_from_file_crafted_data_len");
1253 let path = &file.path;
1254 let mut av = AppendVec::new(path, true, 1024 * 1024);
1255 av.set_no_remove_on_drop();
1256
1257 let crafted_data_len = 1;
1258
1259 av.append_account_test(&create_test_account(10)).unwrap();
1260
1261 let accounts = av.accounts(0);
1262 let account = accounts.first().unwrap();
1263 account.set_data_len_unsafe(crafted_data_len);
1264 assert_eq!(account.meta.data_len, crafted_data_len);
1265
1266 let accounts = av.accounts(0);
1268 let account = accounts.first().unwrap();
1269 assert_eq!(account.meta.data_len, crafted_data_len);
1270
1271 av.flush().unwrap();
1272 let accounts_len = av.len();
1273 drop(av);
1274 let result = AppendVec::new_from_file(path, accounts_len);
1275 assert_matches!(result, Err(ref message) if message.to_string().starts_with("incorrect layout/length/data"));
1276 }
1277
1278 #[test]
1279 fn test_new_from_file_too_large_data_len() {
1280 let file = get_append_vec_path("test_new_from_file_too_large_data_len");
1281 let path = &file.path;
1282 let mut av = AppendVec::new(path, true, 1024 * 1024);
1283 av.set_no_remove_on_drop();
1284
1285 let too_large_data_len = u64::max_value();
1286 av.append_account_test(&create_test_account(10)).unwrap();
1287
1288 let accounts = av.accounts(0);
1289 let account = accounts.first().unwrap();
1290 account.set_data_len_unsafe(too_large_data_len);
1291 assert_eq!(account.meta.data_len, too_large_data_len);
1292
1293 let accounts = av.accounts(0);
1295 assert_matches!(accounts.first(), None);
1296
1297 av.flush().unwrap();
1298 let accounts_len = av.len();
1299 drop(av);
1300 let result = AppendVec::new_from_file(path, accounts_len);
1301 assert_matches!(result, Err(ref message) if message.to_string().starts_with("incorrect layout/length/data"));
1302 }
1303
1304 #[test]
1305 fn test_new_from_file_crafted_executable() {
1306 let file = get_append_vec_path("test_new_from_crafted_executable");
1307 let path = &file.path;
1308 let mut av = AppendVec::new(path, true, 1024 * 1024);
1309 av.set_no_remove_on_drop();
1310 av.append_account_test(&create_test_account(10)).unwrap();
1311 {
1312 let mut executable_account = create_test_account(10);
1313 executable_account.1.set_executable(true);
1314 av.append_account_test(&executable_account).unwrap();
1315 }
1316
1317 let accounts = av.accounts(0);
1319
1320 assert_eq!(*accounts[0].ref_executable_byte(), 0);
1322 assert_eq!(*accounts[1].ref_executable_byte(), 1);
1323
1324 let account = &accounts[0];
1325 let crafted_executable = u8::max_value() - 1;
1326
1327 account.set_executable_as_byte(crafted_executable);
1328
1329 let accounts = av.accounts(0);
1331 let account = accounts.first().unwrap();
1332
1333 assert!(!account.sanitize_executable());
1335
1336 {
1338 let executable_bool: &bool = &account.account_meta.executable;
1339 assert!(!*executable_bool);
1342 #[cfg(not(target_arch = "aarch64"))]
1343 {
1344 const FALSE: bool = false; if *executable_bool == FALSE {
1346 panic!("This didn't occur if this test passed.");
1347 }
1348 }
1349 assert_eq!(*account.ref_executable_byte(), crafted_executable);
1350 }
1351
1352 {
1354 let executable_bool: bool = account.account_meta.executable;
1355 assert!(!executable_bool);
1356 assert_eq!(account.get_executable_byte(), 0); }
1358
1359 av.flush().unwrap();
1360 let accounts_len = av.len();
1361 drop(av);
1362 let result = AppendVec::new_from_file(path, accounts_len);
1363 assert_matches!(result, Err(ref message) if message.to_string().starts_with("incorrect layout/length/data"));
1364 }
1365
1366 #[test]
1367 fn test_type_layout() {
1368 assert_eq!(offset_of!(StoredMeta, write_version_obsolete), 0x00);
1369 assert_eq!(offset_of!(StoredMeta, data_len), 0x08);
1370 assert_eq!(offset_of!(StoredMeta, pubkey), 0x10);
1371 assert_eq!(mem::size_of::<StoredMeta>(), 0x30);
1372
1373 assert_eq!(offset_of!(AccountMeta, lamports), 0x00);
1374 assert_eq!(offset_of!(AccountMeta, rent_epoch), 0x08);
1375 assert_eq!(offset_of!(AccountMeta, owner), 0x10);
1376 assert_eq!(offset_of!(AccountMeta, executable), 0x30);
1377 assert_eq!(mem::size_of::<AccountMeta>(), 0x38);
1378 }
1379}