1use {
2 crate::{
3 bank::{Bank, BankFieldsToSerialize, BankSlotDelta},
4 serde_snapshot::BankIncrementalSnapshotPersistence,
5 snapshot_hash::SnapshotHash,
6 },
7 log::*,
8 solana_accounts_db::{
9 account_storage::meta::StoredMetaWriteVersion,
10 accounts::Accounts,
11 accounts_db::{stats::BankHashStats, AccountStorageEntry},
12 accounts_hash::{AccountsDeltaHash, AccountsHash, AccountsHashKind},
13 epoch_accounts_hash::EpochAccountsHash,
14 },
15 solana_sdk::{
16 clock::Slot, hash::Hash, rent_collector::RentCollector,
17 sysvar::epoch_schedule::EpochSchedule,
18 },
19 std::{
20 sync::{atomic::Ordering, Arc},
21 time::Instant,
22 },
23};
24
25mod compare;
26pub use compare::*;
27
28pub struct AccountsPackage {
30 pub package_kind: AccountsPackageKind,
31 pub slot: Slot,
32 pub block_height: Slot,
33 pub snapshot_storages: Vec<Arc<AccountStorageEntry>>,
34 pub expected_capitalization: u64,
35 pub accounts_hash_for_testing: Option<AccountsHash>,
36 pub accounts: Arc<Accounts>,
37 pub epoch_schedule: EpochSchedule,
38 pub rent_collector: RentCollector,
39
40 pub snapshot_info: Option<SupplementalSnapshotInfo>,
42
43 pub enqueued: Instant,
46}
47
48impl AccountsPackage {
49 pub fn new_for_snapshot(
51 package_kind: AccountsPackageKind,
52 bank: &Bank,
53 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
54 status_cache_slot_deltas: Vec<BankSlotDelta>,
55 accounts_hash_for_testing: Option<AccountsHash>,
56 ) -> Self {
57 let slot = bank.slot();
58 if let AccountsPackageKind::Snapshot(snapshot_kind) = package_kind {
59 info!(
60 "Package snapshot for bank {} has {} account storage entries (snapshot kind: {:?})",
61 slot,
62 snapshot_storages.len(),
63 snapshot_kind,
64 );
65 if let SnapshotKind::IncrementalSnapshot(incremental_snapshot_base_slot) = snapshot_kind
66 {
67 assert!(
68 slot > incremental_snapshot_base_slot,
69 "Incremental snapshot base slot must be less than the bank being snapshotted!"
70 );
71 }
72 }
73
74 let snapshot_info = {
75 let accounts_db = &bank.rc.accounts.accounts_db;
76 let write_version = accounts_db.write_version.load(Ordering::Acquire);
77 let accounts_delta_hash = accounts_db.get_accounts_delta_hash(slot).unwrap();
81 let bank_hash_stats = accounts_db.get_bank_hash_stats(slot).unwrap();
83 let bank_fields_to_serialize = bank.get_fields_to_serialize();
84 SupplementalSnapshotInfo {
85 status_cache_slot_deltas,
86 bank_fields_to_serialize,
87 bank_hash_stats,
88 accounts_delta_hash,
89 must_include_epoch_accounts_hash: bank
90 .must_include_epoch_accounts_hash_in_snapshot(),
91 write_version,
92 }
93 };
94
95 Self::_new(
96 package_kind,
97 bank,
98 snapshot_storages,
99 accounts_hash_for_testing,
100 Some(snapshot_info),
101 )
102 }
103
104 #[must_use]
106 pub fn new_for_accounts_hash_verifier(
107 package_kind: AccountsPackageKind,
108 bank: &Bank,
109 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
110 accounts_hash_for_testing: Option<AccountsHash>,
111 ) -> Self {
112 assert_eq!(package_kind, AccountsPackageKind::AccountsHashVerifier);
113 Self::_new(
114 package_kind,
115 bank,
116 snapshot_storages,
117 accounts_hash_for_testing,
118 None,
119 )
120 }
121
122 #[must_use]
124 pub fn new_for_epoch_accounts_hash(
125 package_kind: AccountsPackageKind,
126 bank: &Bank,
127 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
128 accounts_hash_for_testing: Option<AccountsHash>,
129 ) -> Self {
130 assert_eq!(package_kind, AccountsPackageKind::EpochAccountsHash);
131 Self::_new(
132 package_kind,
133 bank,
134 snapshot_storages,
135 accounts_hash_for_testing,
136 None,
137 )
138 }
139
140 fn _new(
141 package_kind: AccountsPackageKind,
142 bank: &Bank,
143 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
144 accounts_hash_for_testing: Option<AccountsHash>,
145 snapshot_info: Option<SupplementalSnapshotInfo>,
146 ) -> Self {
147 Self {
148 package_kind,
149 slot: bank.slot(),
150 block_height: bank.block_height(),
151 snapshot_storages,
152 expected_capitalization: bank.capitalization(),
153 accounts_hash_for_testing,
154 accounts: bank.accounts(),
155 epoch_schedule: bank.epoch_schedule().clone(),
156 rent_collector: bank.rent_collector().clone(),
157 snapshot_info,
158 enqueued: Instant::now(),
159 }
160 }
161
162 #[cfg(feature = "dev-context-only-utils")]
165 pub fn default_for_tests() -> Self {
166 use solana_accounts_db::accounts_db::AccountsDb;
167 let accounts_db = AccountsDb::default_for_tests();
168 let accounts = Accounts::new(Arc::new(accounts_db));
169 Self {
170 package_kind: AccountsPackageKind::AccountsHashVerifier,
171 slot: Slot::default(),
172 block_height: Slot::default(),
173 snapshot_storages: Vec::default(),
174 expected_capitalization: u64::default(),
175 accounts_hash_for_testing: Option::default(),
176 accounts: Arc::new(accounts),
177 epoch_schedule: EpochSchedule::default(),
178 rent_collector: RentCollector::default(),
179 snapshot_info: Some(SupplementalSnapshotInfo {
180 status_cache_slot_deltas: Vec::default(),
181 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
182 bank_hash_stats: BankHashStats::default(),
183 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
184 must_include_epoch_accounts_hash: false,
185 write_version: StoredMetaWriteVersion::default(),
186 }),
187 enqueued: Instant::now(),
188 }
189 }
190}
191
192impl std::fmt::Debug for AccountsPackage {
193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194 f.debug_struct("AccountsPackage")
195 .field("kind", &self.package_kind)
196 .field("slot", &self.slot)
197 .field("block_height", &self.block_height)
198 .finish_non_exhaustive()
199 }
200}
201
202pub struct SupplementalSnapshotInfo {
204 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
205 pub bank_fields_to_serialize: BankFieldsToSerialize,
206 pub bank_hash_stats: BankHashStats,
207 pub accounts_delta_hash: AccountsDeltaHash,
208 pub must_include_epoch_accounts_hash: bool,
209 pub write_version: StoredMetaWriteVersion,
210}
211
212#[derive(Debug, Copy, Clone, Eq, PartialEq)]
216pub enum AccountsPackageKind {
217 AccountsHashVerifier,
218 Snapshot(SnapshotKind),
219 EpochAccountsHash,
220}
221
222pub struct SnapshotPackage {
224 pub snapshot_kind: SnapshotKind,
225 pub slot: Slot,
226 pub block_height: Slot,
227 pub hash: SnapshotHash,
228 pub snapshot_storages: Vec<Arc<AccountStorageEntry>>,
229 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
230 pub bank_fields_to_serialize: BankFieldsToSerialize,
231 pub bank_hash_stats: BankHashStats,
232 pub accounts_delta_hash: AccountsDeltaHash,
233 pub accounts_hash: AccountsHash,
234 pub epoch_accounts_hash: Option<EpochAccountsHash>,
235 pub write_version: StoredMetaWriteVersion,
236 pub bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
237
238 pub enqueued: Instant,
241}
242
243impl SnapshotPackage {
244 pub fn new(
245 accounts_package: AccountsPackage,
246 accounts_hash_kind: AccountsHashKind,
247 bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
248 ) -> Self {
249 let AccountsPackageKind::Snapshot(kind) = accounts_package.package_kind else {
250 panic!(
251 "The AccountsPackage must be of kind Snapshot in order to make a SnapshotPackage!"
252 );
253 };
254 let Some(snapshot_info) = accounts_package.snapshot_info else {
255 panic!(
256 "The AccountsPackage must have snapshot info in order to make a SnapshotPackage!"
257 );
258 };
259
260 let accounts_hash = match accounts_hash_kind {
261 AccountsHashKind::Full(accounts_hash) => accounts_hash,
262 AccountsHashKind::Incremental(_) => {
263 assert!(bank_incremental_snapshot_persistence.is_some());
269 AccountsHash(Hash::default())
270 }
271 };
272
273 let epoch_accounts_hash = snapshot_info.must_include_epoch_accounts_hash.then(|| {
274 accounts_package
280 .accounts
281 .accounts_db
282 .epoch_accounts_hash_manager
283 .try_get_epoch_accounts_hash()
284 .unwrap()
285 });
286
287 Self {
288 snapshot_kind: kind,
289 slot: accounts_package.slot,
290 block_height: accounts_package.block_height,
291 hash: SnapshotHash::new(&accounts_hash_kind, epoch_accounts_hash.as_ref()),
292 snapshot_storages: accounts_package.snapshot_storages,
293 status_cache_slot_deltas: snapshot_info.status_cache_slot_deltas,
294 bank_fields_to_serialize: snapshot_info.bank_fields_to_serialize,
295 accounts_delta_hash: snapshot_info.accounts_delta_hash,
296 bank_hash_stats: snapshot_info.bank_hash_stats,
297 accounts_hash,
298 epoch_accounts_hash,
299 bank_incremental_snapshot_persistence,
300 write_version: snapshot_info.write_version,
301 enqueued: Instant::now(),
302 }
303 }
304}
305
306#[cfg(feature = "dev-context-only-utils")]
307impl SnapshotPackage {
308 pub fn default_for_tests() -> Self {
311 Self {
312 snapshot_kind: SnapshotKind::FullSnapshot,
313 slot: Slot::default(),
314 block_height: Slot::default(),
315 hash: SnapshotHash(Hash::default()),
316 snapshot_storages: Vec::default(),
317 status_cache_slot_deltas: Vec::default(),
318 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
319 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
320 bank_hash_stats: BankHashStats::default(),
321 accounts_hash: AccountsHash(Hash::default()),
322 epoch_accounts_hash: None,
323 bank_incremental_snapshot_persistence: None,
324 write_version: StoredMetaWriteVersion::default(),
325 enqueued: Instant::now(),
326 }
327 }
328}
329
330impl std::fmt::Debug for SnapshotPackage {
331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332 f.debug_struct("SnapshotPackage")
333 .field("kind", &self.snapshot_kind)
334 .field("slot", &self.slot)
335 .field("block_height", &self.block_height)
336 .finish_non_exhaustive()
337 }
338}
339
340#[derive(Clone, Copy, Debug, Eq, PartialEq)]
343pub enum SnapshotKind {
344 FullSnapshot,
345 IncrementalSnapshot(Slot),
346}
347
348impl SnapshotKind {
349 pub fn is_full_snapshot(&self) -> bool {
350 matches!(self, SnapshotKind::FullSnapshot)
351 }
352 pub fn is_incremental_snapshot(&self) -> bool {
353 matches!(self, SnapshotKind::IncrementalSnapshot(_))
354 }
355}