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