1#[cfg(feature = "dev-context-only-utils")]
2use {
3 crate::{
4 bank::BankFieldsToDeserialize,
5 serde_snapshot::fields_from_streams,
6 snapshot_utils::{
7 deserialize_snapshot_data_files, verify_unpacked_snapshots_dir_and_version,
8 SnapshotRootPaths, UnpackedSnapshotsDirAndVersion,
9 },
10 },
11 solana_accounts_db::accounts_file::StorageAccess,
12 tempfile::TempDir,
13};
14use {
15 crate::{
16 bank::{Bank, BankSlotDelta},
17 epoch_stakes::VersionedEpochStakes,
18 runtime_config::RuntimeConfig,
19 serde_snapshot::{
20 self, reconstruct_bank_from_fields, SnapshotAccountsDbFields, SnapshotBankFields,
21 },
22 snapshot_archive_info::{
23 FullSnapshotArchiveInfo, IncrementalSnapshotArchiveInfo, SnapshotArchiveInfoGetter,
24 },
25 snapshot_config::SnapshotConfig,
26 snapshot_hash::SnapshotHash,
27 snapshot_package::{SnapshotKind, SnapshotPackage},
28 snapshot_utils::{
29 self, get_highest_bank_snapshot_post, get_highest_full_snapshot_archive_info,
30 get_highest_incremental_snapshot_archive_info, rebuild_storages_from_snapshot_dir,
31 verify_and_unarchive_snapshots, ArchiveFormat, BankSnapshotInfo, SnapshotError,
32 SnapshotVersion, StorageAndNextAccountsFileId, UnarchivedSnapshots,
33 VerifyEpochStakesError, VerifySlotDeltasError, VerifySlotHistoryError,
34 },
35 status_cache,
36 },
37 log::*,
38 solana_accounts_db::{
39 accounts_db::{AccountsDbConfig, AtomicAccountsFileId},
40 accounts_update_notifier_interface::AccountsUpdateNotifier,
41 utils::remove_dir_contents,
42 },
43 solana_builtins::prototype::BuiltinPrototype,
44 solana_clock::{Epoch, Slot},
45 solana_genesis_config::GenesisConfig,
46 solana_measure::{measure::Measure, measure_time},
47 solana_pubkey::Pubkey,
48 solana_slot_history::{Check, SlotHistory},
49 std::{
50 collections::{HashMap, HashSet},
51 ops::RangeInclusive,
52 path::{Path, PathBuf},
53 sync::{atomic::AtomicBool, Arc},
54 },
55};
56
57#[derive(Debug)]
58pub struct BankFromArchivesTimings {
59 pub untar_full_snapshot_archive_us: u64,
60 pub untar_incremental_snapshot_archive_us: Option<u64>,
61 pub rebuild_bank_us: u64,
62 pub verify_bank_us: u64,
63}
64
65#[derive(Debug)]
66pub struct BankFromDirTimings {
67 pub rebuild_storages_us: u64,
68 pub rebuild_bank_us: u64,
69}
70
71#[cfg(feature = "dev-context-only-utils")]
74pub fn bank_fields_from_snapshot_archives(
75 full_snapshot_archives_dir: impl AsRef<Path>,
76 incremental_snapshot_archives_dir: impl AsRef<Path>,
77 storage_access: StorageAccess,
78) -> snapshot_utils::Result<BankFieldsToDeserialize> {
79 let full_snapshot_archive_info =
80 get_highest_full_snapshot_archive_info(&full_snapshot_archives_dir).ok_or_else(|| {
81 SnapshotError::NoSnapshotArchives(full_snapshot_archives_dir.as_ref().to_path_buf())
82 })?;
83
84 let incremental_snapshot_archive_info = get_highest_incremental_snapshot_archive_info(
85 &incremental_snapshot_archives_dir,
86 full_snapshot_archive_info.slot(),
87 );
88
89 let temp_unpack_dir = TempDir::new()?;
90 let temp_accounts_dir = TempDir::new()?;
91
92 let account_paths = vec![temp_accounts_dir.path().to_path_buf()];
93
94 let (
95 UnarchivedSnapshots {
96 full_unpacked_snapshots_dir_and_version,
97 incremental_unpacked_snapshots_dir_and_version,
98 ..
99 },
100 _guard,
101 ) = verify_and_unarchive_snapshots(
102 &temp_unpack_dir,
103 &full_snapshot_archive_info,
104 incremental_snapshot_archive_info.as_ref(),
105 &account_paths,
106 storage_access,
107 )?;
108
109 bank_fields_from_snapshots(
110 &full_unpacked_snapshots_dir_and_version,
111 incremental_unpacked_snapshots_dir_and_version.as_ref(),
112 )
113}
114
115#[cfg(feature = "dev-context-only-utils")]
116fn bank_fields_from_snapshots(
117 full_snapshot_unpacked_snapshots_dir_and_version: &UnpackedSnapshotsDirAndVersion,
118 incremental_snapshot_unpacked_snapshots_dir_and_version: Option<
119 &UnpackedSnapshotsDirAndVersion,
120 >,
121) -> snapshot_utils::Result<BankFieldsToDeserialize> {
122 let (snapshot_version, snapshot_root_paths) = snapshot_version_and_root_paths(
123 full_snapshot_unpacked_snapshots_dir_and_version,
124 incremental_snapshot_unpacked_snapshots_dir_and_version,
125 )?;
126
127 info!(
128 "Loading bank from full snapshot {} and incremental snapshot {:?}",
129 snapshot_root_paths.full_snapshot_root_file_path.display(),
130 snapshot_root_paths.incremental_snapshot_root_file_path,
131 );
132
133 deserialize_snapshot_data_files(&snapshot_root_paths, |snapshot_streams| {
134 Ok(match snapshot_version {
135 SnapshotVersion::V1_2_0 => fields_from_streams(snapshot_streams)
136 .map(|(bank_fields, _accountsdb_fields)| bank_fields.collapse_into()),
137 }?)
138 })
139}
140
141#[allow(clippy::too_many_arguments)]
144pub fn bank_from_snapshot_archives(
145 account_paths: &[PathBuf],
146 bank_snapshots_dir: impl AsRef<Path>,
147 full_snapshot_archive_info: &FullSnapshotArchiveInfo,
148 incremental_snapshot_archive_info: Option<&IncrementalSnapshotArchiveInfo>,
149 genesis_config: &GenesisConfig,
150 runtime_config: &RuntimeConfig,
151 debug_keys: Option<Arc<HashSet<Pubkey>>>,
152 additional_builtins: Option<&[BuiltinPrototype]>,
153 limit_load_slot_count_from_snapshot: Option<usize>,
154 accounts_db_skip_shrink: bool,
155 accounts_db_force_initial_clean: bool,
156 verify_index: bool,
157 accounts_db_config: Option<AccountsDbConfig>,
158 accounts_update_notifier: Option<AccountsUpdateNotifier>,
159 exit: Arc<AtomicBool>,
160) -> snapshot_utils::Result<(Bank, BankFromArchivesTimings)> {
161 info!(
162 "Loading bank from full snapshot archive: {}, and incremental snapshot archive: {:?}",
163 full_snapshot_archive_info.path().display(),
164 incremental_snapshot_archive_info
165 .as_ref()
166 .map(
167 |incremental_snapshot_archive_info| incremental_snapshot_archive_info
168 .path()
169 .display()
170 )
171 );
172
173 let (
174 UnarchivedSnapshots {
175 full_storage: mut storage,
176 incremental_storage,
177 bank_fields,
178 accounts_db_fields,
179 full_unpacked_snapshots_dir_and_version,
180 incremental_unpacked_snapshots_dir_and_version,
181 full_measure_untar,
182 incremental_measure_untar,
183 next_append_vec_id,
184 ..
185 },
186 _guard,
187 ) = verify_and_unarchive_snapshots(
188 bank_snapshots_dir,
189 full_snapshot_archive_info,
190 incremental_snapshot_archive_info,
191 account_paths,
192 accounts_db_config
193 .as_ref()
194 .map(|config| config.storage_access)
195 .unwrap_or_default(),
196 )?;
197
198 if let Some(incremental_storage) = incremental_storage {
199 storage.extend(incremental_storage);
200 }
201
202 let storage_and_next_append_vec_id = StorageAndNextAccountsFileId {
203 storage,
204 next_append_vec_id,
205 };
206
207 let mut measure_rebuild = Measure::start("rebuild bank from snapshots");
208 let (bank, info) = reconstruct_bank_from_fields(
209 bank_fields,
210 accounts_db_fields,
211 genesis_config,
212 runtime_config,
213 account_paths,
214 storage_and_next_append_vec_id,
215 debug_keys,
216 additional_builtins,
217 limit_load_slot_count_from_snapshot,
218 verify_index,
219 accounts_db_config,
220 accounts_update_notifier,
221 exit,
222 )?;
223 measure_rebuild.stop();
224 info!("{measure_rebuild}");
225
226 verify_epoch_stakes(&bank)?;
227
228 let status_cache_path = incremental_unpacked_snapshots_dir_and_version
231 .as_ref()
232 .unwrap_or(&full_unpacked_snapshots_dir_and_version)
233 .unpacked_snapshots_dir
234 .join(snapshot_utils::SNAPSHOT_STATUS_CACHE_FILENAME);
235 info!(
236 "Rebuilding status cache from {}",
237 status_cache_path.display()
238 );
239 let slot_deltas = serde_snapshot::deserialize_status_cache(&status_cache_path)?;
240
241 verify_slot_deltas(slot_deltas.as_slice(), &bank)?;
242
243 bank.status_cache.write().unwrap().append(&slot_deltas);
244
245 let snapshot_archive_info = incremental_snapshot_archive_info.map_or_else(
246 || full_snapshot_archive_info.snapshot_archive_info(),
247 |incremental_snapshot_archive_info| {
248 incremental_snapshot_archive_info.snapshot_archive_info()
249 },
250 );
251 verify_bank_against_expected_slot_hash(
252 &bank,
253 snapshot_archive_info.slot,
254 snapshot_archive_info.hash,
255 )?;
256
257 let mut measure_verify = Measure::start("verify");
258 if !bank.verify_snapshot_bank(
259 accounts_db_skip_shrink || !full_snapshot_archive_info.is_remote(),
260 accounts_db_force_initial_clean,
261 full_snapshot_archive_info.slot(),
262 info.duplicates_lt_hash,
263 ) && limit_load_slot_count_from_snapshot.is_none()
264 {
265 panic!("Snapshot bank for slot {} failed to verify", bank.slot());
266 }
267 measure_verify.stop();
268
269 let timings = BankFromArchivesTimings {
270 untar_full_snapshot_archive_us: full_measure_untar.as_us(),
271 untar_incremental_snapshot_archive_us: incremental_measure_untar
272 .as_ref()
273 .map(Measure::as_us),
274 rebuild_bank_us: measure_rebuild.as_us(),
275 verify_bank_us: measure_verify.as_us(),
276 };
277 datapoint_info!(
278 "bank_from_snapshot_archives",
279 (
280 "untar_full_snapshot_archive_us",
281 timings.untar_full_snapshot_archive_us,
282 i64
283 ),
284 (
285 "untar_incremental_snapshot_archive_us",
286 timings.untar_incremental_snapshot_archive_us,
287 Option<i64>
288 ),
289 ("rebuild_bank_us", timings.rebuild_bank_us, i64),
290 ("verify_bank_us", timings.verify_bank_us, i64),
291 );
292 Ok((bank, timings))
293}
294
295#[allow(clippy::too_many_arguments)]
300pub fn bank_from_latest_snapshot_archives(
301 bank_snapshots_dir: impl AsRef<Path>,
302 full_snapshot_archives_dir: impl AsRef<Path>,
303 incremental_snapshot_archives_dir: impl AsRef<Path>,
304 account_paths: &[PathBuf],
305 genesis_config: &GenesisConfig,
306 runtime_config: &RuntimeConfig,
307 debug_keys: Option<Arc<HashSet<Pubkey>>>,
308 additional_builtins: Option<&[BuiltinPrototype]>,
309 limit_load_slot_count_from_snapshot: Option<usize>,
310 accounts_db_skip_shrink: bool,
311 accounts_db_force_initial_clean: bool,
312 verify_index: bool,
313 accounts_db_config: Option<AccountsDbConfig>,
314 accounts_update_notifier: Option<AccountsUpdateNotifier>,
315 exit: Arc<AtomicBool>,
316) -> snapshot_utils::Result<(
317 Bank,
318 FullSnapshotArchiveInfo,
319 Option<IncrementalSnapshotArchiveInfo>,
320)> {
321 let full_snapshot_archive_info =
322 get_highest_full_snapshot_archive_info(&full_snapshot_archives_dir).ok_or_else(|| {
323 SnapshotError::NoSnapshotArchives(full_snapshot_archives_dir.as_ref().to_path_buf())
324 })?;
325
326 let incremental_snapshot_archive_info = get_highest_incremental_snapshot_archive_info(
327 &incremental_snapshot_archives_dir,
328 full_snapshot_archive_info.slot(),
329 );
330
331 let (bank, _) = bank_from_snapshot_archives(
332 account_paths,
333 bank_snapshots_dir.as_ref(),
334 &full_snapshot_archive_info,
335 incremental_snapshot_archive_info.as_ref(),
336 genesis_config,
337 runtime_config,
338 debug_keys,
339 additional_builtins,
340 limit_load_slot_count_from_snapshot,
341 accounts_db_skip_shrink,
342 accounts_db_force_initial_clean,
343 verify_index,
344 accounts_db_config,
345 accounts_update_notifier,
346 exit,
347 )?;
348
349 Ok((
350 bank,
351 full_snapshot_archive_info,
352 incremental_snapshot_archive_info,
353 ))
354}
355
356#[allow(clippy::too_many_arguments)]
358pub fn bank_from_snapshot_dir(
359 account_paths: &[PathBuf],
360 bank_snapshot: &BankSnapshotInfo,
361 genesis_config: &GenesisConfig,
362 runtime_config: &RuntimeConfig,
363 debug_keys: Option<Arc<HashSet<Pubkey>>>,
364 additional_builtins: Option<&[BuiltinPrototype]>,
365 limit_load_slot_count_from_snapshot: Option<usize>,
366 verify_index: bool,
367 accounts_db_config: Option<AccountsDbConfig>,
368 accounts_update_notifier: Option<AccountsUpdateNotifier>,
369 exit: Arc<AtomicBool>,
370) -> snapshot_utils::Result<(Bank, BankFromDirTimings)> {
371 info!(
372 "Loading bank from snapshot dir: {}",
373 bank_snapshot.snapshot_dir.display()
374 );
375
376 for path in account_paths {
379 remove_dir_contents(path);
380 }
381
382 let next_append_vec_id = Arc::new(AtomicAccountsFileId::new(0));
383 let storage_access = accounts_db_config
384 .as_ref()
385 .map(|config| config.storage_access)
386 .unwrap_or_default();
387
388 let ((storage, bank_fields, accounts_db_fields), measure_rebuild_storages) = measure_time!(
389 rebuild_storages_from_snapshot_dir(
390 bank_snapshot,
391 account_paths,
392 next_append_vec_id.clone(),
393 storage_access,
394 )?,
395 "rebuild storages from snapshot dir"
396 );
397 info!("{measure_rebuild_storages}");
398
399 let next_append_vec_id =
400 Arc::try_unwrap(next_append_vec_id).expect("this is the only strong reference");
401 let storage_and_next_append_vec_id = StorageAndNextAccountsFileId {
402 storage,
403 next_append_vec_id,
404 };
405 let snapshot_bank_fields = SnapshotBankFields::new(bank_fields, None);
406 let snapshot_accounts_db_fields = SnapshotAccountsDbFields::new(accounts_db_fields, None);
407 let ((bank, _info), measure_rebuild_bank) = measure_time!(
408 reconstruct_bank_from_fields(
409 snapshot_bank_fields,
410 snapshot_accounts_db_fields,
411 genesis_config,
412 runtime_config,
413 account_paths,
414 storage_and_next_append_vec_id,
415 debug_keys,
416 additional_builtins,
417 limit_load_slot_count_from_snapshot,
418 verify_index,
419 accounts_db_config,
420 accounts_update_notifier,
421 exit,
422 )?,
423 "rebuild bank from snapshot"
424 );
425 info!("{measure_rebuild_bank}");
426
427 verify_epoch_stakes(&bank)?;
428
429 let status_cache_path = bank_snapshot
430 .snapshot_dir
431 .join(snapshot_utils::SNAPSHOT_STATUS_CACHE_FILENAME);
432 info!(
433 "Rebuilding status cache from {}",
434 status_cache_path.display()
435 );
436 let slot_deltas = serde_snapshot::deserialize_status_cache(&status_cache_path)?;
437
438 verify_slot_deltas(slot_deltas.as_slice(), &bank)?;
439
440 bank.status_cache.write().unwrap().append(&slot_deltas);
441
442 bank.set_initial_accounts_hash_verification_completed();
444
445 let timings = BankFromDirTimings {
446 rebuild_storages_us: measure_rebuild_storages.as_us(),
447 rebuild_bank_us: measure_rebuild_bank.as_us(),
448 };
449 datapoint_info!(
450 "bank_from_snapshot_dir",
451 ("rebuild_storages_us", timings.rebuild_storages_us, i64),
452 ("rebuild_bank_us", timings.rebuild_bank_us, i64),
453 );
454 Ok((bank, timings))
455}
456
457#[allow(clippy::too_many_arguments)]
459pub fn bank_from_latest_snapshot_dir(
460 bank_snapshots_dir: impl AsRef<Path>,
461 genesis_config: &GenesisConfig,
462 runtime_config: &RuntimeConfig,
463 account_paths: &[PathBuf],
464 debug_keys: Option<Arc<HashSet<Pubkey>>>,
465 additional_builtins: Option<&[BuiltinPrototype]>,
466 limit_load_slot_count_from_snapshot: Option<usize>,
467 verify_index: bool,
468 accounts_db_config: Option<AccountsDbConfig>,
469 accounts_update_notifier: Option<AccountsUpdateNotifier>,
470 exit: Arc<AtomicBool>,
471) -> snapshot_utils::Result<Bank> {
472 let bank_snapshot = get_highest_bank_snapshot_post(&bank_snapshots_dir).ok_or_else(|| {
473 SnapshotError::NoSnapshotSlotDir(bank_snapshots_dir.as_ref().to_path_buf())
474 })?;
475 let (bank, _) = bank_from_snapshot_dir(
476 account_paths,
477 &bank_snapshot,
478 genesis_config,
479 runtime_config,
480 debug_keys,
481 additional_builtins,
482 limit_load_slot_count_from_snapshot,
483 verify_index,
484 accounts_db_config,
485 accounts_update_notifier,
486 exit,
487 )?;
488
489 Ok(bank)
490}
491
492fn verify_bank_against_expected_slot_hash(
494 bank: &Bank,
495 snapshot_slot: Slot,
496 snapshot_hash: SnapshotHash,
497) -> snapshot_utils::Result<()> {
498 let bank_slot = bank.slot();
499 if bank_slot != snapshot_slot {
500 return Err(SnapshotError::MismatchedSlot(bank_slot, snapshot_slot));
501 }
502
503 let bank_hash = bank.get_snapshot_hash();
504 if bank_hash == snapshot_hash {
505 Ok(())
506 } else {
507 Err(SnapshotError::MismatchedHash(bank_hash, snapshot_hash))
508 }
509}
510
511#[cfg(feature = "dev-context-only-utils")]
513fn snapshot_version_and_root_paths(
514 full_snapshot_unpacked_snapshots_dir_and_version: &UnpackedSnapshotsDirAndVersion,
515 incremental_snapshot_unpacked_snapshots_dir_and_version: Option<
516 &UnpackedSnapshotsDirAndVersion,
517 >,
518) -> snapshot_utils::Result<(SnapshotVersion, SnapshotRootPaths)> {
519 let (full_snapshot_version, full_snapshot_root_paths) =
520 verify_unpacked_snapshots_dir_and_version(
521 full_snapshot_unpacked_snapshots_dir_and_version,
522 )?;
523 let (incremental_snapshot_version, incremental_snapshot_root_paths) =
524 if let Some(snapshot_unpacked_snapshots_dir_and_version) =
525 incremental_snapshot_unpacked_snapshots_dir_and_version
526 {
527 Some(verify_unpacked_snapshots_dir_and_version(
528 snapshot_unpacked_snapshots_dir_and_version,
529 )?)
530 } else {
531 None
532 }
533 .unzip();
534
535 let snapshot_version = incremental_snapshot_version.unwrap_or(full_snapshot_version);
536 let snapshot_root_paths = SnapshotRootPaths {
537 full_snapshot_root_file_path: full_snapshot_root_paths.snapshot_path(),
538 incremental_snapshot_root_file_path: incremental_snapshot_root_paths
539 .map(|root_paths| root_paths.snapshot_path()),
540 };
541
542 Ok((snapshot_version, snapshot_root_paths))
543}
544
545fn verify_slot_deltas(
547 slot_deltas: &[BankSlotDelta],
548 bank: &Bank,
549) -> std::result::Result<(), VerifySlotDeltasError> {
550 let info = verify_slot_deltas_structural(slot_deltas, bank.slot())?;
551 verify_slot_deltas_with_history(&info.slots, &bank.get_slot_history(), bank.slot())
552}
553
554fn verify_slot_deltas_structural(
557 slot_deltas: &[BankSlotDelta],
558 bank_slot: Slot,
559) -> std::result::Result<VerifySlotDeltasStructuralInfo, VerifySlotDeltasError> {
560 let num_entries = slot_deltas.len();
562 if num_entries > status_cache::MAX_CACHE_ENTRIES {
563 return Err(VerifySlotDeltasError::TooManyEntries(
564 num_entries,
565 status_cache::MAX_CACHE_ENTRIES,
566 ));
567 }
568
569 let mut slots_seen_so_far = HashSet::new();
570 for &(slot, is_root, ..) in slot_deltas {
571 if !is_root {
573 return Err(VerifySlotDeltasError::SlotIsNotRoot(slot));
574 }
575
576 if slot > bank_slot {
578 return Err(VerifySlotDeltasError::SlotGreaterThanMaxRoot(
579 slot, bank_slot,
580 ));
581 }
582
583 let is_duplicate = !slots_seen_so_far.insert(slot);
585 if is_duplicate {
586 return Err(VerifySlotDeltasError::SlotHasMultipleEntries(slot));
587 }
588 }
589
590 assert_eq!(slots_seen_so_far.len(), slot_deltas.len());
592
593 Ok(VerifySlotDeltasStructuralInfo {
594 slots: slots_seen_so_far,
595 })
596}
597
598#[derive(Debug, PartialEq, Eq)]
600struct VerifySlotDeltasStructuralInfo {
601 slots: HashSet<Slot>,
603}
604
605fn verify_slot_deltas_with_history(
608 slots_from_slot_deltas: &HashSet<Slot>,
609 slot_history: &SlotHistory,
610 bank_slot: Slot,
611) -> std::result::Result<(), VerifySlotDeltasError> {
612 verify_slot_history(slot_history, bank_slot)?;
615
616 let slot_missing_from_history = slots_from_slot_deltas
618 .iter()
619 .find(|slot| slot_history.check(**slot) != Check::Found);
620 if let Some(slot) = slot_missing_from_history {
621 return Err(VerifySlotDeltasError::SlotNotFoundInHistory(*slot));
622 }
623
624 let slot_missing_from_deltas = (slot_history.oldest()..=slot_history.newest())
632 .rev()
633 .filter(|slot| slot_history.check(*slot) == Check::Found)
634 .take(status_cache::MAX_CACHE_ENTRIES)
635 .find(|slot| !slots_from_slot_deltas.contains(slot));
636 if let Some(slot) = slot_missing_from_deltas {
637 return Err(VerifySlotDeltasError::SlotNotFoundInDeltas(slot));
638 }
639
640 Ok(())
641}
642
643fn verify_slot_history(
645 slot_history: &SlotHistory,
646 bank_slot: Slot,
647) -> Result<(), VerifySlotHistoryError> {
648 if slot_history.newest() != bank_slot {
649 return Err(VerifySlotHistoryError::InvalidNewestSlot);
650 }
651
652 if slot_history.bits.len() != solana_slot_history::MAX_ENTRIES {
653 return Err(VerifySlotHistoryError::InvalidNumEntries);
654 }
655
656 Ok(())
657}
658
659fn verify_epoch_stakes(bank: &Bank) -> std::result::Result<(), VerifyEpochStakesError> {
661 let current_epoch = bank.epoch();
665 let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
666 let required_epochs = current_epoch..=leader_schedule_epoch;
667 _verify_epoch_stakes(bank.epoch_stakes_map(), required_epochs)
668}
669
670fn _verify_epoch_stakes(
675 epoch_stakes_map: &HashMap<Epoch, VersionedEpochStakes>,
676 required_epochs: RangeInclusive<Epoch>,
677) -> std::result::Result<(), VerifyEpochStakesError> {
678 let max_epoch = *required_epochs.end();
683 if let Some(invalid_epoch) = epoch_stakes_map.keys().find(|epoch| **epoch > max_epoch) {
684 return Err(VerifyEpochStakesError::EpochGreaterThanMax(
685 *invalid_epoch,
686 max_epoch,
687 ));
688 }
689
690 if let Some(missing_epoch) = required_epochs
692 .clone()
693 .find(|epoch| !epoch_stakes_map.contains_key(epoch))
694 {
695 return Err(VerifyEpochStakesError::StakesNotFound(
696 missing_epoch,
697 required_epochs,
698 ));
699 }
700
701 Ok(())
702}
703
704pub fn bank_to_full_snapshot_archive(
711 bank_snapshots_dir: impl AsRef<Path>,
712 bank: &Bank,
713 snapshot_version: Option<SnapshotVersion>,
714 full_snapshot_archives_dir: impl AsRef<Path>,
715 incremental_snapshot_archives_dir: impl AsRef<Path>,
716 archive_format: ArchiveFormat,
717) -> snapshot_utils::Result<FullSnapshotArchiveInfo> {
718 let snapshot_version = snapshot_version.unwrap_or_default();
719 let temp_bank_snapshots_dir = tempfile::tempdir_in(bank_snapshots_dir)?;
720 bank_to_full_snapshot_archive_with(
721 &temp_bank_snapshots_dir,
722 bank,
723 snapshot_version,
724 full_snapshot_archives_dir,
725 incremental_snapshot_archives_dir,
726 archive_format,
727 false, )
729}
730
731fn bank_to_full_snapshot_archive_with(
736 bank_snapshots_dir: impl AsRef<Path>,
737 bank: &Bank,
738 snapshot_version: SnapshotVersion,
739 full_snapshot_archives_dir: impl AsRef<Path>,
740 incremental_snapshot_archives_dir: impl AsRef<Path>,
741 archive_format: ArchiveFormat,
742 should_flush_and_hard_link_storages: bool,
743) -> snapshot_utils::Result<FullSnapshotArchiveInfo> {
744 assert!(bank.is_complete());
745 bank.rc
748 .accounts
749 .accounts_db
750 .set_latest_full_snapshot_slot(bank.slot());
751 bank.squash(); bank.rehash(); bank.force_flush_accounts_cache();
754 bank.clean_accounts();
755
756 let snapshot_package = SnapshotPackage::new(
757 SnapshotKind::FullSnapshot,
758 bank,
759 bank.get_snapshot_storages(None),
760 bank.status_cache.read().unwrap().root_slot_deltas(),
761 );
762
763 let snapshot_config = SnapshotConfig {
764 full_snapshot_archives_dir: full_snapshot_archives_dir.as_ref().to_path_buf(),
765 incremental_snapshot_archives_dir: incremental_snapshot_archives_dir.as_ref().to_path_buf(),
766 bank_snapshots_dir: bank_snapshots_dir.as_ref().to_path_buf(),
767 archive_format,
768 snapshot_version,
769 ..Default::default()
770 };
771 let snapshot_archive_info = snapshot_utils::serialize_and_archive_snapshot_package(
772 snapshot_package,
773 &snapshot_config,
774 should_flush_and_hard_link_storages,
775 )?;
776
777 Ok(FullSnapshotArchiveInfo::new(snapshot_archive_info))
778}
779
780pub fn bank_to_incremental_snapshot_archive(
788 bank_snapshots_dir: impl AsRef<Path>,
789 bank: &Bank,
790 full_snapshot_slot: Slot,
791 snapshot_version: Option<SnapshotVersion>,
792 full_snapshot_archives_dir: impl AsRef<Path>,
793 incremental_snapshot_archives_dir: impl AsRef<Path>,
794 archive_format: ArchiveFormat,
795) -> snapshot_utils::Result<IncrementalSnapshotArchiveInfo> {
796 let snapshot_version = snapshot_version.unwrap_or_default();
797
798 assert!(bank.is_complete());
799 assert!(bank.slot() > full_snapshot_slot);
800 bank.rc
803 .accounts
804 .accounts_db
805 .set_latest_full_snapshot_slot(full_snapshot_slot);
806 bank.squash(); bank.rehash(); bank.force_flush_accounts_cache();
809 bank.clean_accounts();
810
811 let snapshot_package = SnapshotPackage::new(
812 SnapshotKind::IncrementalSnapshot(full_snapshot_slot),
813 bank,
814 bank.get_snapshot_storages(Some(full_snapshot_slot)),
815 bank.status_cache.read().unwrap().root_slot_deltas(),
816 );
817
818 let temp_bank_snapshots_dir = tempfile::tempdir_in(bank_snapshots_dir)?;
822 let snapshot_config = SnapshotConfig {
823 full_snapshot_archives_dir: full_snapshot_archives_dir.as_ref().to_path_buf(),
824 incremental_snapshot_archives_dir: incremental_snapshot_archives_dir.as_ref().to_path_buf(),
825 bank_snapshots_dir: temp_bank_snapshots_dir.path().to_path_buf(),
826 archive_format,
827 snapshot_version,
828 ..Default::default()
829 };
830 let snapshot_archive_info = snapshot_utils::serialize_and_archive_snapshot_package(
831 snapshot_package,
832 &snapshot_config,
833 false, )?;
835
836 Ok(IncrementalSnapshotArchiveInfo::new(
837 full_snapshot_slot,
838 snapshot_archive_info,
839 ))
840}
841
842#[cfg(test)]
843mod tests {
844 use {
845 super::*,
846 crate::{
847 bank::{tests::create_simple_test_bank, BankTestConfig},
848 bank_forks::BankForks,
849 snapshot_config::SnapshotConfig,
850 snapshot_utils::{
851 clean_orphaned_account_snapshot_dirs, create_tmp_accounts_dir_for_tests,
852 get_bank_snapshot_dir, get_bank_snapshots, get_bank_snapshots_post,
853 get_bank_snapshots_pre, get_highest_bank_snapshot, get_highest_bank_snapshot_pre,
854 get_highest_loadable_bank_snapshot, get_snapshot_file_name,
855 purge_all_bank_snapshots, purge_bank_snapshot,
856 purge_bank_snapshots_older_than_slot, purge_incomplete_bank_snapshots,
857 purge_old_bank_snapshots, purge_old_bank_snapshots_at_startup,
858 snapshot_storage_rebuilder::get_slot_and_append_vec_id, BankSnapshotKind,
859 BANK_SNAPSHOT_PRE_FILENAME_EXTENSION, SNAPSHOT_FULL_SNAPSHOT_SLOT_FILENAME,
860 },
861 status_cache::Status,
862 },
863 solana_accounts_db::accounts_db::ACCOUNTS_DB_CONFIG_FOR_TESTING,
864 solana_genesis_config::create_genesis_config,
865 solana_keypair::Keypair,
866 solana_native_token::LAMPORTS_PER_SOL,
867 solana_signer::Signer,
868 solana_system_transaction as system_transaction,
869 solana_transaction::sanitized::SanitizedTransaction,
870 std::{
871 fs,
872 sync::{atomic::Ordering, Arc, RwLock},
873 },
874 test_case::test_case,
875 };
876
877 fn create_snapshot_dirs_for_tests(
878 genesis_config: &GenesisConfig,
879 bank_snapshots_dir: impl AsRef<Path>,
880 num_total: usize,
881 num_posts: usize,
882 should_flush_and_hard_link_storages: bool,
883 ) -> Bank {
884 assert!(num_posts <= num_total);
885
886 let snapshot_archives_dir = TempDir::new().unwrap();
889
890 let mut bank = Arc::new(Bank::new_for_tests(genesis_config));
891 for i in 0..num_total {
892 let slot = bank.slot() + 1;
893 bank = Arc::new(Bank::new_from_parent(bank, &Pubkey::new_unique(), slot));
894 bank.fill_bank_with_ticks_for_tests();
895
896 bank_to_full_snapshot_archive_with(
897 &bank_snapshots_dir,
898 &bank,
899 SnapshotVersion::default(),
900 &snapshot_archives_dir,
901 &snapshot_archives_dir,
902 SnapshotConfig::default().archive_format,
903 should_flush_and_hard_link_storages,
904 )
905 .unwrap();
906
907 if i >= num_posts {
909 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
910 let post = bank_snapshot_dir.join(get_snapshot_file_name(slot));
911 let pre = post.with_extension(BANK_SNAPSHOT_PRE_FILENAME_EXTENSION);
912 fs::rename(post, pre).unwrap();
913 }
914 }
915
916 Arc::into_inner(bank).unwrap()
917 }
918
919 fn new_bank_from_parent_with_bank_forks(
920 bank_forks: &RwLock<BankForks>,
921 parent: Arc<Bank>,
922 collector_id: &Pubkey,
923 slot: Slot,
924 ) -> Arc<Bank> {
925 let bank = Bank::new_from_parent(parent, collector_id, slot);
926 bank_forks
927 .write()
928 .unwrap()
929 .insert(bank)
930 .clone_without_scheduler()
931 }
932
933 #[test]
936 fn test_roundtrip_bank_to_and_from_full_snapshot_simple() {
937 let genesis_config = GenesisConfig::default();
938 let original_bank = Bank::new_for_tests(&genesis_config);
939
940 original_bank.fill_bank_with_ticks_for_tests();
941
942 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
943 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
944 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
945 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
946 let snapshot_archive_format = SnapshotConfig::default().archive_format;
947
948 let snapshot_archive_info = bank_to_full_snapshot_archive(
949 &bank_snapshots_dir,
950 &original_bank,
951 None,
952 full_snapshot_archives_dir.path(),
953 incremental_snapshot_archives_dir.path(),
954 snapshot_archive_format,
955 )
956 .unwrap();
957
958 let (roundtrip_bank, _) = bank_from_snapshot_archives(
959 &[accounts_dir],
960 bank_snapshots_dir.path(),
961 &snapshot_archive_info,
962 None,
963 &genesis_config,
964 &RuntimeConfig::default(),
965 None,
966 None,
967 None,
968 false,
969 false,
970 false,
971 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
972 None,
973 Arc::default(),
974 )
975 .unwrap();
976 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
977 assert_eq!(original_bank, roundtrip_bank);
978 }
979
980 #[test]
983 fn test_roundtrip_bank_to_and_from_full_snapshot_with_obsolete_account() {
984 let collector = Pubkey::new_unique();
985 let key1 = Keypair::new();
986 let key2 = Keypair::new();
987 let key3 = Keypair::new();
988
989 let (genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
991 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
992 bank0
993 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
994 .unwrap();
995 bank0
996 .transfer(2 * LAMPORTS_PER_SOL, &mint_keypair, &key2.pubkey())
997 .unwrap();
998 bank0
999 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1000 .unwrap();
1001 bank0.fill_bank_with_ticks_for_tests();
1002
1003 bank0.squash();
1005 bank0.force_flush_accounts_cache();
1006
1007 let target_slot = 0;
1009 let account_storage_entry = bank0
1010 .accounts()
1011 .accounts_db
1012 .storage
1013 .get_slot_storage_entry(target_slot)
1014 .unwrap();
1015
1016 let accounts = bank0
1018 .accounts()
1019 .accounts_db
1020 .get_unique_accounts_from_storage(&account_storage_entry);
1021
1022 let offset = accounts
1024 .stored_accounts
1025 .iter()
1026 .find(|account| key1.pubkey() == *account.pubkey())
1027 .map(|account| account.index_info.offset())
1028 .expect("Pubkey1 is present in Slot0");
1029
1030 let slot = 1;
1032 let bank1 =
1033 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1034 bank1
1035 .transfer(LAMPORTS_PER_SOL, &key3, &key1.pubkey())
1036 .unwrap();
1037
1038 bank1.fill_bank_with_ticks_for_tests();
1039
1040 account_storage_entry.mark_accounts_obsolete(vec![(offset, 0)].into_iter(), slot);
1042
1043 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1044 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1045 let snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1046 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1047
1048 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1049 bank_snapshots_dir.path(),
1050 &bank1,
1051 None,
1052 snapshot_archives_dir.path(),
1053 snapshot_archives_dir.path(),
1054 snapshot_archive_format,
1055 )
1056 .unwrap();
1057
1058 let (roundtrip_bank, _) = bank_from_snapshot_archives(
1059 &[accounts_dir],
1060 bank_snapshots_dir.path(),
1061 &full_snapshot_archive_info,
1062 None,
1063 &genesis_config,
1064 &RuntimeConfig::default(),
1065 None,
1066 None,
1067 None,
1068 false,
1069 false,
1070 false,
1071 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1072 None,
1073 Arc::default(),
1074 )
1075 .unwrap();
1076 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1077 assert_eq!(*bank1, roundtrip_bank);
1078 }
1079
1080 #[test]
1084 fn test_roundtrip_bank_to_and_from_snapshot_complex() {
1085 let collector = Pubkey::new_unique();
1086 let key1 = Keypair::new();
1087 let key2 = Keypair::new();
1088 let key3 = Keypair::new();
1089 let key4 = Keypair::new();
1090 let key5 = Keypair::new();
1091
1092 let (genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
1093 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1094 bank0
1095 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1096 .unwrap();
1097 bank0
1098 .transfer(2 * LAMPORTS_PER_SOL, &mint_keypair, &key2.pubkey())
1099 .unwrap();
1100 bank0
1101 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1102 .unwrap();
1103 bank0.fill_bank_with_ticks_for_tests();
1104
1105 let slot = 1;
1106 let bank1 =
1107 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1108 bank1
1109 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1110 .unwrap();
1111 bank1
1112 .transfer(4 * LAMPORTS_PER_SOL, &mint_keypair, &key4.pubkey())
1113 .unwrap();
1114 bank1
1115 .transfer(5 * LAMPORTS_PER_SOL, &mint_keypair, &key5.pubkey())
1116 .unwrap();
1117 bank1.fill_bank_with_ticks_for_tests();
1118
1119 let slot = slot + 1;
1120 let bank2 =
1121 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1122 bank2
1123 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1124 .unwrap();
1125 bank2.fill_bank_with_ticks_for_tests();
1126
1127 let slot = slot + 1;
1128 let bank3 =
1129 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1130 bank3
1131 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1132 .unwrap();
1133 bank3.fill_bank_with_ticks_for_tests();
1134
1135 let slot = slot + 1;
1136 let bank4 =
1137 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1138 bank4
1139 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1140 .unwrap();
1141 bank4.fill_bank_with_ticks_for_tests();
1142
1143 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1144 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1145 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1146 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1147 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1148
1149 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1150 bank_snapshots_dir.path(),
1151 &bank4,
1152 None,
1153 full_snapshot_archives_dir.path(),
1154 incremental_snapshot_archives_dir.path(),
1155 snapshot_archive_format,
1156 )
1157 .unwrap();
1158
1159 let (roundtrip_bank, _) = bank_from_snapshot_archives(
1160 &[accounts_dir],
1161 bank_snapshots_dir.path(),
1162 &full_snapshot_archive_info,
1163 None,
1164 &genesis_config,
1165 &RuntimeConfig::default(),
1166 None,
1167 None,
1168 None,
1169 false,
1170 false,
1171 false,
1172 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1173 None,
1174 Arc::default(),
1175 )
1176 .unwrap();
1177 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1178 assert_eq!(*bank4, roundtrip_bank);
1179 }
1180
1181 #[test]
1191 fn test_roundtrip_bank_to_and_from_incremental_snapshot() {
1192 let collector = Pubkey::new_unique();
1193 let key1 = Keypair::new();
1194 let key2 = Keypair::new();
1195 let key3 = Keypair::new();
1196 let key4 = Keypair::new();
1197 let key5 = Keypair::new();
1198
1199 let (genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
1200 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1201 bank0
1202 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1203 .unwrap();
1204 bank0
1205 .transfer(2 * LAMPORTS_PER_SOL, &mint_keypair, &key2.pubkey())
1206 .unwrap();
1207 bank0
1208 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1209 .unwrap();
1210 bank0.fill_bank_with_ticks_for_tests();
1211
1212 let slot = 1;
1213 let bank1 =
1214 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1215 bank1
1216 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1217 .unwrap();
1218 bank1
1219 .transfer(4 * LAMPORTS_PER_SOL, &mint_keypair, &key4.pubkey())
1220 .unwrap();
1221 bank1
1222 .transfer(5 * LAMPORTS_PER_SOL, &mint_keypair, &key5.pubkey())
1223 .unwrap();
1224 bank1.fill_bank_with_ticks_for_tests();
1225
1226 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1227 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1228 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1229 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1230 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1231
1232 let full_snapshot_slot = slot;
1233 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1234 bank_snapshots_dir.path(),
1235 &bank1,
1236 None,
1237 full_snapshot_archives_dir.path(),
1238 incremental_snapshot_archives_dir.path(),
1239 snapshot_archive_format,
1240 )
1241 .unwrap();
1242
1243 let slot = slot + 1;
1244 let bank2 =
1245 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1246 bank2
1247 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1248 .unwrap();
1249 bank2.fill_bank_with_ticks_for_tests();
1250
1251 let slot = slot + 1;
1252 let bank3 =
1253 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1254 bank3
1255 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1256 .unwrap();
1257 bank3.fill_bank_with_ticks_for_tests();
1258
1259 let slot = slot + 1;
1260 let bank4 =
1261 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1262 bank4
1263 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1264 .unwrap();
1265 bank4.fill_bank_with_ticks_for_tests();
1266
1267 let incremental_snapshot_archive_info = bank_to_incremental_snapshot_archive(
1268 bank_snapshots_dir.path(),
1269 &bank4,
1270 full_snapshot_slot,
1271 None,
1272 full_snapshot_archives_dir.path(),
1273 incremental_snapshot_archives_dir.path(),
1274 snapshot_archive_format,
1275 )
1276 .unwrap();
1277
1278 let (roundtrip_bank, _) = bank_from_snapshot_archives(
1279 &[accounts_dir],
1280 bank_snapshots_dir.path(),
1281 &full_snapshot_archive_info,
1282 Some(&incremental_snapshot_archive_info),
1283 &genesis_config,
1284 &RuntimeConfig::default(),
1285 None,
1286 None,
1287 None,
1288 false,
1289 false,
1290 false,
1291 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1292 None,
1293 Arc::default(),
1294 )
1295 .unwrap();
1296 roundtrip_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1297 assert_eq!(*bank4, roundtrip_bank);
1298 }
1299
1300 #[test]
1302 fn test_bank_from_latest_snapshot_archives() {
1303 let collector = Pubkey::new_unique();
1304 let key1 = Keypair::new();
1305 let key2 = Keypair::new();
1306 let key3 = Keypair::new();
1307
1308 let (genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
1309 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1310 bank0
1311 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1312 .unwrap();
1313 bank0
1314 .transfer(2 * LAMPORTS_PER_SOL, &mint_keypair, &key2.pubkey())
1315 .unwrap();
1316 bank0
1317 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1318 .unwrap();
1319 bank0.fill_bank_with_ticks_for_tests();
1320
1321 let slot = 1;
1322 let bank1 =
1323 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1324 bank1
1325 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1326 .unwrap();
1327 bank1
1328 .transfer(2 * LAMPORTS_PER_SOL, &mint_keypair, &key2.pubkey())
1329 .unwrap();
1330 bank1
1331 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1332 .unwrap();
1333 bank1.fill_bank_with_ticks_for_tests();
1334
1335 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1336 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1337 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1338 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1339 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1340
1341 let full_snapshot_slot = slot;
1342 bank_to_full_snapshot_archive(
1343 &bank_snapshots_dir,
1344 &bank1,
1345 None,
1346 &full_snapshot_archives_dir,
1347 &incremental_snapshot_archives_dir,
1348 snapshot_archive_format,
1349 )
1350 .unwrap();
1351
1352 let slot = slot + 1;
1353 let bank2 =
1354 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1355 bank2
1356 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1357 .unwrap();
1358 bank2.fill_bank_with_ticks_for_tests();
1359
1360 let slot = slot + 1;
1361 let bank3 =
1362 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1363 bank3
1364 .transfer(2 * LAMPORTS_PER_SOL, &mint_keypair, &key2.pubkey())
1365 .unwrap();
1366 bank3.fill_bank_with_ticks_for_tests();
1367
1368 let slot = slot + 1;
1369 let bank4 =
1370 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1371 bank4
1372 .transfer(3 * LAMPORTS_PER_SOL, &mint_keypair, &key3.pubkey())
1373 .unwrap();
1374 bank4.fill_bank_with_ticks_for_tests();
1375
1376 bank_to_incremental_snapshot_archive(
1377 &bank_snapshots_dir,
1378 &bank4,
1379 full_snapshot_slot,
1380 None,
1381 &full_snapshot_archives_dir,
1382 &incremental_snapshot_archives_dir,
1383 snapshot_archive_format,
1384 )
1385 .unwrap();
1386
1387 let (deserialized_bank, ..) = bank_from_latest_snapshot_archives(
1388 &bank_snapshots_dir,
1389 &full_snapshot_archives_dir,
1390 &incremental_snapshot_archives_dir,
1391 &[accounts_dir],
1392 &genesis_config,
1393 &RuntimeConfig::default(),
1394 None,
1395 None,
1396 None,
1397 false,
1398 false,
1399 false,
1400 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1401 None,
1402 Arc::default(),
1403 )
1404 .unwrap();
1405 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1406 assert_eq!(deserialized_bank, *bank4);
1407 }
1408
1409 #[test]
1432 fn test_incremental_snapshots_handle_zero_lamport_accounts() {
1433 let collector = Pubkey::new_unique();
1434 let key1 = Keypair::new();
1435 let key2 = Keypair::new();
1436
1437 let (_tmp_dir, accounts_dir) = create_tmp_accounts_dir_for_tests();
1438 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1439 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1440 let incremental_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1441 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1442
1443 let (mut genesis_config, mint_keypair) =
1444 create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
1445 genesis_config.fee_rate_governor = solana_fee_calculator::FeeRateGovernor::new(0, 0);
1447
1448 let lamports_to_transfer = 123_456 * LAMPORTS_PER_SOL;
1449 let (bank0, bank_forks) = Bank::new_with_paths_for_tests(
1450 &genesis_config,
1451 Arc::<RuntimeConfig>::default(),
1452 BankTestConfig::default(),
1453 vec![accounts_dir.clone()],
1454 )
1455 .wrap_with_bank_forks_for_tests();
1456 bank0
1457 .transfer(lamports_to_transfer, &mint_keypair, &key2.pubkey())
1458 .unwrap();
1459 bank0.fill_bank_with_ticks_for_tests();
1460
1461 let slot = 1;
1462 let bank1 =
1463 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1464 bank1
1465 .transfer(lamports_to_transfer, &key2, &key1.pubkey())
1466 .unwrap();
1467 bank1.fill_bank_with_ticks_for_tests();
1468
1469 let full_snapshot_slot = slot;
1470 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1471 bank_snapshots_dir.path(),
1472 &bank1,
1473 None,
1474 full_snapshot_archives_dir.path(),
1475 incremental_snapshot_archives_dir.path(),
1476 snapshot_archive_format,
1477 )
1478 .unwrap();
1479
1480 let slot = slot + 1;
1481 let bank2 =
1482 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1483 let blockhash = bank2.last_blockhash();
1484 let tx = SanitizedTransaction::from_transaction_for_tests(system_transaction::transfer(
1485 &key1,
1486 &key2.pubkey(),
1487 lamports_to_transfer,
1488 blockhash,
1489 ));
1490 let fee = bank2.get_fee_for_message(tx.message()).unwrap();
1491 let tx = system_transaction::transfer(
1492 &key1,
1493 &key2.pubkey(),
1494 lamports_to_transfer - fee,
1495 blockhash,
1496 );
1497 bank2.process_transaction(&tx).unwrap();
1498 assert_eq!(
1499 bank2.get_balance(&key1.pubkey()),
1500 0,
1501 "Ensure Account1's balance is zero"
1502 );
1503 bank2.fill_bank_with_ticks_for_tests();
1504
1505 let incremental_snapshot_archive_info = bank_to_incremental_snapshot_archive(
1508 bank_snapshots_dir.path(),
1509 &bank2,
1510 full_snapshot_slot,
1511 None,
1512 full_snapshot_archives_dir.path(),
1513 incremental_snapshot_archives_dir.path(),
1514 snapshot_archive_format,
1515 )
1516 .unwrap();
1517 let (deserialized_bank, _) = bank_from_snapshot_archives(
1518 &[accounts_dir.clone()],
1519 bank_snapshots_dir.path(),
1520 &full_snapshot_archive_info,
1521 Some(&incremental_snapshot_archive_info),
1522 &genesis_config,
1523 &RuntimeConfig::default(),
1524 None,
1525 None,
1526 None,
1527 false,
1528 false,
1529 false,
1530 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1531 None,
1532 Arc::default(),
1533 )
1534 .unwrap();
1535 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1536 assert_eq!(
1537 deserialized_bank, *bank2,
1538 "Ensure rebuilding from an incremental snapshot works"
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
1546 .transfer(lamports_to_transfer, &mint_keypair, &key2.pubkey())
1547 .unwrap();
1548 bank3.fill_bank_with_ticks_for_tests();
1549
1550 let slot = slot + 1;
1551 let bank4 =
1552 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank3, &collector, slot);
1553 bank4.fill_bank_with_ticks_for_tests();
1554
1555 bank4.squash();
1557 bank4.clean_accounts();
1558 assert!(
1559 bank4.get_account_modified_slot(&key1.pubkey()).is_none(),
1560 "Ensure Account1 has been cleaned and purged from AccountsDb"
1561 );
1562
1563 let incremental_snapshot_archive_info = bank_to_incremental_snapshot_archive(
1566 bank_snapshots_dir.path(),
1567 &bank4,
1568 full_snapshot_slot,
1569 None,
1570 full_snapshot_archives_dir.path(),
1571 incremental_snapshot_archives_dir.path(),
1572 snapshot_archive_format,
1573 )
1574 .unwrap();
1575
1576 let (deserialized_bank, _) = bank_from_snapshot_archives(
1577 &[accounts_dir],
1578 bank_snapshots_dir.path(),
1579 &full_snapshot_archive_info,
1580 Some(&incremental_snapshot_archive_info),
1581 &genesis_config,
1582 &RuntimeConfig::default(),
1583 None,
1584 None,
1585 None,
1586 false,
1587 false,
1588 false,
1589 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1590 None,
1591 Arc::default(),
1592 )
1593 .unwrap();
1594 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1595 assert_eq!(
1596 deserialized_bank, *bank4,
1597 "Ensure rebuilding from an incremental snapshot works",
1598 );
1599 assert!(
1600 deserialized_bank
1601 .get_account_modified_slot(&key1.pubkey())
1602 .is_none(),
1603 "Ensure Account1 has not been brought back from the dead"
1604 );
1605 }
1606
1607 #[test_case(StorageAccess::Mmap)]
1608 #[test_case(StorageAccess::File)]
1609 fn test_bank_fields_from_snapshot(storage_access: StorageAccess) {
1610 let collector = Pubkey::new_unique();
1611 let key1 = Keypair::new();
1612
1613 let (genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
1614 let (bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1615 bank0.fill_bank_with_ticks_for_tests();
1616
1617 let slot = 1;
1618 let bank1 =
1619 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1620 bank1.fill_bank_with_ticks_for_tests();
1621
1622 let all_snapshots_dir = tempfile::TempDir::new().unwrap();
1623 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1624
1625 let full_snapshot_slot = slot;
1626 bank_to_full_snapshot_archive(
1627 &all_snapshots_dir,
1628 &bank1,
1629 None,
1630 &all_snapshots_dir,
1631 &all_snapshots_dir,
1632 snapshot_archive_format,
1633 )
1634 .unwrap();
1635
1636 let slot = slot + 1;
1637 let bank2 =
1638 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1639 bank2
1640 .transfer(LAMPORTS_PER_SOL, &mint_keypair, &key1.pubkey())
1641 .unwrap();
1642 bank2.fill_bank_with_ticks_for_tests();
1643
1644 bank_to_incremental_snapshot_archive(
1645 &all_snapshots_dir,
1646 &bank2,
1647 full_snapshot_slot,
1648 None,
1649 &all_snapshots_dir,
1650 &all_snapshots_dir,
1651 snapshot_archive_format,
1652 )
1653 .unwrap();
1654
1655 let bank_fields = bank_fields_from_snapshot_archives(
1656 &all_snapshots_dir,
1657 &all_snapshots_dir,
1658 storage_access,
1659 )
1660 .unwrap();
1661 assert_eq!(bank_fields.slot, bank2.slot());
1662 assert_eq!(bank_fields.parent_slot, bank2.parent_slot());
1663 }
1664
1665 #[test]
1666 fn test_bank_snapshot_dir_accounts_hardlinks() {
1667 let bank = Bank::new_for_tests(&GenesisConfig::default());
1668 bank.fill_bank_with_ticks_for_tests();
1669
1670 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1671 let snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1672 bank_to_full_snapshot_archive_with(
1673 &bank_snapshots_dir,
1674 &bank,
1675 SnapshotVersion::default(),
1676 &snapshot_archives_dir,
1677 &snapshot_archives_dir,
1678 SnapshotConfig::default().archive_format,
1679 true,
1680 )
1681 .unwrap();
1682
1683 let accounts_hardlinks_dir = get_bank_snapshot_dir(&bank_snapshots_dir, bank.slot())
1684 .join(snapshot_utils::SNAPSHOT_ACCOUNTS_HARDLINKS);
1685 assert!(fs::metadata(&accounts_hardlinks_dir).is_ok());
1686
1687 let mut hardlink_dirs = Vec::new();
1688 for entry in fs::read_dir(accounts_hardlinks_dir).unwrap() {
1690 let entry = entry.unwrap();
1691 let symlink = entry.path();
1692 let dst_path = fs::read_link(symlink).unwrap();
1693 assert!(fs::metadata(&dst_path).is_ok());
1694 hardlink_dirs.push(dst_path);
1695 }
1696
1697 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, bank.slot());
1698 assert!(purge_bank_snapshot(bank_snapshot_dir).is_ok());
1699
1700 assert!(hardlink_dirs.iter().all(|dir| fs::metadata(dir).is_err()));
1702 }
1703
1704 #[test_case(false)]
1705 #[test_case(true)]
1706 fn test_get_highest_bank_snapshot(should_flush_and_hard_link_storages: bool) {
1707 let genesis_config = GenesisConfig::default();
1708 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1709 let _bank = create_snapshot_dirs_for_tests(
1710 &genesis_config,
1711 &bank_snapshots_dir,
1712 4,
1713 0,
1714 should_flush_and_hard_link_storages,
1715 );
1716
1717 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1718 assert_eq!(snapshot.slot, 4);
1719
1720 let complete_flag_file = snapshot
1721 .snapshot_dir
1722 .join(snapshot_utils::SNAPSHOT_STATE_COMPLETE_FILENAME);
1723 fs::remove_file(complete_flag_file).unwrap();
1724 let snapshot_dir_4 = snapshot.snapshot_dir;
1726 assert!(snapshot_dir_4.exists());
1727 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1728 assert_eq!(snapshot.slot, 3);
1729
1730 let snapshot_version_file = snapshot
1731 .snapshot_dir
1732 .join(snapshot_utils::SNAPSHOT_VERSION_FILENAME);
1733 fs::remove_file(snapshot_version_file).unwrap();
1734 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1735 assert_eq!(snapshot.slot, 2);
1736
1737 let status_cache_file = snapshot
1738 .snapshot_dir
1739 .join(snapshot_utils::SNAPSHOT_STATUS_CACHE_FILENAME);
1740 fs::remove_file(status_cache_file).unwrap();
1741 let snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1742 assert_eq!(snapshot.slot, 1);
1743 }
1744
1745 #[test]
1746 fn test_clean_orphaned_account_snapshot_dirs() {
1747 let genesis_config = GenesisConfig::default();
1748 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1749 let _bank =
1750 create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 2, 0, true);
1751
1752 let snapshot_dir_slot_2 = bank_snapshots_dir.path().join("2");
1753 let accounts_link_dir_slot_2 =
1754 snapshot_dir_slot_2.join(snapshot_utils::SNAPSHOT_ACCOUNTS_HARDLINKS);
1755
1756 let hardlink_dirs_slot_2: Vec<PathBuf> = fs::read_dir(accounts_link_dir_slot_2)
1759 .unwrap()
1760 .map(|entry| {
1761 let symlink = entry.unwrap().path();
1762 fs::read_link(symlink).unwrap()
1763 })
1764 .collect();
1765
1766 fs::remove_dir_all(snapshot_dir_slot_2).unwrap();
1768
1769 assert!(hardlink_dirs_slot_2
1771 .iter()
1772 .all(|dir| fs::metadata(dir).is_ok()));
1773
1774 let account_snapshot_paths: Vec<PathBuf> = hardlink_dirs_slot_2
1775 .iter()
1776 .map(|dir| dir.parent().unwrap().parent().unwrap().to_path_buf())
1777 .collect();
1778 clean_orphaned_account_snapshot_dirs(&bank_snapshots_dir, &account_snapshot_paths).unwrap();
1780
1781 assert!(hardlink_dirs_slot_2
1783 .iter()
1784 .all(|dir| fs::metadata(dir).is_err()));
1785 }
1786
1787 #[test]
1790 fn test_clean_orphaned_account_snapshot_dirs_no_hard_link() {
1791 let genesis_config = GenesisConfig::default();
1792 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1793 let _bank =
1794 create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 2, 0, false);
1795
1796 let bank_snapshot_dir = snapshot_utils::get_bank_snapshot_dir(&bank_snapshots_dir, 2);
1798 assert!(fs::exists(&bank_snapshot_dir).unwrap());
1799
1800 let bank_snapshot_accounts_hard_link_dir =
1803 bank_snapshot_dir.join(snapshot_utils::SNAPSHOT_ACCOUNTS_HARDLINKS);
1804 assert!(!fs::exists(&bank_snapshot_accounts_hard_link_dir).unwrap());
1805
1806 clean_orphaned_account_snapshot_dirs(&bank_snapshots_dir, &[]).unwrap();
1808 }
1809
1810 #[test_case(false)]
1811 #[test_case(true)]
1812 fn test_purge_incomplete_bank_snapshots(should_flush_and_hard_link_storages: bool) {
1813 let genesis_config = GenesisConfig::default();
1814 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1815 let _bank = create_snapshot_dirs_for_tests(
1816 &genesis_config,
1817 &bank_snapshots_dir,
1818 2,
1819 0,
1820 should_flush_and_hard_link_storages,
1821 );
1822
1823 for slot in [1, 2] {
1825 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
1826 let state_complete_file =
1827 bank_snapshot_dir.join(snapshot_utils::SNAPSHOT_STATE_COMPLETE_FILENAME);
1828 fs::remove_file(state_complete_file).unwrap();
1829 }
1830
1831 purge_incomplete_bank_snapshots(&bank_snapshots_dir);
1832
1833 for slot in [1, 2] {
1835 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
1836 assert!(!bank_snapshot_dir.exists());
1837 }
1838 }
1839
1840 #[test_case(StorageAccess::Mmap)]
1853 #[test_case(StorageAccess::File)]
1854 fn test_snapshots_handle_zero_lamport_accounts(storage_access: StorageAccess) {
1855 let collector = Pubkey::new_unique();
1856 let key1 = Keypair::new();
1857 let key2 = Keypair::new();
1858 let key3 = Keypair::new();
1859
1860 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1861 let full_snapshot_archives_dir = tempfile::TempDir::new().unwrap();
1862 let snapshot_archive_format = SnapshotConfig::default().archive_format;
1863
1864 let (genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
1865
1866 let lamports_to_transfer = 123_456 * LAMPORTS_PER_SOL;
1867 let bank_test_config = BankTestConfig {
1868 accounts_db_config: AccountsDbConfig {
1869 storage_access,
1870 ..ACCOUNTS_DB_CONFIG_FOR_TESTING
1871 },
1872 };
1873
1874 let bank0 = Bank::new_with_config_for_tests(&genesis_config, bank_test_config);
1875
1876 let (bank0, bank_forks) = Bank::wrap_with_bank_forks_for_tests(bank0);
1877
1878 bank0
1879 .transfer(lamports_to_transfer, &mint_keypair, &key2.pubkey())
1880 .unwrap();
1881
1882 bank0.fill_bank_with_ticks_for_tests();
1883
1884 let slot = 1;
1885 let bank1 =
1886 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank0, &collector, slot);
1887 bank1
1888 .transfer(lamports_to_transfer, &key2, &key1.pubkey())
1889 .unwrap();
1890 bank1
1891 .transfer(lamports_to_transfer, &mint_keypair, &key3.pubkey())
1892 .unwrap();
1893
1894 bank1.fill_bank_with_ticks_for_tests();
1895
1896 bank1.squash();
1898 bank1.force_flush_accounts_cache();
1899
1900 let slot = slot + 1;
1901 let bank2 =
1902 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank1, &collector, slot);
1903 let blockhash = bank2.last_blockhash();
1904 let tx = SanitizedTransaction::from_transaction_for_tests(system_transaction::transfer(
1905 &key1,
1906 &key2.pubkey(),
1907 lamports_to_transfer,
1908 blockhash,
1909 ));
1910
1911 let fee = bank2.get_fee_for_message(tx.message()).unwrap();
1912 bank2
1913 .transfer(lamports_to_transfer - fee, &key1, &key2.pubkey())
1914 .unwrap();
1915
1916 assert_eq!(
1917 bank2.get_balance(&key1.pubkey()),
1918 0,
1919 "Ensure Account1's balance is zero"
1920 );
1921 bank2.fill_bank_with_ticks_for_tests();
1922
1923 let slot = slot + 1;
1924 let bank3 =
1925 new_bank_from_parent_with_bank_forks(bank_forks.as_ref(), bank2, &collector, slot);
1926 bank3
1928 .transfer(lamports_to_transfer, &mint_keypair, &key2.pubkey())
1929 .unwrap();
1930 bank3.fill_bank_with_ticks_for_tests();
1931
1932 assert!(
1933 bank3.get_account_modified_slot(&key1.pubkey()).is_none(),
1934 "Ensure Account1 has been cleaned and purged from AccountsDb"
1935 );
1936
1937 let full_snapshot_archive_info = bank_to_full_snapshot_archive(
1940 bank_snapshots_dir.path(),
1941 &bank3,
1942 None,
1943 full_snapshot_archives_dir.path(),
1944 full_snapshot_archives_dir.path(),
1945 snapshot_archive_format,
1946 )
1947 .unwrap();
1948
1949 let accounts_dir = tempfile::TempDir::new().unwrap();
1950 let other_bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1951 let (deserialized_bank, _) = bank_from_snapshot_archives(
1952 &[accounts_dir.path().to_path_buf()],
1953 other_bank_snapshots_dir.path(),
1954 &full_snapshot_archive_info,
1955 None,
1956 &genesis_config,
1957 &RuntimeConfig::default(),
1958 None,
1959 None,
1960 None,
1961 false,
1962 false,
1963 false,
1964 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
1965 None,
1966 Arc::default(),
1967 )
1968 .unwrap();
1969
1970 deserialized_bank.wait_for_initial_accounts_hash_verification_completed_for_tests();
1971
1972 assert!(
1973 deserialized_bank
1974 .get_account_modified_slot(&key1.pubkey())
1975 .is_none(),
1976 "Ensure Account1 has not been brought back from the dead"
1977 );
1978
1979 assert_eq!(*bank3, deserialized_bank);
1980 }
1981
1982 #[test_case(StorageAccess::Mmap)]
1983 #[test_case(StorageAccess::File)]
1984 fn test_bank_from_snapshot_dir(storage_access: StorageAccess) {
1985 let genesis_config = GenesisConfig::default();
1986 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
1987 let bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 3, 0, true);
1988
1989 let bank_snapshot = get_highest_bank_snapshot(&bank_snapshots_dir).unwrap();
1990 let account_paths = &bank.rc.accounts.accounts_db.paths;
1991
1992 let (bank_constructed, ..) = bank_from_snapshot_dir(
1993 account_paths,
1994 &bank_snapshot,
1995 &genesis_config,
1996 &RuntimeConfig::default(),
1997 None,
1998 None,
1999 None,
2000 false,
2001 Some(AccountsDbConfig {
2002 storage_access,
2003 ..ACCOUNTS_DB_CONFIG_FOR_TESTING
2004 }),
2005 None,
2006 Arc::default(),
2007 )
2008 .unwrap();
2009
2010 bank_constructed.wait_for_initial_accounts_hash_verification_completed_for_tests();
2011 assert_eq!(bank_constructed, bank);
2012
2013 let mut max_id = 0;
2015 for path in account_paths {
2016 fs::read_dir(path).unwrap().for_each(|entry| {
2017 let path = entry.unwrap().path();
2018 let filename = path.file_name().unwrap();
2019 let (_slot, append_vec_id) =
2020 get_slot_and_append_vec_id(filename.to_str().unwrap()).unwrap();
2021 max_id = std::cmp::max(max_id, append_vec_id);
2022 });
2023 }
2024 let next_id = bank.accounts().accounts_db.next_id.load(Ordering::Relaxed) as usize;
2025 assert_eq!(max_id, next_id - 1);
2026 }
2027
2028 #[test]
2029 fn test_bank_from_latest_snapshot_dir() {
2030 let genesis_config = GenesisConfig::default();
2031 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2032 let bank = create_snapshot_dirs_for_tests(&genesis_config, &bank_snapshots_dir, 3, 3, true);
2033
2034 let account_paths = &bank.rc.accounts.accounts_db.paths;
2035
2036 let deserialized_bank = bank_from_latest_snapshot_dir(
2037 &bank_snapshots_dir,
2038 &genesis_config,
2039 &RuntimeConfig::default(),
2040 account_paths,
2041 None,
2042 None,
2043 None,
2044 false,
2045 Some(ACCOUNTS_DB_CONFIG_FOR_TESTING),
2046 None,
2047 Arc::default(),
2048 )
2049 .unwrap();
2050
2051 assert_eq!(
2052 deserialized_bank, bank,
2053 "Ensure rebuilding bank from the highest snapshot dir results in the highest bank",
2054 );
2055 }
2056
2057 #[test_case(false)]
2058 #[test_case(true)]
2059 fn test_purge_all_bank_snapshots(should_flush_and_hard_link_storages: bool) {
2060 let genesis_config = GenesisConfig::default();
2061 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2062 let _bank = create_snapshot_dirs_for_tests(
2063 &genesis_config,
2064 &bank_snapshots_dir,
2065 10,
2066 5,
2067 should_flush_and_hard_link_storages,
2068 );
2069 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 10);
2073 purge_all_bank_snapshots(&bank_snapshots_dir);
2074 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 0);
2075 }
2076
2077 #[test_case(false)]
2078 #[test_case(true)]
2079 fn test_purge_old_bank_snapshots(should_flush_and_hard_link_storages: bool) {
2080 let genesis_config = GenesisConfig::default();
2081 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2082 let _bank = create_snapshot_dirs_for_tests(
2083 &genesis_config,
2084 &bank_snapshots_dir,
2085 10,
2086 5,
2087 should_flush_and_hard_link_storages,
2088 );
2089 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 10);
2093
2094 purge_old_bank_snapshots(&bank_snapshots_dir, 3, Some(BankSnapshotKind::Pre));
2095 assert_eq!(get_bank_snapshots_pre(&bank_snapshots_dir).len(), 3);
2096
2097 purge_old_bank_snapshots(&bank_snapshots_dir, 2, Some(BankSnapshotKind::Post));
2098 assert_eq!(get_bank_snapshots_post(&bank_snapshots_dir).len(), 2);
2099
2100 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 5);
2101
2102 purge_old_bank_snapshots(&bank_snapshots_dir, 2, None);
2103 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 2);
2104
2105 purge_old_bank_snapshots(&bank_snapshots_dir, 0, None);
2106 assert_eq!(get_bank_snapshots(&bank_snapshots_dir).len(), 0);
2107 }
2108
2109 #[test_case(false)]
2110 #[test_case(true)]
2111 fn test_purge_bank_snapshots_older_than_slot(should_flush_and_hard_link_storages: bool) {
2112 let genesis_config = GenesisConfig::default();
2113 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2114
2115 let _bank = create_snapshot_dirs_for_tests(
2117 &genesis_config,
2118 &bank_snapshots_dir,
2119 9,
2120 6,
2121 should_flush_and_hard_link_storages,
2122 );
2123 let bank_snapshots_before = get_bank_snapshots(&bank_snapshots_dir);
2124
2125 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, 0);
2126 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2127 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len());
2128
2129 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, 3);
2130 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2131 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len() + 2);
2132
2133 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, 8);
2134 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2135 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len() + 7);
2136
2137 purge_bank_snapshots_older_than_slot(&bank_snapshots_dir, Slot::MAX);
2138 let bank_snapshots_after = get_bank_snapshots(&bank_snapshots_dir);
2139 assert_eq!(bank_snapshots_before.len(), bank_snapshots_after.len() + 9);
2140 assert!(bank_snapshots_after.is_empty());
2141 }
2142
2143 #[test_case(false)]
2144 #[test_case(true)]
2145 fn test_purge_old_bank_snapshots_at_startup(should_flush_and_hard_link_storages: bool) {
2146 let genesis_config = GenesisConfig::default();
2147 let bank_snapshots_dir = tempfile::TempDir::new().unwrap();
2148
2149 let _bank = create_snapshot_dirs_for_tests(
2151 &genesis_config,
2152 &bank_snapshots_dir,
2153 9,
2154 6,
2155 should_flush_and_hard_link_storages,
2156 );
2157
2158 purge_old_bank_snapshots_at_startup(&bank_snapshots_dir);
2159
2160 let bank_snapshots_pre = get_bank_snapshots_pre(&bank_snapshots_dir);
2161 assert!(bank_snapshots_pre.is_empty());
2162
2163 let bank_snapshots_post = get_bank_snapshots_post(&bank_snapshots_dir);
2164 assert_eq!(bank_snapshots_post.len(), 1);
2165 assert_eq!(bank_snapshots_post.first().unwrap().slot, 6);
2166 }
2167
2168 #[test]
2169 fn test_verify_slot_deltas_structural_bad_too_many_entries() {
2170 let bank_slot = status_cache::MAX_CACHE_ENTRIES as Slot + 1;
2171 let slot_deltas: Vec<_> = (0..bank_slot)
2172 .map(|slot| (slot, true, Status::default()))
2173 .collect();
2174
2175 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2176 assert_eq!(
2177 result,
2178 Err(VerifySlotDeltasError::TooManyEntries(
2179 status_cache::MAX_CACHE_ENTRIES + 1,
2180 status_cache::MAX_CACHE_ENTRIES
2181 )),
2182 );
2183 }
2184
2185 #[test]
2186 fn test_verify_slot_deltas_structural_good() {
2187 let slot_deltas = vec![
2189 (222, true, Status::default()),
2190 (333, true, Status::default()),
2191 (111, true, Status::default()),
2192 ];
2193
2194 let bank_slot = 333;
2195 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2196 assert_eq!(
2197 result,
2198 Ok(VerifySlotDeltasStructuralInfo {
2199 slots: HashSet::from([111, 222, 333])
2200 })
2201 );
2202 }
2203
2204 #[test]
2205 fn test_verify_slot_deltas_structural_bad_slot_not_root() {
2206 let slot_deltas = vec![
2207 (111, true, Status::default()),
2208 (222, false, Status::default()), (333, true, Status::default()),
2210 ];
2211
2212 let bank_slot = 333;
2213 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2214 assert_eq!(result, Err(VerifySlotDeltasError::SlotIsNotRoot(222)));
2215 }
2216
2217 #[test]
2218 fn test_verify_slot_deltas_structural_bad_slot_greater_than_bank() {
2219 let slot_deltas = vec![
2220 (222, true, Status::default()),
2221 (111, true, Status::default()),
2222 (555, true, Status::default()), ];
2224
2225 let bank_slot = 444;
2226 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2227 assert_eq!(
2228 result,
2229 Err(VerifySlotDeltasError::SlotGreaterThanMaxRoot(
2230 555, bank_slot
2231 )),
2232 );
2233 }
2234
2235 #[test]
2236 fn test_verify_slot_deltas_structural_bad_slot_has_multiple_entries() {
2237 let slot_deltas = vec![
2238 (111, true, Status::default()),
2239 (222, true, Status::default()),
2240 (111, true, Status::default()), ];
2242
2243 let bank_slot = 222;
2244 let result = verify_slot_deltas_structural(slot_deltas.as_slice(), bank_slot);
2245 assert_eq!(
2246 result,
2247 Err(VerifySlotDeltasError::SlotHasMultipleEntries(111)),
2248 );
2249 }
2250
2251 #[test]
2252 fn test_verify_slot_deltas_with_history_good() {
2253 let mut slots_from_slot_deltas = HashSet::default();
2254 let mut slot_history = SlotHistory::default();
2255 for slot in [0, 111, 222, 333, 444] {
2257 slots_from_slot_deltas.insert(slot);
2258 slot_history.add(slot);
2259 }
2260
2261 let bank_slot = 444;
2262 let result =
2263 verify_slot_deltas_with_history(&slots_from_slot_deltas, &slot_history, bank_slot);
2264 assert_eq!(result, Ok(()));
2265 }
2266
2267 #[test]
2268 fn test_verify_slot_deltas_with_history_bad_slot_not_in_history() {
2269 let slots_from_slot_deltas = HashSet::from([
2270 0, 444, 222,
2272 ]);
2273 let mut slot_history = SlotHistory::default();
2274 slot_history.add(444); let bank_slot = 444;
2277 let result =
2278 verify_slot_deltas_with_history(&slots_from_slot_deltas, &slot_history, bank_slot);
2279
2280 assert_eq!(
2281 result,
2282 Err(VerifySlotDeltasError::SlotNotFoundInHistory(222)),
2283 );
2284 }
2285
2286 #[test]
2287 fn test_verify_slot_deltas_with_history_bad_slot_not_in_deltas() {
2288 let slots_from_slot_deltas = HashSet::from([
2289 0, 444, 222,
2291 ]);
2293 let mut slot_history = SlotHistory::default();
2294 slot_history.add(222);
2295 slot_history.add(333);
2296 slot_history.add(444);
2297
2298 let bank_slot = 444;
2299 let result =
2300 verify_slot_deltas_with_history(&slots_from_slot_deltas, &slot_history, bank_slot);
2301
2302 assert_eq!(
2303 result,
2304 Err(VerifySlotDeltasError::SlotNotFoundInDeltas(333)),
2305 );
2306 }
2307
2308 #[test]
2309 fn test_verify_slot_history_good() {
2310 let mut slot_history = SlotHistory::default();
2311 for slot in [0, 111, 222, 333, 444] {
2313 slot_history.add(slot);
2314 }
2315
2316 let bank_slot = 444;
2317 let result = verify_slot_history(&slot_history, bank_slot);
2318 assert_eq!(result, Ok(()));
2319 }
2320
2321 #[test]
2322 fn test_verify_slot_history_bad_invalid_newest_slot() {
2323 let slot_history = SlotHistory::default();
2324 let bank_slot = 444;
2325 let result = verify_slot_history(&slot_history, bank_slot);
2326 assert_eq!(result, Err(VerifySlotHistoryError::InvalidNewestSlot));
2327 }
2328
2329 #[test]
2330 fn test_verify_slot_history_bad_invalid_num_entries() {
2331 let mut slot_history = SlotHistory::default();
2332 slot_history.bits.truncate(slot_history.bits.len() - 1);
2333
2334 let bank_slot = 0;
2335 let result = verify_slot_history(&slot_history, bank_slot);
2336 assert_eq!(result, Err(VerifySlotHistoryError::InvalidNumEntries));
2337 }
2338
2339 #[test]
2340 fn test_verify_epoch_stakes_good() {
2341 let bank = create_simple_test_bank(100 * LAMPORTS_PER_SOL);
2342 assert_eq!(verify_epoch_stakes(&bank), Ok(()));
2343 }
2344
2345 #[test]
2346 fn test_verify_epoch_stakes_bad() {
2347 let bank = create_simple_test_bank(100 * LAMPORTS_PER_SOL);
2348 let current_epoch = bank.epoch();
2349 let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
2350 let required_epochs = current_epoch..=leader_schedule_epoch;
2351
2352 {
2354 let mut epoch_stakes_map = bank.epoch_stakes_map().clone();
2355 let invalid_epoch = *required_epochs.end() + 1;
2356 epoch_stakes_map.insert(
2357 invalid_epoch,
2358 bank.epoch_stakes(bank.epoch()).cloned().unwrap(),
2359 );
2360
2361 assert_eq!(
2362 _verify_epoch_stakes(&epoch_stakes_map, required_epochs.clone()),
2363 Err(VerifyEpochStakesError::EpochGreaterThanMax(
2364 invalid_epoch,
2365 *required_epochs.end(),
2366 )),
2367 );
2368 }
2369
2370 {
2372 for removed_epoch in required_epochs.clone() {
2373 let mut epoch_stakes_map = bank.epoch_stakes_map().clone();
2374 let removed_stakes = epoch_stakes_map.remove(&removed_epoch);
2375 assert!(removed_stakes.is_some());
2376
2377 assert_eq!(
2378 _verify_epoch_stakes(&epoch_stakes_map, required_epochs.clone()),
2379 Err(VerifyEpochStakesError::StakesNotFound(
2380 removed_epoch,
2381 required_epochs.clone(),
2382 )),
2383 );
2384 }
2385 }
2386 }
2387
2388 #[test]
2389 fn test_get_highest_loadable_bank_snapshot() {
2390 let bank_snapshots_dir = TempDir::new().unwrap();
2391 let snapshot_archives_dir = TempDir::new().unwrap();
2392
2393 let snapshot_config = SnapshotConfig {
2394 bank_snapshots_dir: bank_snapshots_dir.as_ref().to_path_buf(),
2395 full_snapshot_archives_dir: snapshot_archives_dir.as_ref().to_path_buf(),
2396 incremental_snapshot_archives_dir: snapshot_archives_dir.as_ref().to_path_buf(),
2397 ..Default::default()
2398 };
2399 let load_only_snapshot_config = SnapshotConfig {
2400 bank_snapshots_dir: snapshot_config.bank_snapshots_dir.clone(),
2401 full_snapshot_archives_dir: snapshot_config.full_snapshot_archives_dir.clone(),
2402 incremental_snapshot_archives_dir: snapshot_config
2403 .incremental_snapshot_archives_dir
2404 .clone(),
2405 ..SnapshotConfig::new_load_only()
2406 };
2407
2408 let genesis_config = GenesisConfig::default();
2409 let mut bank = Arc::new(Bank::new_for_tests(&genesis_config));
2410 let mut full_snapshot_archive_info = None;
2411
2412 for _ in 0..snapshot_config
2415 .maximum_full_snapshot_archives_to_retain
2416 .get()
2417 + 1
2418 {
2419 let slot = bank.slot() + 1;
2420 bank = Arc::new(Bank::new_from_parent(bank, &Pubkey::default(), slot));
2421 bank.fill_bank_with_ticks_for_tests();
2422 full_snapshot_archive_info = Some(
2423 bank_to_full_snapshot_archive_with(
2424 &snapshot_config.bank_snapshots_dir,
2425 &bank,
2426 snapshot_config.snapshot_version,
2427 &snapshot_config.full_snapshot_archives_dir,
2428 &snapshot_config.incremental_snapshot_archives_dir,
2429 snapshot_config.archive_format,
2430 false,
2431 )
2432 .unwrap(),
2433 );
2434 }
2435
2436 let slot = bank.slot();
2438 let bank_snapshot_dir = get_bank_snapshot_dir(&bank_snapshots_dir, slot);
2439 let post = bank_snapshot_dir.join(get_snapshot_file_name(slot));
2440 let pre = post.with_extension(BANK_SNAPSHOT_PRE_FILENAME_EXTENSION);
2441 fs::rename(post, pre).unwrap();
2442
2443 fs::remove_file(full_snapshot_archive_info.unwrap().path()).unwrap();
2445
2446 let highest_full_snapshot_archive =
2447 get_highest_full_snapshot_archive_info(&snapshot_archives_dir).unwrap();
2448 let highest_bank_snapshot_post =
2449 get_highest_bank_snapshot_post(&bank_snapshots_dir).unwrap();
2450 let highest_bank_snapshot_pre = get_highest_bank_snapshot_pre(&bank_snapshots_dir).unwrap();
2451
2452 assert!(highest_bank_snapshot_pre.slot > highest_bank_snapshot_post.slot);
2455
2456 assert!(get_highest_loadable_bank_snapshot(&SnapshotConfig::default()).is_none());
2458
2459 assert!(get_highest_loadable_bank_snapshot(&snapshot_config).is_none());
2461
2462 snapshot_utils::write_storages_flushed_file(&highest_bank_snapshot_post.snapshot_dir)
2464 .unwrap();
2465 let bank_snapshot = get_highest_loadable_bank_snapshot(&snapshot_config).unwrap();
2466 assert_eq!(bank_snapshot, highest_bank_snapshot_post);
2467
2468 fs::remove_file(highest_full_snapshot_archive.path()).unwrap();
2470 assert!(get_highest_loadable_bank_snapshot(&snapshot_config).is_none());
2471
2472 let bank_snapshot = get_highest_loadable_bank_snapshot(&load_only_snapshot_config).unwrap();
2474 assert_eq!(bank_snapshot, highest_bank_snapshot_post);
2475
2476 fs::remove_dir_all(&highest_bank_snapshot_post.snapshot_dir).unwrap();
2478 assert!(get_highest_loadable_bank_snapshot(&snapshot_config).is_none());
2479
2480 snapshot_utils::write_storages_flushed_file(get_bank_snapshot_dir(
2482 &snapshot_config.bank_snapshots_dir,
2483 highest_bank_snapshot_post.slot - 1,
2484 ))
2485 .unwrap();
2486 let bank_snapshot = get_highest_loadable_bank_snapshot(&snapshot_config).unwrap();
2487 assert_eq!(bank_snapshot.slot, highest_bank_snapshot_post.slot - 1);
2488
2489 fs::remove_file(
2491 bank_snapshot
2492 .snapshot_dir
2493 .join(SNAPSHOT_FULL_SNAPSHOT_SLOT_FILENAME),
2494 )
2495 .unwrap();
2496 assert!(get_highest_loadable_bank_snapshot(&snapshot_config).is_none());
2497
2498 let bank_snapshot2 =
2500 get_highest_loadable_bank_snapshot(&load_only_snapshot_config).unwrap();
2501 assert_eq!(bank_snapshot2, bank_snapshot);
2502 }
2503}