1use {
2 crate::{
3 bank::{Bank, BankFieldsToDeserialize, BankSlotDelta},
4 epoch_stakes::EpochStakes,
5 runtime_config::RuntimeConfig,
6 serde_snapshot::{
7 bank_from_streams, fields_from_streams, BankIncrementalSnapshotPersistence,
8 },
9 snapshot_archive_info::{
10 FullSnapshotArchiveInfo, IncrementalSnapshotArchiveInfo, SnapshotArchiveInfoGetter,
11 },
12 snapshot_config::SnapshotConfig,
13 snapshot_hash::SnapshotHash,
14 snapshot_package::{AccountsPackage, AccountsPackageKind, SnapshotKind, SnapshotPackage},
15 snapshot_utils::{
16 self, deserialize_snapshot_data_file, deserialize_snapshot_data_files,
17 get_highest_bank_snapshot_post, get_highest_full_snapshot_archive_info,
18 get_highest_incremental_snapshot_archive_info, rebuild_storages_from_snapshot_dir,
19 serialize_snapshot_data_file, verify_and_unarchive_snapshots,
20 verify_unpacked_snapshots_dir_and_version, ArchiveFormat, BankSnapshotInfo,
21 SnapshotError, SnapshotRootPaths, SnapshotVersion, StorageAndNextAccountsFileId,
22 UnpackedSnapshotsDirAndVersion, VerifyEpochStakesError, VerifySlotDeltasError,
23 },
24 status_cache,
25 },
26 bincode::{config::Options, serialize_into},
27 log::*,
28 solana_accounts_db::{
29 accounts_db::{
30 AccountStorageEntry, AccountsDbConfig, AtomicAccountsFileId,
31 CalcAccountsHashDataSource, DuplicatesLtHash,
32 },
33 accounts_file::StorageAccess,
34 accounts_hash::MerkleOrLatticeAccountsHash,
35 accounts_update_notifier_interface::AccountsUpdateNotifier,
36 utils::delete_contents_of_path,
37 },
38 solana_builtins::prototype::BuiltinPrototype,
39 solana_measure::{measure::Measure, measure_time},
40 solana_sdk::{
41 clock::{Epoch, Slot},
42 feature_set,
43 genesis_config::GenesisConfig,
44 pubkey::Pubkey,
45 slot_history::{Check, SlotHistory},
46 },
47 std::{
48 collections::{HashMap, HashSet},
49 ops::RangeInclusive,
50 path::{Path, PathBuf},
51 sync::{atomic::AtomicBool, Arc},
52 },
53 tempfile::TempDir,
54};
55
56pub const DEFAULT_FULL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS: Slot = 25_000;
57pub const DEFAULT_INCREMENTAL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS: Slot = 100;
58pub const DISABLED_SNAPSHOT_ARCHIVE_INTERVAL: Slot = Slot::MAX;
59
60pub fn serialize_status_cache(
61 slot_deltas: &[BankSlotDelta],
62 status_cache_path: &Path,
63) -> snapshot_utils::Result<u64> {
64 serialize_snapshot_data_file(status_cache_path, |stream| {
65 serialize_into(stream, slot_deltas)?;
66 Ok(())
67 })
68}
69
70#[derive(Debug)]
71pub struct BankFromArchivesTimings {
72 pub untar_full_snapshot_archive_us: u64,
73 pub untar_incremental_snapshot_archive_us: u64,
74 pub rebuild_bank_us: u64,
75 pub verify_bank_us: u64,
76}
77
78#[derive(Debug)]
79pub struct BankFromDirTimings {
80 pub rebuild_storages_us: u64,
81 pub rebuild_bank_us: u64,
82}
83
84pub fn bank_fields_from_snapshot_archives(
87 full_snapshot_archives_dir: impl AsRef<Path>,
88 incremental_snapshot_archives_dir: impl AsRef<Path>,
89 storage_access: StorageAccess,
90) -> snapshot_utils::Result<BankFieldsToDeserialize> {
91 let full_snapshot_archive_info =
92 get_highest_full_snapshot_archive_info(&full_snapshot_archives_dir).ok_or_else(|| {
93 SnapshotError::NoSnapshotArchives(full_snapshot_archives_dir.as_ref().to_path_buf())
94 })?;
95
96 let incremental_snapshot_archive_info = get_highest_incremental_snapshot_archive_info(
97 &incremental_snapshot_archives_dir,
98 full_snapshot_archive_info.slot(),
99 );
100
101 let temp_unpack_dir = TempDir::new()?;
102 let temp_accounts_dir = TempDir::new()?;
103
104 let account_paths = vec![temp_accounts_dir.path().to_path_buf()];
105
106 let (unarchived_full_snapshot, unarchived_incremental_snapshot, _next_append_vec_id) =
107 verify_and_unarchive_snapshots(
108 &temp_unpack_dir,
109 &full_snapshot_archive_info,
110 incremental_snapshot_archive_info.as_ref(),
111 &account_paths,
112 storage_access,
113 )?;
114
115 bank_fields_from_snapshots(
116 &unarchived_full_snapshot.unpacked_snapshots_dir_and_version,
117 unarchived_incremental_snapshot
118 .as_ref()
119 .map(|unarchive_preparation_result| {
120 &unarchive_preparation_result.unpacked_snapshots_dir_and_version
121 }),
122 )
123}
124
125#[allow(clippy::too_many_arguments)]
128pub fn bank_from_snapshot_archives(
129 account_paths: &[PathBuf],
130 bank_snapshots_dir: impl AsRef<Path>,
131 full_snapshot_archive_info: &FullSnapshotArchiveInfo,
132 incremental_snapshot_archive_info: Option<&IncrementalSnapshotArchiveInfo>,
133 genesis_config: &GenesisConfig,
134 runtime_config: &RuntimeConfig,
135 debug_keys: Option<Arc<HashSet<Pubkey>>>,
136 additional_builtins: Option<&[BuiltinPrototype]>,
137 limit_load_slot_count_from_snapshot: Option<usize>,
138 test_hash_calculation: bool,
139 accounts_db_skip_shrink: bool,
140 accounts_db_force_initial_clean: bool,
141 verify_index: bool,
142 accounts_db_config: Option<AccountsDbConfig>,
143 accounts_update_notifier: Option<AccountsUpdateNotifier>,
144 exit: Arc<AtomicBool>,
145) -> snapshot_utils::Result<(Bank, BankFromArchivesTimings)> {
146 info!(
147 "Loading bank from full snapshot archive: {}, and incremental snapshot archive: {:?}",
148 full_snapshot_archive_info.path().display(),
149 incremental_snapshot_archive_info
150 .as_ref()
151 .map(
152 |incremental_snapshot_archive_info| incremental_snapshot_archive_info
153 .path()
154 .display()
155 )
156 );
157
158 let (unarchived_full_snapshot, mut unarchived_incremental_snapshot, next_append_vec_id) =
159 verify_and_unarchive_snapshots(
160 bank_snapshots_dir,
161 full_snapshot_archive_info,
162 incremental_snapshot_archive_info,
163 account_paths,
164 accounts_db_config
165 .as_ref()
166 .map(|config| config.storage_access)
167 .unwrap_or_default(),
168 )?;
169
170 let mut storage = unarchived_full_snapshot.storage;
171 if let Some(ref mut unarchive_preparation_result) = unarchived_incremental_snapshot {
172 let incremental_snapshot_storages =
173 std::mem::take(&mut unarchive_preparation_result.storage);
174 storage.extend(incremental_snapshot_storages);
175 }
176
177 let storage_and_next_append_vec_id = StorageAndNextAccountsFileId {
178 storage,
179 next_append_vec_id,
180 };
181
182 let mut measure_rebuild = Measure::start("rebuild bank from snapshots");
183 let (bank, info) = rebuild_bank_from_unarchived_snapshots(
184 &unarchived_full_snapshot.unpacked_snapshots_dir_and_version,
185 unarchived_incremental_snapshot
186 .as_ref()
187 .map(|unarchive_preparation_result| {
188 &unarchive_preparation_result.unpacked_snapshots_dir_and_version
189 }),
190 account_paths,
191 storage_and_next_append_vec_id,
192 genesis_config,
193 runtime_config,
194 debug_keys,
195 additional_builtins,
196 limit_load_slot_count_from_snapshot,
197 verify_index,
198 accounts_db_config,
199 accounts_update_notifier,
200 exit,
201 )?;
202 measure_rebuild.stop();
203 info!("{}", measure_rebuild);
204
205 let snapshot_archive_info = incremental_snapshot_archive_info.map_or_else(
206 || full_snapshot_archive_info.snapshot_archive_info(),
207 |incremental_snapshot_archive_info| {
208 incremental_snapshot_archive_info.snapshot_archive_info()
209 },
210 );
211 verify_bank_against_expected_slot_hash(
212 &bank,
213 snapshot_archive_info.slot,
214 snapshot_archive_info.hash,
215 )?;
216
217 let base = if bank.is_snapshots_lt_hash_enabled() {
218 None
219 } else {
220 incremental_snapshot_archive_info.is_some().then(|| {
221 let base_slot = full_snapshot_archive_info.slot();
222 let base_capitalization = bank
223 .rc
224 .accounts
225 .accounts_db
226 .get_accounts_hash(base_slot)
227 .expect("accounts hash must exist at full snapshot's slot")
228 .1;
229 (base_slot, base_capitalization)
230 })
231 };
232
233 let mut measure_verify = Measure::start("verify");
234 if !bank.verify_snapshot_bank(
235 test_hash_calculation,
236 accounts_db_skip_shrink || !full_snapshot_archive_info.is_remote(),
237 accounts_db_force_initial_clean,
238 full_snapshot_archive_info.slot(),
239 base,
240 info.duplicates_lt_hash,
241 ) && limit_load_slot_count_from_snapshot.is_none()
242 {
243 panic!("Snapshot bank for slot {} failed to verify", bank.slot());
244 }
245 measure_verify.stop();
246
247 let timings = BankFromArchivesTimings {
248 untar_full_snapshot_archive_us: unarchived_full_snapshot.measure_untar.as_us(),
249 untar_incremental_snapshot_archive_us: unarchived_incremental_snapshot
250 .map_or(0, |unarchive_preparation_result| {
251 unarchive_preparation_result.measure_untar.as_us()
252 }),
253 rebuild_bank_us: measure_rebuild.as_us(),
254 verify_bank_us: measure_verify.as_us(),
255 };
256 datapoint_info!(
257 "bank_from_snapshot_archives",
258 (
259 "untar_full_snapshot_archive_us",
260 timings.untar_full_snapshot_archive_us,
261 i64
262 ),
263 (
264 "untar_incremental_snapshot_archive_us",
265 timings.untar_incremental_snapshot_archive_us,
266 i64
267 ),
268 ("rebuild_bank_us", timings.rebuild_bank_us, i64),
269 ("verify_bank_us", timings.verify_bank_us, i64),
270 );
271 Ok((bank, timings))
272}
273
274#[allow(clippy::too_many_arguments)]
279pub fn bank_from_latest_snapshot_archives(
280 bank_snapshots_dir: impl AsRef<Path>,
281 full_snapshot_archives_dir: impl AsRef<Path>,
282 incremental_snapshot_archives_dir: impl AsRef<Path>,
283 account_paths: &[PathBuf],
284 genesis_config: &GenesisConfig,
285 runtime_config: &RuntimeConfig,
286 debug_keys: Option<Arc<HashSet<Pubkey>>>,
287 additional_builtins: Option<&[BuiltinPrototype]>,
288 limit_load_slot_count_from_snapshot: Option<usize>,
289 test_hash_calculation: bool,
290 accounts_db_skip_shrink: bool,
291 accounts_db_force_initial_clean: bool,
292 verify_index: bool,
293 accounts_db_config: Option<AccountsDbConfig>,
294 accounts_update_notifier: Option<AccountsUpdateNotifier>,
295 exit: Arc<AtomicBool>,
296) -> snapshot_utils::Result<(
297 Bank,
298 FullSnapshotArchiveInfo,
299 Option<IncrementalSnapshotArchiveInfo>,
300)> {
301 let full_snapshot_archive_info =
302 get_highest_full_snapshot_archive_info(&full_snapshot_archives_dir).ok_or_else(|| {
303 SnapshotError::NoSnapshotArchives(full_snapshot_archives_dir.as_ref().to_path_buf())
304 })?;
305
306 let incremental_snapshot_archive_info = get_highest_incremental_snapshot_archive_info(
307 &incremental_snapshot_archives_dir,
308 full_snapshot_archive_info.slot(),
309 );
310
311 let (bank, _) = bank_from_snapshot_archives(
312 account_paths,
313 bank_snapshots_dir.as_ref(),
314 &full_snapshot_archive_info,
315 incremental_snapshot_archive_info.as_ref(),
316 genesis_config,
317 runtime_config,
318 debug_keys,
319 additional_builtins,
320 limit_load_slot_count_from_snapshot,
321 test_hash_calculation,
322 accounts_db_skip_shrink,
323 accounts_db_force_initial_clean,
324 verify_index,
325 accounts_db_config,
326 accounts_update_notifier,
327 exit,
328 )?;
329
330 Ok((
331 bank,
332 full_snapshot_archive_info,
333 incremental_snapshot_archive_info,
334 ))
335}
336
337#[allow(clippy::too_many_arguments)]
339pub fn bank_from_snapshot_dir(
340 account_paths: &[PathBuf],
341 bank_snapshot: &BankSnapshotInfo,
342 genesis_config: &GenesisConfig,
343 runtime_config: &RuntimeConfig,
344 debug_keys: Option<Arc<HashSet<Pubkey>>>,
345 additional_builtins: Option<&[BuiltinPrototype]>,
346 limit_load_slot_count_from_snapshot: Option<usize>,
347 verify_index: bool,
348 accounts_db_config: Option<AccountsDbConfig>,
349 accounts_update_notifier: Option<AccountsUpdateNotifier>,
350 exit: Arc<AtomicBool>,
351) -> snapshot_utils::Result<(Bank, BankFromDirTimings)> {
352 info!(
353 "Loading bank from snapshot dir: {}",
354 bank_snapshot.snapshot_dir.display()
355 );
356
357 for path in account_paths {
360 delete_contents_of_path(path);
361 }
362
363 let next_append_vec_id = Arc::new(AtomicAccountsFileId::new(0));
364 let storage_access = accounts_db_config
365 .as_ref()
366 .map(|config| config.storage_access)
367 .unwrap_or_default();
368
369 let (storage, measure_rebuild_storages) = measure_time!(
370 rebuild_storages_from_snapshot_dir(
371 bank_snapshot,
372 account_paths,
373 next_append_vec_id.clone(),
374 storage_access,
375 )?,
376 "rebuild storages from snapshot dir"
377 );
378 info!("{}", measure_rebuild_storages);
379
380 let next_append_vec_id =
381 Arc::try_unwrap(next_append_vec_id).expect("this is the only strong reference");
382 let storage_and_next_append_vec_id = StorageAndNextAccountsFileId {
383 storage,
384 next_append_vec_id,
385 };
386 let ((bank, _info), measure_rebuild_bank) = measure_time!(
387 rebuild_bank_from_snapshot(
388 bank_snapshot,
389 account_paths,
390 storage_and_next_append_vec_id,
391 genesis_config,
392 runtime_config,
393 debug_keys,
394 additional_builtins,
395 limit_load_slot_count_from_snapshot,
396 verify_index,
397 accounts_db_config,
398 accounts_update_notifier,
399 exit,
400 )?,
401 "rebuild bank from snapshot"
402 );
403 info!("{}", measure_rebuild_bank);
404
405 bank.set_initial_accounts_hash_verification_completed();
408
409 let timings = BankFromDirTimings {
410 rebuild_storages_us: measure_rebuild_storages.as_us(),
411 rebuild_bank_us: measure_rebuild_bank.as_us(),
412 };
413 datapoint_info!(
414 "bank_from_snapshot_dir",
415 ("rebuild_storages_us", timings.rebuild_storages_us, i64),
416 ("rebuild_bank_us", timings.rebuild_bank_us, i64),
417 );
418 Ok((bank, timings))
419}
420
421#[allow(clippy::too_many_arguments)]
423pub fn bank_from_latest_snapshot_dir(
424 bank_snapshots_dir: impl AsRef<Path>,
425 genesis_config: &GenesisConfig,
426 runtime_config: &RuntimeConfig,
427 account_paths: &[PathBuf],
428 debug_keys: Option<Arc<HashSet<Pubkey>>>,
429 additional_builtins: Option<&[BuiltinPrototype]>,
430 limit_load_slot_count_from_snapshot: Option<usize>,
431 verify_index: bool,
432 accounts_db_config: Option<AccountsDbConfig>,
433 accounts_update_notifier: Option<AccountsUpdateNotifier>,
434 exit: Arc<AtomicBool>,
435) -> snapshot_utils::Result<Bank> {
436 let bank_snapshot = get_highest_bank_snapshot_post(&bank_snapshots_dir).ok_or_else(|| {
437 SnapshotError::NoSnapshotSlotDir(bank_snapshots_dir.as_ref().to_path_buf())
438 })?;
439 let (bank, _) = bank_from_snapshot_dir(
440 account_paths,
441 &bank_snapshot,
442 genesis_config,
443 runtime_config,
444 debug_keys,
445 additional_builtins,
446 limit_load_slot_count_from_snapshot,
447 verify_index,
448 accounts_db_config,
449 accounts_update_notifier,
450 exit,
451 )?;
452
453 Ok(bank)
454}
455
456fn verify_bank_against_expected_slot_hash(
458 bank: &Bank,
459 snapshot_slot: Slot,
460 snapshot_hash: SnapshotHash,
461) -> snapshot_utils::Result<()> {
462 let bank_slot = bank.slot();
463 if bank_slot != snapshot_slot {
464 return Err(SnapshotError::MismatchedSlot(bank_slot, snapshot_slot));
465 }
466
467 let bank_hash = bank.get_snapshot_hash();
468 if bank_hash == snapshot_hash {
469 return Ok(());
470 }
471
472 if bank
476 .feature_set
477 .is_active(&feature_set::snapshots_lt_hash::id())
478 {
479 return Err(SnapshotError::MismatchedHash(bank_hash, snapshot_hash));
481 }
482
483 let other_bank_hash = if bank.is_snapshots_lt_hash_enabled() {
486 bank.get_merkle_snapshot_hash()
489 } else {
490 bank.get_lattice_snapshot_hash()
493 };
494
495 if other_bank_hash == snapshot_hash {
496 Ok(())
497 } else {
498 Err(SnapshotError::MismatchedHash(bank_hash, snapshot_hash))
500 }
501}
502
503fn bank_fields_from_snapshots(
504 full_snapshot_unpacked_snapshots_dir_and_version: &UnpackedSnapshotsDirAndVersion,
505 incremental_snapshot_unpacked_snapshots_dir_and_version: Option<
506 &UnpackedSnapshotsDirAndVersion,
507 >,
508) -> snapshot_utils::Result<BankFieldsToDeserialize> {
509 let (full_snapshot_version, full_snapshot_root_paths) =
510 verify_unpacked_snapshots_dir_and_version(
511 full_snapshot_unpacked_snapshots_dir_and_version,
512 )?;
513 let (incremental_snapshot_version, incremental_snapshot_root_paths) =
514 if let Some(snapshot_unpacked_snapshots_dir_and_version) =
515 incremental_snapshot_unpacked_snapshots_dir_and_version
516 {
517 let (snapshot_version, bank_snapshot_info) = verify_unpacked_snapshots_dir_and_version(
518 snapshot_unpacked_snapshots_dir_and_version,
519 )?;
520 (Some(snapshot_version), Some(bank_snapshot_info))
521 } else {
522 (None, None)
523 };
524 info!(
525 "Loading bank from full snapshot {} and incremental snapshot {:?}",
526 full_snapshot_root_paths.snapshot_path().display(),
527 incremental_snapshot_root_paths
528 .as_ref()
529 .map(|paths| paths.snapshot_path()),
530 );
531
532 let snapshot_root_paths = SnapshotRootPaths {
533 full_snapshot_root_file_path: full_snapshot_root_paths.snapshot_path(),
534 incremental_snapshot_root_file_path: incremental_snapshot_root_paths
535 .map(|root_paths| root_paths.snapshot_path()),
536 };
537
538 deserialize_snapshot_data_files(&snapshot_root_paths, |snapshot_streams| {
539 Ok(
540 match incremental_snapshot_version.unwrap_or(full_snapshot_version) {
541 SnapshotVersion::V1_2_0 => fields_from_streams(snapshot_streams)
542 .map(|(bank_fields, _accountsdb_fields)| bank_fields.collapse_into()),
543 }?,
544 )
545 })
546}
547
548fn deserialize_status_cache(
549 status_cache_path: &Path,
550) -> snapshot_utils::Result<Vec<BankSlotDelta>> {
551 deserialize_snapshot_data_file(status_cache_path, |stream| {
552 info!(
553 "Rebuilding status cache from {}",
554 status_cache_path.display()
555 );
556 let slot_delta: Vec<BankSlotDelta> = bincode::options()
557 .with_limit(snapshot_utils::MAX_SNAPSHOT_DATA_FILE_SIZE)
558 .with_fixint_encoding()
559 .allow_trailing_bytes()
560 .deserialize_from(stream)?;
561 Ok(slot_delta)
562 })
563}
564
565#[derive(Debug)]
567struct RebuiltBankInfo {
568 duplicates_lt_hash: Option<Box<DuplicatesLtHash>>,
569}
570
571#[allow(clippy::too_many_arguments)]
572fn rebuild_bank_from_unarchived_snapshots(
573 full_snapshot_unpacked_snapshots_dir_and_version: &UnpackedSnapshotsDirAndVersion,
574 incremental_snapshot_unpacked_snapshots_dir_and_version: Option<
575 &UnpackedSnapshotsDirAndVersion,
576 >,
577 account_paths: &[PathBuf],
578 storage_and_next_append_vec_id: StorageAndNextAccountsFileId,
579 genesis_config: &GenesisConfig,
580 runtime_config: &RuntimeConfig,
581 debug_keys: Option<Arc<HashSet<Pubkey>>>,
582 additional_builtins: Option<&[BuiltinPrototype]>,
583 limit_load_slot_count_from_snapshot: Option<usize>,
584 verify_index: bool,
585 accounts_db_config: Option<AccountsDbConfig>,
586 accounts_update_notifier: Option<AccountsUpdateNotifier>,
587 exit: Arc<AtomicBool>,
588) -> snapshot_utils::Result<(Bank, RebuiltBankInfo)> {
589 let (full_snapshot_version, full_snapshot_root_paths) =
590 verify_unpacked_snapshots_dir_and_version(
591 full_snapshot_unpacked_snapshots_dir_and_version,
592 )?;
593 let (incremental_snapshot_version, incremental_snapshot_root_paths) =
594 if let Some(snapshot_unpacked_snapshots_dir_and_version) =
595 incremental_snapshot_unpacked_snapshots_dir_and_version
596 {
597 Some(verify_unpacked_snapshots_dir_and_version(
598 snapshot_unpacked_snapshots_dir_and_version,
599 )?)
600 } else {
601 None
602 }
603 .unzip();
604 info!(
605 "Rebuilding bank from full snapshot {} and incremental snapshot {:?}",
606 full_snapshot_root_paths.snapshot_path().display(),
607 incremental_snapshot_root_paths
608 .as_ref()
609 .map(|paths| paths.snapshot_path()),
610 );
611
612 let snapshot_root_paths = SnapshotRootPaths {
613 full_snapshot_root_file_path: full_snapshot_root_paths.snapshot_path(),
614 incremental_snapshot_root_file_path: incremental_snapshot_root_paths
615 .map(|root_paths| root_paths.snapshot_path()),
616 };
617
618 let (bank, info) = deserialize_snapshot_data_files(&snapshot_root_paths, |snapshot_streams| {
619 Ok(
620 match incremental_snapshot_version.unwrap_or(full_snapshot_version) {
621 SnapshotVersion::V1_2_0 => bank_from_streams(
622 snapshot_streams,
623 account_paths,
624 storage_and_next_append_vec_id,
625 genesis_config,
626 runtime_config,
627 debug_keys,
628 additional_builtins,
629 limit_load_slot_count_from_snapshot,
630 verify_index,
631 accounts_db_config,
632 accounts_update_notifier,
633 exit,
634 ),
635 }?,
636 )
637 })?;
638
639 verify_epoch_stakes(&bank)?;
640
641 let status_cache_path = incremental_snapshot_unpacked_snapshots_dir_and_version
644 .map_or_else(
645 || {
646 full_snapshot_unpacked_snapshots_dir_and_version
647 .unpacked_snapshots_dir
648 .as_path()
649 },
650 |unpacked_snapshots_dir_and_version| {
651 unpacked_snapshots_dir_and_version
652 .unpacked_snapshots_dir
653 .as_path()
654 },
655 )
656 .join(snapshot_utils::SNAPSHOT_STATUS_CACHE_FILENAME);
657 let slot_deltas = deserialize_status_cache(&status_cache_path)?;
658
659 verify_slot_deltas(slot_deltas.as_slice(), &bank)?;
660
661 bank.status_cache.write().unwrap().append(&slot_deltas);
662
663 info!("Rebuilt bank for slot: {}", bank.slot());
664 Ok((
665 bank,
666 RebuiltBankInfo {
667 duplicates_lt_hash: info.duplicates_lt_hash,
668 },
669 ))
670}
671
672#[allow(clippy::too_many_arguments)]
673fn rebuild_bank_from_snapshot(
674 bank_snapshot: &BankSnapshotInfo,
675 account_paths: &[PathBuf],
676 storage_and_next_append_vec_id: StorageAndNextAccountsFileId,
677 genesis_config: &GenesisConfig,
678 runtime_config: &RuntimeConfig,
679 debug_keys: Option<Arc<HashSet<Pubkey>>>,
680 additional_builtins: Option<&[BuiltinPrototype]>,
681 limit_load_slot_count_from_snapshot: Option<usize>,
682 verify_index: bool,
683 accounts_db_config: Option<AccountsDbConfig>,
684 accounts_update_notifier: Option<AccountsUpdateNotifier>,
685 exit: Arc<AtomicBool>,
686) -> snapshot_utils::Result<(Bank, RebuiltBankInfo)> {
687 info!(
688 "Rebuilding bank from snapshot {}",
689 bank_snapshot.snapshot_dir.display(),
690 );
691
692 let snapshot_root_paths = SnapshotRootPaths {
693 full_snapshot_root_file_path: bank_snapshot.snapshot_path(),
694 incremental_snapshot_root_file_path: None,
695 };
696
697 let (bank, info) = deserialize_snapshot_data_files(&snapshot_root_paths, |snapshot_streams| {
698 Ok(bank_from_streams(
699 snapshot_streams,
700 account_paths,
701 storage_and_next_append_vec_id,
702 genesis_config,
703 runtime_config,
704 debug_keys,
705 additional_builtins,
706 limit_load_slot_count_from_snapshot,
707 verify_index,
708 accounts_db_config,
709 accounts_update_notifier,
710 exit,
711 )?)
712 })?;
713
714 verify_epoch_stakes(&bank)?;
715
716 let status_cache_path = bank_snapshot
717 .snapshot_dir
718 .join(snapshot_utils::SNAPSHOT_STATUS_CACHE_FILENAME);
719 let slot_deltas = deserialize_status_cache(&status_cache_path)?;
720
721 verify_slot_deltas(slot_deltas.as_slice(), &bank)?;
722
723 bank.status_cache.write().unwrap().append(&slot_deltas);
724
725 info!("Rebuilt bank for slot: {}", bank.slot());
726 Ok((
727 bank,
728 RebuiltBankInfo {
729 duplicates_lt_hash: info.duplicates_lt_hash,
730 },
731 ))
732}
733
734fn verify_slot_deltas(
736 slot_deltas: &[BankSlotDelta],
737 bank: &Bank,
738) -> std::result::Result<(), VerifySlotDeltasError> {
739 let info = verify_slot_deltas_structural(slot_deltas, bank.slot())?;
740 verify_slot_deltas_with_history(&info.slots, &bank.get_slot_history(), bank.slot())
741}
742
743fn verify_slot_deltas_structural(
746 slot_deltas: &[BankSlotDelta],
747 bank_slot: Slot,
748) -> std::result::Result<VerifySlotDeltasStructuralInfo, VerifySlotDeltasError> {
749 let num_entries = slot_deltas.len();
751 if num_entries > status_cache::MAX_CACHE_ENTRIES {
752 return Err(VerifySlotDeltasError::TooManyEntries(
753 num_entries,
754 status_cache::MAX_CACHE_ENTRIES,
755 ));
756 }
757
758 let mut slots_seen_so_far = HashSet::new();
759 for &(slot, is_root, ..) in slot_deltas {
760 if !is_root {
762 return Err(VerifySlotDeltasError::SlotIsNotRoot(slot));
763 }
764
765 if slot > bank_slot {
767 return Err(VerifySlotDeltasError::SlotGreaterThanMaxRoot(
768 slot, bank_slot,
769 ));
770 }
771
772 let is_duplicate = !slots_seen_so_far.insert(slot);
774 if is_duplicate {
775 return Err(VerifySlotDeltasError::SlotHasMultipleEntries(slot));
776 }
777 }
778
779 assert_eq!(slots_seen_so_far.len(), slot_deltas.len());
781
782 Ok(VerifySlotDeltasStructuralInfo {
783 slots: slots_seen_so_far,
784 })
785}
786
787#[derive(Debug, PartialEq, Eq)]
789struct VerifySlotDeltasStructuralInfo {
790 slots: HashSet<Slot>,
792}
793
794fn verify_slot_deltas_with_history(
797 slots_from_slot_deltas: &HashSet<Slot>,
798 slot_history: &SlotHistory,
799 bank_slot: Slot,
800) -> std::result::Result<(), VerifySlotDeltasError> {
801 if slot_history.newest() != bank_slot {
804 return Err(VerifySlotDeltasError::BadSlotHistory);
805 }
806
807 let slot_missing_from_history = slots_from_slot_deltas
809 .iter()
810 .find(|slot| slot_history.check(**slot) != Check::Found);
811 if let Some(slot) = slot_missing_from_history {
812 return Err(VerifySlotDeltasError::SlotNotFoundInHistory(*slot));
813 }
814
815 let slot_missing_from_deltas = (slot_history.oldest()..=slot_history.newest())
823 .rev()
824 .filter(|slot| slot_history.check(*slot) == Check::Found)
825 .take(status_cache::MAX_CACHE_ENTRIES)
826 .find(|slot| !slots_from_slot_deltas.contains(slot));
827 if let Some(slot) = slot_missing_from_deltas {
828 return Err(VerifySlotDeltasError::SlotNotFoundInDeltas(slot));
829 }
830
831 Ok(())
832}
833
834fn verify_epoch_stakes(bank: &Bank) -> std::result::Result<(), VerifyEpochStakesError> {
836 let current_epoch = bank.epoch();
840 let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
841 let required_epochs = current_epoch..=leader_schedule_epoch;
842 _verify_epoch_stakes(bank.epoch_stakes_map(), required_epochs)
843}
844
845fn _verify_epoch_stakes(
850 epoch_stakes_map: &HashMap<Epoch, EpochStakes>,
851 required_epochs: RangeInclusive<Epoch>,
852) -> std::result::Result<(), VerifyEpochStakesError> {
853 let max_epoch = *required_epochs.end();
858 if let Some(invalid_epoch) = epoch_stakes_map.keys().find(|epoch| **epoch > max_epoch) {
859 return Err(VerifyEpochStakesError::EpochGreaterThanMax(
860 *invalid_epoch,
861 max_epoch,
862 ));
863 }
864
865 if let Some(missing_epoch) = required_epochs
867 .clone()
868 .find(|epoch| !epoch_stakes_map.contains_key(epoch))
869 {
870 return Err(VerifyEpochStakesError::StakesNotFound(
871 missing_epoch,
872 required_epochs,
873 ));
874 }
875
876 Ok(())
877}
878
879pub fn get_snapshot_storages(bank: &Bank) -> Vec<Arc<AccountStorageEntry>> {
881 let mut measure_snapshot_storages = Measure::start("snapshot-storages");
882 let snapshot_storages = bank.get_snapshot_storages(None);
883 measure_snapshot_storages.stop();
884 datapoint_info!(
885 "get_snapshot_storages",
886 (
887 "snapshot-storages-time-ms",
888 measure_snapshot_storages.as_ms(),
889 i64
890 ),
891 );
892
893 snapshot_storages
894}
895
896pub fn bank_to_full_snapshot_archive(
903 bank_snapshots_dir: impl AsRef<Path>,
904 bank: &Bank,
905 snapshot_version: Option<SnapshotVersion>,
906 full_snapshot_archives_dir: impl AsRef<Path>,
907 incremental_snapshot_archives_dir: impl AsRef<Path>,
908 archive_format: ArchiveFormat,
909) -> snapshot_utils::Result<FullSnapshotArchiveInfo> {
910 let snapshot_version = snapshot_version.unwrap_or_default();
911 let temp_bank_snapshots_dir = tempfile::tempdir_in(bank_snapshots_dir)?;
912 bank_to_full_snapshot_archive_with(
913 &temp_bank_snapshots_dir,
914 bank,
915 snapshot_version,
916 full_snapshot_archives_dir,
917 incremental_snapshot_archives_dir,
918 archive_format,
919 )
920}
921
922fn bank_to_full_snapshot_archive_with(
927 bank_snapshots_dir: impl AsRef<Path>,
928 bank: &Bank,
929 snapshot_version: SnapshotVersion,
930 full_snapshot_archives_dir: impl AsRef<Path>,
931 incremental_snapshot_archives_dir: impl AsRef<Path>,
932 archive_format: ArchiveFormat,
933) -> snapshot_utils::Result<FullSnapshotArchiveInfo> {
934 assert!(bank.is_complete());
935 bank.rc
938 .accounts
939 .accounts_db
940 .set_latest_full_snapshot_slot(bank.slot());
941 bank.squash(); bank.rehash(); bank.force_flush_accounts_cache();
944 bank.clean_accounts();
945
946 let merkle_or_lattice_accounts_hash = if bank.is_snapshots_lt_hash_enabled() {
947 MerkleOrLatticeAccountsHash::Lattice
948 } else {
949 let calculated_accounts_hash =
950 bank.update_accounts_hash(CalcAccountsHashDataSource::Storages, false, false);
951 let accounts_hash = bank
952 .get_accounts_hash()
953 .expect("accounts hash is required for snapshot");
954 assert_eq!(accounts_hash, calculated_accounts_hash);
955 MerkleOrLatticeAccountsHash::Merkle(accounts_hash.into())
956 };
957
958 let snapshot_storages = bank.get_snapshot_storages(None);
959 let status_cache_slot_deltas = bank.status_cache.read().unwrap().root_slot_deltas();
960 let accounts_package = AccountsPackage::new_for_snapshot(
961 AccountsPackageKind::Snapshot(SnapshotKind::FullSnapshot),
962 bank,
963 snapshot_storages,
964 status_cache_slot_deltas,
965 None,
966 );
967 let snapshot_package =
968 SnapshotPackage::new(accounts_package, merkle_or_lattice_accounts_hash, None);
969
970 let snapshot_config = SnapshotConfig {
971 full_snapshot_archives_dir: full_snapshot_archives_dir.as_ref().to_path_buf(),
972 incremental_snapshot_archives_dir: incremental_snapshot_archives_dir.as_ref().to_path_buf(),
973 bank_snapshots_dir: bank_snapshots_dir.as_ref().to_path_buf(),
974 archive_format,
975 snapshot_version,
976 ..Default::default()
977 };
978 let snapshot_archive_info =
979 snapshot_utils::serialize_and_archive_snapshot_package(snapshot_package, &snapshot_config)?;
980
981 Ok(FullSnapshotArchiveInfo::new(snapshot_archive_info))
982}
983
984pub fn bank_to_incremental_snapshot_archive(
992 bank_snapshots_dir: impl AsRef<Path>,
993 bank: &Bank,
994 full_snapshot_slot: Slot,
995 snapshot_version: Option<SnapshotVersion>,
996 full_snapshot_archives_dir: impl AsRef<Path>,
997 incremental_snapshot_archives_dir: impl AsRef<Path>,
998 archive_format: ArchiveFormat,
999) -> snapshot_utils::Result<IncrementalSnapshotArchiveInfo> {
1000 let snapshot_version = snapshot_version.unwrap_or_default();
1001
1002 assert!(bank.is_complete());
1003 assert!(bank.slot() > full_snapshot_slot);
1004 bank.rc
1007 .accounts
1008 .accounts_db
1009 .set_latest_full_snapshot_slot(full_snapshot_slot);
1010 bank.squash(); bank.rehash(); bank.force_flush_accounts_cache();
1013 bank.clean_accounts();
1014
1015 let (merkle_or_lattice_accounts_hash, bank_incremental_snapshot_persistence) =
1016 if bank.is_snapshots_lt_hash_enabled() {
1017 (MerkleOrLatticeAccountsHash::Lattice, None)
1018 } else {
1019 let calculated_incremental_accounts_hash =
1020 bank.update_incremental_accounts_hash(full_snapshot_slot);
1021 let (full_accounts_hash, full_capitalization) = bank
1022 .rc
1023 .accounts
1024 .accounts_db
1025 .get_accounts_hash(full_snapshot_slot)
1026 .expect("base accounts hash is required for incremental snapshot");
1027 let (incremental_accounts_hash, incremental_capitalization) = bank
1028 .rc
1029 .accounts
1030 .accounts_db
1031 .get_incremental_accounts_hash(bank.slot())
1032 .expect("incremental accounts hash is required for incremental snapshot");
1033 assert_eq!(
1034 incremental_accounts_hash,
1035 calculated_incremental_accounts_hash,
1036 );
1037 let bank_incremental_snapshot_persistence = BankIncrementalSnapshotPersistence {
1038 full_slot: full_snapshot_slot,
1039 full_hash: full_accounts_hash.into(),
1040 full_capitalization,
1041 incremental_hash: incremental_accounts_hash.into(),
1042 incremental_capitalization,
1043 };
1044 (
1045 MerkleOrLatticeAccountsHash::Merkle(incremental_accounts_hash.into()),
1046 Some(bank_incremental_snapshot_persistence),
1047 )
1048 };
1049
1050 let snapshot_storages = bank.get_snapshot_storages(Some(full_snapshot_slot));
1051 let status_cache_slot_deltas = bank.status_cache.read().unwrap().root_slot_deltas();
1052 let accounts_package = AccountsPackage::new_for_snapshot(
1053 AccountsPackageKind::Snapshot(SnapshotKind::IncrementalSnapshot(full_snapshot_slot)),
1054 bank,
1055 snapshot_storages,
1056 status_cache_slot_deltas,
1057 None,
1058 );
1059 let snapshot_package = SnapshotPackage::new(
1060 accounts_package,
1061 merkle_or_lattice_accounts_hash,
1062 bank_incremental_snapshot_persistence,
1063 );
1064
1065 let temp_bank_snapshots_dir = tempfile::tempdir_in(bank_snapshots_dir)?;
1069 let snapshot_config = SnapshotConfig {
1070 full_snapshot_archives_dir: full_snapshot_archives_dir.as_ref().to_path_buf(),
1071 incremental_snapshot_archives_dir: incremental_snapshot_archives_dir.as_ref().to_path_buf(),
1072 bank_snapshots_dir: temp_bank_snapshots_dir.path().to_path_buf(),
1073 archive_format,
1074 snapshot_version,
1075 ..Default::default()
1076 };
1077 let snapshot_archive_info =
1078 snapshot_utils::serialize_and_archive_snapshot_package(snapshot_package, &snapshot_config)?;
1079
1080 Ok(IncrementalSnapshotArchiveInfo::new(
1081 full_snapshot_slot,
1082 snapshot_archive_info,
1083 ))
1084}
1085
1086#[cfg(test)]
1087mod tests {
1088 use {
1089 super::*,
1090 crate::{
1091 bank::{tests::create_simple_test_bank, BankTestConfig},
1092 bank_forks::BankForks,
1093 genesis_utils,
1094 snapshot_config::SnapshotConfig,
1095 snapshot_utils::{
1096 clean_orphaned_account_snapshot_dirs, create_tmp_accounts_dir_for_tests,
1097 get_bank_snapshot_dir, get_bank_snapshots, get_bank_snapshots_post,
1098 get_bank_snapshots_pre, get_highest_bank_snapshot, get_highest_bank_snapshot_pre,
1099 get_highest_loadable_bank_snapshot, get_snapshot_file_name,
1100 purge_all_bank_snapshots, purge_bank_snapshot,
1101 purge_bank_snapshots_older_than_slot, purge_incomplete_bank_snapshots,
1102 purge_old_bank_snapshots, purge_old_bank_snapshots_at_startup,
1103 snapshot_storage_rebuilder::get_slot_and_append_vec_id, ArchiveFormat,
1104 BankSnapshotKind, BANK_SNAPSHOT_PRE_FILENAME_EXTENSION,
1105 SNAPSHOT_FULL_SNAPSHOT_SLOT_FILENAME,
1106 },
1107 status_cache::Status,
1108 },
1109 solana_accounts_db::{
1110 accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING,
1111 accounts_hash::{CalcAccountsHashConfig, HashStats},
1112 sorted_storages::SortedStorages,
1113 },
1114 solana_sdk::{
1115 feature_set,
1116 genesis_config::create_genesis_config,
1117 native_token::{sol_to_lamports, LAMPORTS_PER_SOL},
1118 signature::{Keypair, Signer},
1119 system_transaction,
1120 transaction::SanitizedTransaction,
1121 },
1122 std::{
1123 fs,
1124 sync::{atomic::Ordering, Arc, RwLock},
1125 },
1126 test_case::test_case,
1127 };
1128
1129 fn create_snapshot_dirs_for_tests(
1130 genesis_config: &GenesisConfig,
1131 bank_snapshots_dir: impl AsRef<Path>,
1132 num_total: usize,
1133 num_posts: usize,
1134 ) -> Bank {
1135 assert!(num_posts <= num_total);
1136
1137 let snapshot_archives_dir = TempDir::new().unwrap();
1140
1141 let mut bank = Arc::new(Bank::new_for_tests(genesis_config));
1142 for i in 0..num_total {
1143 let slot = bank.slot() + 1;
1144 bank = Arc::new(Bank::new_from_parent(bank, &Pubkey::new_unique(), slot));
1145 bank.fill_bank_with_ticks_for_tests();
1146
1147 bank_to_full_snapshot_archive_with(
1148 &bank_snapshots_dir,
1149 &bank,
1150 SnapshotVersion::default(),
1151 &snapshot_archives_dir,
1152 &snapshot_archives_dir,
1153 ArchiveFormat::Tar,
1154 )
1155 .unwrap();
1156
1157 if i >= num_posts {
1159 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
1160 let post = bank_snapshot_dir.join(get_snapshot_file_name(slot));
1161 let pre = post.with_extension(BANK_SNAPSHOT_PRE_FILENAME_EXTENSION);
1162 fs::rename(post, pre).unwrap();
1163 }
1164 }
1165
1166 Arc::into_inner(bank).unwrap()
1167 }
1168
1169 fn new_bank_from_parent_with_bank_forks(
1170 bank_forks: &RwLock<BankForks>,
1171 parent: Arc<Bank>,
1172 collector_id: &Pubkey,
1173 slot: Slot,
1174 ) -> Arc<Bank> {
1175 let bank = Bank::new_from_parent(parent, collector_id, slot);
1176 bank_forks
1177 .write()
1178 .unwrap()
1179 .insert(bank)
1180 .clone_without_scheduler()
1181 }
1182
1183 #[test]
1186 fn test_roundtrip_bank_to_and_from_full_snapshot_simple() {
1187 let genesis_config = GenesisConfig::default();
1188 let original_bank = Bank::new_for_tests(&genesis_config);
1189
1190 while !original_bank.is_complete() {
1191 original_bank.register_unique_tick();
1192 }
1193
1194 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1195 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1196 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1197 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1198 let snapshot_archive_format = ArchiveFormat::Tar;
1199
1200 let snapshot_archive_info = bank_to_full_snapshot_archive(
1201 &bank_snapshots_dir,
1202 &original_bank,
1203 None,
1204 full_snapshot_archives_dir.path(),
1205 incremental_snapshot_archives_dir.path(),
1206 snapshot_archive_format,
1207 )
1208 .unwrap();
1209
1210 let (roundtrip_bank, _) = bank_from_snapshot_archives(
1211 &[accounts_dir],
1212 bank_snapshots_dir.path(),
1213 &snapshot_archive_info,
1214 None,
1215 &genesis_config,
1216 &RuntimeConfig::default(),
1217 None,
1218 None,
1219 None,
1220 false,
1221 false,
1222 false,
1223 false,
1224 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1225 None,
1226 Arc::default(),
1227 )
1228 .unwrap();
1229 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1230 assert_eq!(original_bank, roundtrip_bank);
1231 }
1232
1233 #[test]
1237 fn test_roundtrip_bank_to_and_from_snapshot_complex() {
1238 let collector = Pubkey::new_unique();
1239 let key1 = Keypair::new();
1240 let key2 = Keypair::new();
1241 let key3 = Keypair::new();
1242 let key4 = Keypair::new();
1243 let key5 = Keypair::new();
1244
1245 let (genesis_config, mint_keypair) = create_genesis_config(sol_to_lamports(1_000_000.));
1246 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1247 bank0
1248 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1249 .unwrap();
1250 bank0
1251 .transfer(sol_to_lamports(2.), &mint_keypair, &key2.pubkey())
1252 .unwrap();
1253 bank0
1254 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1255 .unwrap();
1256 while !bank0.is_complete() {
1257 bank0.register_unique_tick();
1258 }
1259
1260 let slot = 1;
1261 let bank1 =
1262 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1263 bank1
1264 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1265 .unwrap();
1266 bank1
1267 .transfer(sol_to_lamports(4.), &mint_keypair, &key4.pubkey())
1268 .unwrap();
1269 bank1
1270 .transfer(sol_to_lamports(5.), &mint_keypair, &key5.pubkey())
1271 .unwrap();
1272 while !bank1.is_complete() {
1273 bank1.register_unique_tick();
1274 }
1275
1276 let slot = slot + 1;
1277 let bank2 =
1278 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1279 bank2
1280 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1281 .unwrap();
1282 while !bank2.is_complete() {
1283 bank2.register_unique_tick();
1284 }
1285
1286 let slot = slot + 1;
1287 let bank3 =
1288 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1289 bank3
1290 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1291 .unwrap();
1292 while !bank3.is_complete() {
1293 bank3.register_unique_tick();
1294 }
1295
1296 let slot = slot + 1;
1297 let bank4 =
1298 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1299 bank4
1300 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1301 .unwrap();
1302 while !bank4.is_complete() {
1303 bank4.register_unique_tick();
1304 }
1305
1306 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1307 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1308 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1309 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1310 let snapshot_archive_format = ArchiveFormat::Tar;
1311
1312 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1313 bank_snapshots_dir.path(),
1314 &bank4,
1315 None,
1316 full_snapshot_archives_dir.path(),
1317 incremental_snapshot_archives_dir.path(),
1318 snapshot_archive_format,
1319 )
1320 .unwrap();
1321
1322 let (roundtrip_bank, _) = bank_from_snapshot_archives(
1323 &[accounts_dir],
1324 bank_snapshots_dir.path(),
1325 &full_snapshot_archive_info,
1326 None,
1327 &genesis_config,
1328 &RuntimeConfig::default(),
1329 None,
1330 None,
1331 None,
1332 false,
1333 false,
1334 false,
1335 false,
1336 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1337 None,
1338 Arc::default(),
1339 )
1340 .unwrap();
1341 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1342 assert_eq!(*bank4, roundtrip_bank);
1343 }
1344
1345 #[test]
1355 fn test_roundtrip_bank_to_and_from_incremental_snapshot() {
1356 let collector = Pubkey::new_unique();
1357 let key1 = Keypair::new();
1358 let key2 = Keypair::new();
1359 let key3 = Keypair::new();
1360 let key4 = Keypair::new();
1361 let key5 = Keypair::new();
1362
1363 let (genesis_config, mint_keypair) = create_genesis_config(sol_to_lamports(1_000_000.));
1364 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1365 bank0
1366 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1367 .unwrap();
1368 bank0
1369 .transfer(sol_to_lamports(2.), &mint_keypair, &key2.pubkey())
1370 .unwrap();
1371 bank0
1372 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1373 .unwrap();
1374 while !bank0.is_complete() {
1375 bank0.register_unique_tick();
1376 }
1377
1378 let slot = 1;
1379 let bank1 =
1380 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1381 bank1
1382 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1383 .unwrap();
1384 bank1
1385 .transfer(sol_to_lamports(4.), &mint_keypair, &key4.pubkey())
1386 .unwrap();
1387 bank1
1388 .transfer(sol_to_lamports(5.), &mint_keypair, &key5.pubkey())
1389 .unwrap();
1390 while !bank1.is_complete() {
1391 bank1.register_unique_tick();
1392 }
1393
1394 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1395 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1396 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1397 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1398 let snapshot_archive_format = ArchiveFormat::Tar;
1399
1400 let full_snapshot_slot = slot;
1401 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1402 bank_snapshots_dir.path(),
1403 &bank1,
1404 None,
1405 full_snapshot_archives_dir.path(),
1406 incremental_snapshot_archives_dir.path(),
1407 snapshot_archive_format,
1408 )
1409 .unwrap();
1410
1411 let slot = slot + 1;
1412 let bank2 =
1413 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1414 bank2
1415 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1416 .unwrap();
1417 while !bank2.is_complete() {
1418 bank2.register_unique_tick();
1419 }
1420
1421 let slot = slot + 1;
1422 let bank3 =
1423 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1424 bank3
1425 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1426 .unwrap();
1427 while !bank3.is_complete() {
1428 bank3.register_unique_tick();
1429 }
1430
1431 let slot = slot + 1;
1432 let bank4 =
1433 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1434 bank4
1435 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1436 .unwrap();
1437 while !bank4.is_complete() {
1438 bank4.register_unique_tick();
1439 }
1440
1441 let incremental_snapshot_archive_info = bank_to_incremental_snapshot_archive(
1442 bank_snapshots_dir.path(),
1443 &bank4,
1444 full_snapshot_slot,
1445 None,
1446 full_snapshot_archives_dir.path(),
1447 incremental_snapshot_archives_dir.path(),
1448 snapshot_archive_format,
1449 )
1450 .unwrap();
1451
1452 let (roundtrip_bank, _) = bank_from_snapshot_archives(
1453 &[accounts_dir],
1454 bank_snapshots_dir.path(),
1455 &full_snapshot_archive_info,
1456 Some(&incremental_snapshot_archive_info),
1457 &genesis_config,
1458 &RuntimeConfig::default(),
1459 None,
1460 None,
1461 None,
1462 false,
1463 false,
1464 false,
1465 false,
1466 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1467 None,
1468 Arc::default(),
1469 )
1470 .unwrap();
1471 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1472 assert_eq!(*bank4, roundtrip_bank);
1473 }
1474
1475 #[test]
1477 fn test_bank_from_latest_snapshot_archives() {
1478 let collector = Pubkey::new_unique();
1479 let key1 = Keypair::new();
1480 let key2 = Keypair::new();
1481 let key3 = Keypair::new();
1482
1483 let (genesis_config, mint_keypair) = create_genesis_config(sol_to_lamports(1_000_000.));
1484 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1485 bank0
1486 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1487 .unwrap();
1488 bank0
1489 .transfer(sol_to_lamports(2.), &mint_keypair, &key2.pubkey())
1490 .unwrap();
1491 bank0
1492 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1493 .unwrap();
1494 while !bank0.is_complete() {
1495 bank0.register_unique_tick();
1496 }
1497
1498 let slot = 1;
1499 let bank1 =
1500 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1501 bank1
1502 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1503 .unwrap();
1504 bank1
1505 .transfer(sol_to_lamports(2.), &mint_keypair, &key2.pubkey())
1506 .unwrap();
1507 bank1
1508 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1509 .unwrap();
1510 while !bank1.is_complete() {
1511 bank1.register_unique_tick();
1512 }
1513
1514 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1515 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1516 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1517 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1518 let snapshot_archive_format = ArchiveFormat::Tar;
1519
1520 let full_snapshot_slot = slot;
1521 bank_to_full_snapshot_archive(
1522 &bank_snapshots_dir,
1523 &bank1,
1524 None,
1525 &full_snapshot_archives_dir,
1526 &incremental_snapshot_archives_dir,
1527 snapshot_archive_format,
1528 )
1529 .unwrap();
1530
1531 let slot = slot + 1;
1532 let bank2 =
1533 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1534 bank2
1535 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1536 .unwrap();
1537 while !bank2.is_complete() {
1538 bank2.register_unique_tick();
1539 }
1540
1541 let slot = slot + 1;
1542 let bank3 =
1543 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1544 bank3
1545 .transfer(sol_to_lamports(2.), &mint_keypair, &key2.pubkey())
1546 .unwrap();
1547 while !bank3.is_complete() {
1548 bank3.register_unique_tick();
1549 }
1550
1551 let slot = slot + 1;
1552 let bank4 =
1553 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1554 bank4
1555 .transfer(sol_to_lamports(3.), &mint_keypair, &key3.pubkey())
1556 .unwrap();
1557 while !bank4.is_complete() {
1558 bank4.register_unique_tick();
1559 }
1560
1561 bank_to_incremental_snapshot_archive(
1562 &bank_snapshots_dir,
1563 &bank4,
1564 full_snapshot_slot,
1565 None,
1566 &full_snapshot_archives_dir,
1567 &incremental_snapshot_archives_dir,
1568 snapshot_archive_format,
1569 )
1570 .unwrap();
1571
1572 let (deserialized_bank, ..) = bank_from_latest_snapshot_archives(
1573 &bank_snapshots_dir,
1574 &full_snapshot_archives_dir,
1575 &incremental_snapshot_archives_dir,
1576 &[accounts_dir],
1577 &genesis_config,
1578 &RuntimeConfig::default(),
1579 None,
1580 None,
1581 None,
1582 false,
1583 false,
1584 false,
1585 false,
1586 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1587 None,
1588 Arc::default(),
1589 )
1590 .unwrap();
1591 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1592 assert_eq!(deserialized_bank, *bank4);
1593 }
1594
1595 #[test]
1618 fn test_incremental_snapshots_handle_zero_lamport_accounts() {
1619 let collector = Pubkey::new_unique();
1620 let key1 = Keypair::new();
1621 let key2 = Keypair::new();
1622
1623 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1624 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1625 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1626 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1627 let snapshot_archive_format = ArchiveFormat::Tar;
1628
1629 let (mut genesis_config, mint_keypair) = create_genesis_config(sol_to_lamports(1_000_000.));
1630 genesis_config.fee_rate_governor = solana_sdk::fee_calculator::FeeRateGovernor::new(0, 0);
1632
1633 let lamports_to_transfer = sol_to_lamports(123_456.);
1634 let (bank0, bank_forks) = Bank::new_with_paths_for_tests(
1635 &genesis_config,
1636 Arc::<RuntimeConfig>::default(),
1637 BankTestConfig::default(),
1638 vec![accounts_dir.clone()],
1639 )
1640 .wrap_with_bank_forks_for_tests();
1641 bank0
1642 .transfer(lamports_to_transfer, &mint_keypair, &key2.pubkey())
1643 .unwrap();
1644 while !bank0.is_complete() {
1645 bank0.register_unique_tick();
1646 }
1647
1648 let slot = 1;
1649 let bank1 =
1650 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1651 bank1
1652 .transfer(lamports_to_transfer, &key2, &key1.pubkey())
1653 .unwrap();
1654 while !bank1.is_complete() {
1655 bank1.register_unique_tick();
1656 }
1657
1658 let full_snapshot_slot = slot;
1659 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1660 bank_snapshots_dir.path(),
1661 &bank1,
1662 None,
1663 full_snapshot_archives_dir.path(),
1664 incremental_snapshot_archives_dir.path(),
1665 snapshot_archive_format,
1666 )
1667 .unwrap();
1668
1669 let slot = slot + 1;
1670 let bank2 =
1671 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1672 let blockhash = bank2.last_blockhash();
1673 let tx = SanitizedTransaction::from_transaction_for_tests(system_transaction::transfer(
1674 &key1,
1675 &key2.pubkey(),
1676 lamports_to_transfer,
1677 blockhash,
1678 ));
1679 let fee = bank2.get_fee_for_message(tx.message()).unwrap();
1680 let tx = system_transaction::transfer(
1681 &key1,
1682 &key2.pubkey(),
1683 lamports_to_transfer - fee,
1684 blockhash,
1685 );
1686 bank2.process_transaction(&tx).unwrap();
1687 assert_eq!(
1688 bank2.get_balance(&key1.pubkey()),
1689 0,
1690 "Ensure Account1's balance is zero"
1691 );
1692 while !bank2.is_complete() {
1693 bank2.register_unique_tick();
1694 }
1695
1696 let incremental_snapshot_archive_info = bank_to_incremental_snapshot_archive(
1699 bank_snapshots_dir.path(),
1700 &bank2,
1701 full_snapshot_slot,
1702 None,
1703 full_snapshot_archives_dir.path(),
1704 incremental_snapshot_archives_dir.path(),
1705 snapshot_archive_format,
1706 )
1707 .unwrap();
1708 let (deserialized_bank, _) = bank_from_snapshot_archives(
1709 &[accounts_dir.clone()],
1710 bank_snapshots_dir.path(),
1711 &full_snapshot_archive_info,
1712 Some(&incremental_snapshot_archive_info),
1713 &genesis_config,
1714 &RuntimeConfig::default(),
1715 None,
1716 None,
1717 None,
1718 false,
1719 false,
1720 false,
1721 false,
1722 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1723 None,
1724 Arc::default(),
1725 )
1726 .unwrap();
1727 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1728 assert_eq!(
1729 deserialized_bank, *bank2,
1730 "Ensure rebuilding from an incremental snapshot works"
1731 );
1732
1733 let slot = slot + 1;
1734 let bank3 =
1735 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1736 bank3
1738 .transfer(lamports_to_transfer, &mint_keypair, &key2.pubkey())
1739 .unwrap();
1740 while !bank3.is_complete() {
1741 bank3.register_unique_tick();
1742 }
1743
1744 let slot = slot + 1;
1745 let bank4 =
1746 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1747 while !bank4.is_complete() {
1748 bank4.register_unique_tick();
1749 }
1750
1751 bank4.squash();
1753 bank4.clean_accounts();
1754 assert!(
1755 bank4.get_account_modified_slot(&key1.pubkey()).is_none(),
1756 "Ensure Account1 has been cleaned and purged from AccountsDb"
1757 );
1758
1759 let incremental_snapshot_archive_info = bank_to_incremental_snapshot_archive(
1762 bank_snapshots_dir.path(),
1763 &bank4,
1764 full_snapshot_slot,
1765 None,
1766 full_snapshot_archives_dir.path(),
1767 incremental_snapshot_archives_dir.path(),
1768 snapshot_archive_format,
1769 )
1770 .unwrap();
1771
1772 let (deserialized_bank, _) = bank_from_snapshot_archives(
1773 &[accounts_dir],
1774 bank_snapshots_dir.path(),
1775 &full_snapshot_archive_info,
1776 Some(&incremental_snapshot_archive_info),
1777 &genesis_config,
1778 &RuntimeConfig::default(),
1779 None,
1780 None,
1781 None,
1782 false,
1783 false,
1784 false,
1785 false,
1786 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1787 None,
1788 Arc::default(),
1789 )
1790 .unwrap();
1791 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1792 assert_eq!(
1793 deserialized_bank, *bank4,
1794 "Ensure rebuilding from an incremental snapshot works",
1795 );
1796 assert!(
1797 deserialized_bank
1798 .get_account_modified_slot(&key1.pubkey())
1799 .is_none(),
1800 "Ensure Account1 has not been brought back from the dead"
1801 );
1802 }
1803
1804 #[test_case(StorageAccess::Mmap)]
1805 #[test_case(StorageAccess::File)]
1806 fn test_bank_fields_from_snapshot(storage_access: StorageAccess) {
1807 let collector = Pubkey::new_unique();
1808 let key1 = Keypair::new();
1809
1810 let (genesis_config, mint_keypair) = create_genesis_config(sol_to_lamports(1_000_000.));
1811 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1812 while !bank0.is_complete() {
1813 bank0.register_unique_tick();
1814 }
1815
1816 let slot = 1;
1817 let bank1 =
1818 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1819 while !bank1.is_complete() {
1820 bank1.register_unique_tick();
1821 }
1822
1823 let all_snapshots_dir = tempfile::TempDir::new().unwrap();
1824 let snapshot_archive_format = ArchiveFormat::Tar;
1825
1826 let full_snapshot_slot = slot;
1827 bank_to_full_snapshot_archive(
1828 &all_snapshots_dir,
1829 &bank1,
1830 None,
1831 &all_snapshots_dir,
1832 &all_snapshots_dir,
1833 snapshot_archive_format,
1834 )
1835 .unwrap();
1836
1837 let slot = slot + 1;
1838 let bank2 =
1839 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1840 bank2
1841 .transfer(sol_to_lamports(1.), &mint_keypair, &key1.pubkey())
1842 .unwrap();
1843 while !bank2.is_complete() {
1844 bank2.register_unique_tick();
1845 }
1846
1847 bank_to_incremental_snapshot_archive(
1848 &all_snapshots_dir,
1849 &bank2,
1850 full_snapshot_slot,
1851 None,
1852 &all_snapshots_dir,
1853 &all_snapshots_dir,
1854 snapshot_archive_format,
1855 )
1856 .unwrap();
1857
1858 let bank_fields = bank_fields_from_snapshot_archives(
1859 &all_snapshots_dir,
1860 &all_snapshots_dir,
1861 storage_access,
1862 )
1863 .unwrap();
1864 assert_eq!(bank_fields.slot, bank2.slot());
1865 assert_eq!(bank_fields.parent_slot, bank2.parent_slot());
1866 }
1867
1868 #[test]
1869 fn test_bank_snapshot_dir_accounts_hardlinks() {
1870 let bank = Bank::new_for_tests(&GenesisConfig::default());
1871 bank.fill_bank_with_ticks_for_tests();
1872
1873 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1874 let snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1875 bank_to_full_snapshot_archive_with(
1876 &bank_snapshots_dir,
1877 &bank,
1878 SnapshotVersion::default(),
1879 &snapshot_archives_dir,
1880 &snapshot_archives_dir,
1881 ArchiveFormat::Tar,
1882 )
1883 .unwrap();
1884
1885 let accounts_hardlinks_dir = get_bank_snapshot_dir(&bank_snapshots_dir, bank.slot())
1886 .join(snapshot_utils::SNAPSHOT_ACCOUNTS_HARDLINKS);
1887 assert!(fs::metadata(&accounts_hardlinks_dir).is_ok());
1888
1889 let mut hardlink_dirs = Vec::new();
1890 for entry in fs::read_dir(accounts_hardlinks_dir).unwrap() {
1892 let entry = entry.unwrap();
1893 let symlink = entry.path();
1894 let dst_path = fs::read_link(symlink).unwrap();
1895 assert!(fs::metadata(&dst_path).is_ok());
1896 hardlink_dirs.push(dst_path);
1897 }
1898
1899 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, bank.slot());
1900 assert!(purge_bank_snapshot(bank_snapshot_dir).is_ok());
1901
1902 assert!(hardlink_dirs.iter().all(|dir| fs::metadata(dir).is_err()));
1904 }
1905
1906 #[test]
1907 fn test_get_highest_bank_snapshot() {
1908 let genesis_config = GenesisConfig::default();
1909 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1910 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 4, 0);
1911
1912 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1913 assert_eq!(snapshot.slot, 4);
1914
1915 let complete_flag_file = snapshot
1916 .snapshot_dir
1917 .join(snapshot_utils::SNAPSHOT_STATE_COMPLETE_FILENAME);
1918 fs::remove_file(complete_flag_file).unwrap();
1919 let snapshot_dir_4 = snapshot.snapshot_dir;
1921 assert!(snapshot_dir_4.exists());
1922 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1923 assert_eq!(snapshot.slot, 3);
1924
1925 let snapshot_version_file = snapshot
1926 .snapshot_dir
1927 .join(snapshot_utils::SNAPSHOT_VERSION_FILENAME);
1928 fs::remove_file(snapshot_version_file).unwrap();
1929 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1930 assert_eq!(snapshot.slot, 2);
1931
1932 let status_cache_file = snapshot
1933 .snapshot_dir
1934 .join(snapshot_utils::SNAPSHOT_STATUS_CACHE_FILENAME);
1935 fs::remove_file(status_cache_file).unwrap();
1936 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1937 assert_eq!(snapshot.slot, 1);
1938 }
1939
1940 #[test]
1941 fn test_clean_orphaned_account_snapshot_dirs() {
1942 let genesis_config = GenesisConfig::default();
1943 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1944 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 2, 0);
1945
1946 let snapshot_dir_slot_2 = bank_snapshots_dir.path().join("2");
1947 let accounts_link_dir_slot_2 =
1948 snapshot_dir_slot_2.join(snapshot_utils::SNAPSHOT_ACCOUNTS_HARDLINKS);
1949
1950 let hardlink_dirs_slot_2: Vec<PathBuf> = fs::read_dir(accounts_link_dir_slot_2)
1953 .unwrap()
1954 .map(|entry| {
1955 let symlink = entry.unwrap().path();
1956 fs::read_link(symlink).unwrap()
1957 })
1958 .collect();
1959
1960 fs::remove_dir_all(snapshot_dir_slot_2).unwrap();
1962
1963 assert!(hardlink_dirs_slot_2
1965 .iter()
1966 .all(|dir| fs::metadata(dir).is_ok()));
1967
1968 let account_snapshot_paths: Vec<PathBuf> = hardlink_dirs_slot_2
1969 .iter()
1970 .map(|dir| dir.parent().unwrap().parent().unwrap().to_path_buf())
1971 .collect();
1972 clean_orphaned_account_snapshot_dirs(&bank_snapshots_dir, &account_snapshot_paths).unwrap();
1974
1975 assert!(hardlink_dirs_slot_2
1977 .iter()
1978 .all(|dir| fs::metadata(dir).is_err()));
1979 }
1980
1981 #[test]
1982 fn test_purge_incomplete_bank_snapshots() {
1983 let genesis_config = GenesisConfig::default();
1984 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1985 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 2, 0);
1986
1987 for slot in [1, 2] {
1989 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
1990 let state_complete_file =
1991 bank_snapshot_dir.join(snapshot_utils::SNAPSHOT_STATE_COMPLETE_FILENAME);
1992 fs::remove_file(state_complete_file).unwrap();
1993 }
1994
1995 purge_incomplete_bank_snapshots(&bank_snapshots_dir);
1996
1997 for slot in [1, 2] {
1999 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
2000 assert!(!bank_snapshot_dir.exists());
2001 }
2002 }
2003
2004 #[test]
2010 fn test_incremental_snapshot_with_incremental_accounts_hash() {
2011 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2012 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
2013 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
2014
2015 let mut genesis_config_info = genesis_utils::create_genesis_config_with_leader(
2016 1_000_000 * LAMPORTS_PER_SOL,
2017 &Pubkey::new_unique(),
2018 100 * LAMPORTS_PER_SOL,
2019 );
2020 let mint = &genesis_config_info.mint_keypair;
2021 genesis_config_info
2025 .genesis_config
2026 .accounts
2027 .remove(&feature_set::snapshots_lt_hash::id())
2028 .unwrap();
2029 genesis_config_info
2032 .genesis_config
2033 .accounts
2034 .remove(&feature_set::accounts_lt_hash::id())
2035 .unwrap();
2036
2037 let do_transfers = |bank: &Bank| {
2038 let key1 = Keypair::new(); let key2 = Keypair::new(); let key3 = Keypair::new(); let amount = 123_456_789;
2043 let fee = {
2044 let blockhash = bank.last_blockhash();
2045 let transaction = SanitizedTransaction::from_transaction_for_tests(
2046 system_transaction::transfer(&key2, &key3.pubkey(), amount, blockhash),
2047 );
2048 bank.get_fee_for_message(transaction.message()).unwrap()
2049 };
2050 bank.transfer(amount + fee, mint, &key1.pubkey()).unwrap();
2051 bank.transfer(amount + fee, mint, &key2.pubkey()).unwrap();
2052 bank.transfer(amount + fee, &key2, &key3.pubkey()).unwrap();
2053 assert_eq!(bank.get_balance(&key2.pubkey()), 0);
2054
2055 bank.fill_bank_with_ticks_for_tests();
2056 };
2057
2058 let (mut bank, bank_forks) =
2059 Bank::new_with_bank_forks_for_tests(&genesis_config_info.genesis_config);
2060
2061 for _ in 0..5 {
2063 let slot = bank.slot() + 1;
2064 bank = new_bank_from_parent_with_bank_forks(
2065 bank_forks.as_ref(),
2066 bank,
2067 &Pubkey::new_unique(),
2068 slot,
2069 );
2070 do_transfers(&bank);
2071 }
2072
2073 let full_snapshot_archive = bank_to_full_snapshot_archive(
2075 &bank_snapshots_dir,
2076 &bank,
2077 None,
2078 &full_snapshot_archives_dir,
2079 &incremental_snapshot_archives_dir,
2080 ArchiveFormat::Tar,
2081 )
2082 .unwrap();
2083 let full_accounts_hash = bank
2084 .rc
2085 .accounts
2086 .accounts_db
2087 .get_accounts_hash(bank.slot())
2088 .unwrap();
2089
2090 for _ in 0..5 {
2092 let slot = bank.slot() + 1;
2093 bank = new_bank_from_parent_with_bank_forks(
2094 bank_forks.as_ref(),
2095 bank,
2096 &Pubkey::new_unique(),
2097 slot,
2098 );
2099 do_transfers(&bank);
2100 }
2101
2102 let incremental_snapshot_archive = bank_to_incremental_snapshot_archive(
2104 &bank_snapshots_dir,
2105 &bank,
2106 full_snapshot_archive.slot(),
2107 None,
2108 &full_snapshot_archives_dir,
2109 &incremental_snapshot_archives_dir,
2110 ArchiveFormat::Tar,
2111 )
2112 .unwrap();
2113 let incremental_accounts_hash = bank
2114 .rc
2115 .accounts
2116 .accounts_db
2117 .get_incremental_accounts_hash(bank.slot())
2118 .unwrap();
2119
2120 let other_accounts_dir = tempfile::TempDir::new().unwrap();
2122 let other_bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2123 let (deserialized_bank, _) = bank_from_snapshot_archives(
2124 &[other_accounts_dir.path().to_path_buf()],
2125 &other_bank_snapshots_dir,
2126 &full_snapshot_archive,
2127 Some(&incremental_snapshot_archive),
2128 &genesis_config_info.genesis_config,
2129 &RuntimeConfig::default(),
2130 None,
2131 None,
2132 None,
2133 false,
2134 false,
2135 false,
2136 false,
2137 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
2138 None,
2139 Arc::default(),
2140 )
2141 .unwrap();
2142 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
2143 assert_eq!(&deserialized_bank, bank.as_ref());
2144
2145 let deserialized_accounts_hash = deserialized_bank
2147 .rc
2148 .accounts
2149 .accounts_db
2150 .get_accounts_hash(full_snapshot_archive.slot())
2151 .unwrap();
2152 assert_eq!(deserialized_accounts_hash, full_accounts_hash);
2153
2154 let deserialized_incrmental_accounts_hash = deserialized_bank
2156 .rc
2157 .accounts
2158 .accounts_db
2159 .get_incremental_accounts_hash(incremental_snapshot_archive.slot())
2160 .unwrap();
2161 assert_eq!(
2162 deserialized_incrmental_accounts_hash,
2163 incremental_accounts_hash
2164 );
2165
2166 let other_incremental_snapshot_storages =
2168 deserialized_bank.get_snapshot_storages(Some(full_snapshot_archive.slot()));
2169 let other_incremental_accounts_hash = bank
2170 .rc
2171 .accounts
2172 .accounts_db
2173 .calculate_incremental_accounts_hash(
2174 &CalcAccountsHashConfig {
2175 use_bg_thread_pool: false,
2176 ancestors: None,
2177 epoch_schedule: deserialized_bank.epoch_schedule(),
2178 rent_collector: deserialized_bank.rent_collector(),
2179 store_detailed_debug_info_on_failure: false,
2180 },
2181 &SortedStorages::new(&other_incremental_snapshot_storages),
2182 HashStats::default(),
2183 );
2184 assert_eq!(other_incremental_accounts_hash, incremental_accounts_hash);
2185 }
2186
2187 #[test_case(StorageAccess::Mmap)]
2188 #[test_case(StorageAccess::File)]
2189 fn test_bank_from_snapshot_dir(storage_access: StorageAccess) {
2190 let genesis_config = GenesisConfig::default();
2191 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2192 let bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 3, 0);
2193
2194 let bank_snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
2195 let account_paths = &bank.rc.accounts.accounts_db.paths;
2196
2197 let (bank_constructed, ..) = bank_from_snapshot_dir(
2198 account_paths,
2199 &bank_snapshot,
2200 &genesis_config,
2201 &RuntimeConfig::default(),
2202 None,
2203 None,
2204 None,
2205 false,
2206 Some(AccountsDbConfig {
2207 storage_access,
2208 ..ACCOUNTS_DB_CONFIG_FOR_TESTING
2209 }),
2210 None,
2211 Arc::default(),
2212 )
2213 .unwrap();
2214
2215 bank_constructed.wait_for_initial_accounts_hash_verification_completed_for_tests();
2216 assert_eq!(bank_constructed, bank);
2217
2218 let mut max_id = 0;
2220 for path in account_paths {
2221 fs::read_dir(path).unwrap().for_each(|entry| {
2222 let path = entry.unwrap().path();
2223 let filename = path.file_name().unwrap();
2224 let (_slot, append_vec_id) =
2225 get_slot_and_append_vec_id(filename.to_str().unwrap()).unwrap();
2226 max_id = std::cmp::max(max_id, append_vec_id);
2227 });
2228 }
2229 let next_id = bank.accounts().accounts_db.next_id.load(Ordering::Relaxed) as usize;
2230 assert_eq!(max_id, next_id - 1);
2231 }
2232
2233 #[test]
2234 fn test_bank_from_latest_snapshot_dir() {
2235 let genesis_config = GenesisConfig::default();
2236 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2237 let bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 3, 3);
2238
2239 let account_paths = &bank.rc.accounts.accounts_db.paths;
2240
2241 let deserialized_bank = bank_from_latest_snapshot_dir(
2242 &bank_snapshots_dir,
2243 &genesis_config,
2244 &RuntimeConfig::default(),
2245 account_paths,
2246 None,
2247 None,
2248 None,
2249 false,
2250 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
2251 None,
2252 Arc::default(),
2253 )
2254 .unwrap();
2255
2256 assert_eq!(
2257 deserialized_bank, bank,
2258 "Ensure rebuilding bank from the highest snapshot dir results in the highest bank",
2259 );
2260 }
2261
2262 #[test]
2263 fn test_purge_all_bank_snapshots() {
2264 let genesis_config = GenesisConfig::default();
2265 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2266 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 10, 5);
2267 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 10);
2271 purge_all_bank_snapshots(&bank_snapshots_dir);
2272 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 0);
2273 }
2274
2275 #[test]
2276 fn test_purge_old_bank_snapshots() {
2277 let genesis_config = GenesisConfig::default();
2278 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2279 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 10, 5);
2280 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 10);
2284
2285 purge_old_bank_snapshots(&bank_snapshots_dir, 3, Some(BankSnapshotKind::Pre));
2286 assert_eq!(get_bank_snapshots_pre(&bank_snapshots_dir).len(), 3);
2287
2288 purge_old_bank_snapshots(&bank_snapshots_dir, 2, Some(BankSnapshotKind::Post));
2289 assert_eq!(get_bank_snapshots_post(&bank_snapshots_dir).len(), 2);
2290
2291 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 5);
2292
2293 purge_old_bank_snapshots(&bank_snapshots_dir, 2, None);
2294 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 2);
2295
2296 purge_old_bank_snapshots(&bank_snapshots_dir, 0, None);
2297 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 0);
2298 }
2299
2300 #[test]
2301 fn test_purge_bank_snapshots_older_than_slot() {
2302 let genesis_config = GenesisConfig::default();
2303 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2304
2305 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 9, 6);
2307 let bank_snapshots_before = get_bank_snapshots(&bank_snapshots_dir);
2308
2309 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, 0);
2310 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2311 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len());
2312
2313 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, 3);
2314 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2315 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len() + 2);
2316
2317 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, 8);
2318 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2319 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len() + 7);
2320
2321 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, Slot::MAX);
2322 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2323 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len() + 9);
2324 assert!(bank_snapshots_after.is_empty());
2325 }
2326
2327 #[test]
2328 fn test_purge_old_bank_snapshots_at_startup() {
2329 let genesis_config = GenesisConfig::default();
2330 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2331
2332 let _bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 9, 6);
2334
2335 purge_old_bank_snapshots_at_startup(&bank_snapshots_dir);
2336
2337 let bank_snapshots_pre = get_bank_snapshots_pre(&bank_snapshots_dir);
2338 assert!(bank_snapshots_pre.is_empty());
2339
2340 let bank_snapshots_post = get_bank_snapshots_post(&bank_snapshots_dir);
2341 assert_eq!(bank_snapshots_post.len(), 1);
2342 assert_eq!(bank_snapshots_post.first().unwrap().slot, 6);
2343 }
2344
2345 #[test]
2346 fn test_verify_slot_deltas_structural_bad_too_many_entries() {
2347 let bank_slot = status_cache::MAX_CACHE_ENTRIES as Slot + 1;
2348 let slot_deltas: Vec<_> = (0..bank_slot)
2349 .map(|slot| (slot, true, Status::default()))
2350 .collect();
2351
2352 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2353 assert_eq!(
2354 result,
2355 Err(VerifySlotDeltasError::TooManyEntries(
2356 status_cache::MAX_CACHE_ENTRIES + 1,
2357 status_cache::MAX_CACHE_ENTRIES
2358 )),
2359 );
2360 }
2361
2362 #[test]
2363 fn test_verify_slot_deltas_structural_good() {
2364 let slot_deltas = vec![
2366 (222, true, Status::default()),
2367 (333, true, Status::default()),
2368 (111, true, Status::default()),
2369 ];
2370
2371 let bank_slot = 333;
2372 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2373 assert_eq!(
2374 result,
2375 Ok(VerifySlotDeltasStructuralInfo {
2376 slots: HashSet::from([111, 222, 333])
2377 })
2378 );
2379 }
2380
2381 #[test]
2382 fn test_verify_slot_deltas_structural_bad_slot_not_root() {
2383 let slot_deltas = vec![
2384 (111, true, Status::default()),
2385 (222, false, Status::default()), (333, true, Status::default()),
2387 ];
2388
2389 let bank_slot = 333;
2390 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2391 assert_eq!(result, Err(VerifySlotDeltasError::SlotIsNotRoot(222)));
2392 }
2393
2394 #[test]
2395 fn test_verify_slot_deltas_structural_bad_slot_greater_than_bank() {
2396 let slot_deltas = vec![
2397 (222, true, Status::default()),
2398 (111, true, Status::default()),
2399 (555, true, Status::default()), ];
2401
2402 let bank_slot = 444;
2403 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2404 assert_eq!(
2405 result,
2406 Err(VerifySlotDeltasError::SlotGreaterThanMaxRoot(
2407 555, bank_slot
2408 )),
2409 );
2410 }
2411
2412 #[test]
2413 fn test_verify_slot_deltas_structural_bad_slot_has_multiple_entries() {
2414 let slot_deltas = vec![
2415 (111, true, Status::default()),
2416 (222, true, Status::default()),
2417 (111, true, Status::default()), ];
2419
2420 let bank_slot = 222;
2421 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2422 assert_eq!(
2423 result,
2424 Err(VerifySlotDeltasError::SlotHasMultipleEntries(111)),
2425 );
2426 }
2427
2428 #[test]
2429 fn test_verify_slot_deltas_with_history_good() {
2430 let mut slots_from_slot_deltas = HashSet::default();
2431 let mut slot_history = SlotHistory::default();
2432 for slot in [0, 111, 222, 333, 444] {
2434 slots_from_slot_deltas.insert(slot);
2435 slot_history.add(slot);
2436 }
2437
2438 let bank_slot = 444;
2439 let result =
2440 verify_slot_deltas_with_history(&slots_from_slot_deltas, &slot_history, bank_slot);
2441 assert_eq!(result, Ok(()));
2442 }
2443
2444 #[test]
2445 fn test_verify_slot_deltas_with_history_bad_slot_history() {
2446 let bank_slot = 444;
2447 let result = verify_slot_deltas_with_history(
2448 &HashSet::default(),
2449 &SlotHistory::default(), bank_slot,
2451 );
2452 assert_eq!(result, Err(VerifySlotDeltasError::BadSlotHistory));
2453 }
2454
2455 #[test]
2456 fn test_verify_slot_deltas_with_history_bad_slot_not_in_history() {
2457 let slots_from_slot_deltas = HashSet::from([
2458 0, 444, 222,
2460 ]);
2461 let mut slot_history = SlotHistory::default();
2462 slot_history.add(444); let bank_slot = 444;
2465 let result =
2466 verify_slot_deltas_with_history(&slots_from_slot_deltas, &slot_history, bank_slot);
2467
2468 assert_eq!(
2469 result,
2470 Err(VerifySlotDeltasError::SlotNotFoundInHistory(222)),
2471 );
2472 }
2473
2474 #[test]
2475 fn test_verify_slot_deltas_with_history_bad_slot_not_in_deltas() {
2476 let slots_from_slot_deltas = HashSet::from([
2477 0, 444, 222,
2479 ]);
2481 let mut slot_history = SlotHistory::default();
2482 slot_history.add(222);
2483 slot_history.add(333);
2484 slot_history.add(444);
2485
2486 let bank_slot = 444;
2487 let result =
2488 verify_slot_deltas_with_history(&slots_from_slot_deltas, &slot_history, bank_slot);
2489
2490 assert_eq!(
2491 result,
2492 Err(VerifySlotDeltasError::SlotNotFoundInDeltas(333)),
2493 );
2494 }
2495
2496 #[test]
2497 fn test_verify_epoch_stakes_good() {
2498 let bank = create_simple_test_bank(100 * LAMPORTS_PER_SOL);
2499 assert_eq!(verify_epoch_stakes(&bank), Ok(()));
2500 }
2501
2502 #[test]
2503 fn test_verify_epoch_stakes_bad() {
2504 let bank = create_simple_test_bank(100 * LAMPORTS_PER_SOL);
2505 let current_epoch = bank.epoch();
2506 let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
2507 let required_epochs = current_epoch..=leader_schedule_epoch;
2508
2509 {
2511 let mut epoch_stakes_map = bank.epoch_stakes_map().clone();
2512 let invalid_epoch = *required_epochs.end() + 1;
2513 epoch_stakes_map.insert(
2514 invalid_epoch,
2515 bank.epoch_stakes(bank.epoch()).cloned().unwrap(),
2516 );
2517
2518 assert_eq!(
2519 _verify_epoch_stakes(&epoch_stakes_map, required_epochs.clone()),
2520 Err(VerifyEpochStakesError::EpochGreaterThanMax(
2521 invalid_epoch,
2522 *required_epochs.end(),
2523 )),
2524 );
2525 }
2526
2527 {
2529 for removed_epoch in required_epochs.clone() {
2530 let mut epoch_stakes_map = bank.epoch_stakes_map().clone();
2531 let removed_stakes = epoch_stakes_map.remove(&removed_epoch);
2532 assert!(removed_stakes.is_some());
2533
2534 assert_eq!(
2535 _verify_epoch_stakes(&epoch_stakes_map, required_epochs.clone()),
2536 Err(VerifyEpochStakesError::StakesNotFound(
2537 removed_epoch,
2538 required_epochs.clone(),
2539 )),
2540 );
2541 }
2542 }
2543 }
2544
2545 #[test]
2546 fn test_get_highest_loadable_bank_snapshot() {
2547 let bank_snapshots_dir = TempDir::new().unwrap();
2548 let snapshot_archives_dir = TempDir::new().unwrap();
2549
2550 let snapshot_config = SnapshotConfig {
2551 bank_snapshots_dir: bank_snapshots_dir.as_ref().to_path_buf(),
2552 full_snapshot_archives_dir: snapshot_archives_dir.as_ref().to_path_buf(),
2553 incremental_snapshot_archives_dir: snapshot_archives_dir.as_ref().to_path_buf(),
2554 ..Default::default()
2555 };
2556 let load_only_snapshot_config = SnapshotConfig {
2557 bank_snapshots_dir: snapshot_config.bank_snapshots_dir.clone(),
2558 full_snapshot_archives_dir: snapshot_config.full_snapshot_archives_dir.clone(),
2559 incremental_snapshot_archives_dir: snapshot_config
2560 .incremental_snapshot_archives_dir
2561 .clone(),
2562 ..SnapshotConfig::new_load_only()
2563 };
2564
2565 let genesis_config = GenesisConfig::default();
2566 let mut bank = Arc::new(Bank::new_for_tests(&genesis_config));
2567 let mut full_snapshot_archive_info = None;
2568
2569 for _ in 0..snapshot_config
2572 .maximum_full_snapshot_archives_to_retain
2573 .get()
2574 + 1
2575 {
2576 let slot = bank.slot() + 1;
2577 bank = Arc::new(Bank::new_from_parent(bank, &Pubkey::default(), slot));
2578 bank.fill_bank_with_ticks_for_tests();
2579 full_snapshot_archive_info = Some(
2580 bank_to_full_snapshot_archive_with(
2581 &snapshot_config.bank_snapshots_dir,
2582 &bank,
2583 snapshot_config.snapshot_version,
2584 &snapshot_config.full_snapshot_archives_dir,
2585 &snapshot_config.incremental_snapshot_archives_dir,
2586 snapshot_config.archive_format,
2587 )
2588 .unwrap(),
2589 );
2590 }
2591
2592 let slot = bank.slot();
2594 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
2595 let post = bank_snapshot_dir.join(get_snapshot_file_name(slot));
2596 let pre = post.with_extension(BANK_SNAPSHOT_PRE_FILENAME_EXTENSION);
2597 fs::rename(post, pre).unwrap();
2598
2599 fs::remove_file(full_snapshot_archive_info.unwrap().path()).unwrap();
2601
2602 let highest_full_snapshot_archive =
2603 get_highest_full_snapshot_archive_info(&snapshot_archives_dir).unwrap();
2604 let highest_bank_snapshot_post =
2605 get_highest_bank_snapshot_post(&bank_snapshots_dir).unwrap();
2606 let highest_bank_snapshot_pre = get_highest_bank_snapshot_pre(&bank_snapshots_dir).unwrap();
2607
2608 assert!(highest_bank_snapshot_pre.slot > highest_bank_snapshot_post.slot);
2611
2612 assert!(get_highest_loadable_bank_snapshot(&SnapshotConfig::default()).is_none());
2614
2615 let bank_snapshot = get_highest_loadable_bank_snapshot(&snapshot_config).unwrap();
2617 assert_eq!(bank_snapshot, highest_bank_snapshot_post);
2618
2619 fs::remove_file(highest_full_snapshot_archive.path()).unwrap();
2621 assert!(get_highest_loadable_bank_snapshot(&snapshot_config).is_none());
2622
2623 let bank_snapshot = get_highest_loadable_bank_snapshot(&load_only_snapshot_config).unwrap();
2625 assert_eq!(bank_snapshot, highest_bank_snapshot_post);
2626
2627 fs::remove_dir_all(&highest_bank_snapshot_post.snapshot_dir).unwrap();
2629 let bank_snapshot = get_highest_loadable_bank_snapshot(&snapshot_config).unwrap();
2630 assert_eq!(bank_snapshot.slot, highest_bank_snapshot_post.slot - 1);
2631
2632 fs::remove_file(
2634 bank_snapshot
2635 .snapshot_dir
2636 .join(SNAPSHOT_FULL_SNAPSHOT_SLOT_FILENAME),
2637 )
2638 .unwrap();
2639 assert!(get_highest_loadable_bank_snapshot(&snapshot_config).is_none());
2640
2641 let bank_snapshot2 =
2643 get_highest_loadable_bank_snapshot(&load_only_snapshot_config).unwrap();
2644 assert_eq!(bank_snapshot2, bank_snapshot);
2645 }
2646}