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 epoch_accounts_hash: bank.get_epoch_accounts_hash_to_serialize(),
90 write_version,
91 }
92 };
93
94 Self::_new(
95 package_kind,
96 bank,
97 snapshot_storages,
98 accounts_hash_for_testing,
99 Some(snapshot_info),
100 )
101 }
102
103 #[must_use]
105 pub fn new_for_accounts_hash_verifier(
106 package_kind: AccountsPackageKind,
107 bank: &Bank,
108 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
109 accounts_hash_for_testing: Option<AccountsHash>,
110 ) -> Self {
111 assert_eq!(package_kind, AccountsPackageKind::AccountsHashVerifier);
112 Self::_new(
113 package_kind,
114 bank,
115 snapshot_storages,
116 accounts_hash_for_testing,
117 None,
118 )
119 }
120
121 #[must_use]
123 pub fn new_for_epoch_accounts_hash(
124 package_kind: AccountsPackageKind,
125 bank: &Bank,
126 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
127 accounts_hash_for_testing: Option<AccountsHash>,
128 ) -> Self {
129 assert_eq!(package_kind, AccountsPackageKind::EpochAccountsHash);
130 Self::_new(
131 package_kind,
132 bank,
133 snapshot_storages,
134 accounts_hash_for_testing,
135 None,
136 )
137 }
138
139 fn _new(
140 package_kind: AccountsPackageKind,
141 bank: &Bank,
142 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
143 accounts_hash_for_testing: Option<AccountsHash>,
144 snapshot_info: Option<SupplementalSnapshotInfo>,
145 ) -> Self {
146 Self {
147 package_kind,
148 slot: bank.slot(),
149 block_height: bank.block_height(),
150 snapshot_storages,
151 expected_capitalization: bank.capitalization(),
152 accounts_hash_for_testing,
153 accounts: bank.accounts(),
154 epoch_schedule: bank.epoch_schedule().clone(),
155 rent_collector: bank.rent_collector().clone(),
156 snapshot_info,
157 enqueued: Instant::now(),
158 }
159 }
160
161 #[cfg(feature = "dev-context-only-utils")]
164 pub fn default_for_tests() -> Self {
165 use solana_accounts_db::accounts_db::AccountsDb;
166 let accounts_db = AccountsDb::default_for_tests();
167 let accounts = Accounts::new(Arc::new(accounts_db));
168 Self {
169 package_kind: AccountsPackageKind::AccountsHashVerifier,
170 slot: Slot::default(),
171 block_height: Slot::default(),
172 snapshot_storages: Vec::default(),
173 expected_capitalization: u64::default(),
174 accounts_hash_for_testing: Option::default(),
175 accounts: Arc::new(accounts),
176 epoch_schedule: EpochSchedule::default(),
177 rent_collector: RentCollector::default(),
178 snapshot_info: Some(SupplementalSnapshotInfo {
179 status_cache_slot_deltas: Vec::default(),
180 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
181 bank_hash_stats: BankHashStats::default(),
182 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
183 epoch_accounts_hash: Option::default(),
184 write_version: StoredMetaWriteVersion::default(),
185 }),
186 enqueued: Instant::now(),
187 }
188 }
189}
190
191impl std::fmt::Debug for AccountsPackage {
192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193 f.debug_struct("AccountsPackage")
194 .field("kind", &self.package_kind)
195 .field("slot", &self.slot)
196 .field("block_height", &self.block_height)
197 .finish_non_exhaustive()
198 }
199}
200
201pub struct SupplementalSnapshotInfo {
203 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
204 pub bank_fields_to_serialize: BankFieldsToSerialize,
205 pub bank_hash_stats: BankHashStats,
206 pub accounts_delta_hash: AccountsDeltaHash,
207 pub epoch_accounts_hash: Option<EpochAccountsHash>,
208 pub write_version: StoredMetaWriteVersion,
209}
210
211#[derive(Debug, Copy, Clone, Eq, PartialEq)]
215pub enum AccountsPackageKind {
216 AccountsHashVerifier,
217 Snapshot(SnapshotKind),
218 EpochAccountsHash,
219}
220
221pub struct SnapshotPackage {
223 pub snapshot_kind: SnapshotKind,
224 pub slot: Slot,
225 pub block_height: Slot,
226 pub hash: SnapshotHash,
227 pub snapshot_storages: Vec<Arc<AccountStorageEntry>>,
228 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
229 pub bank_fields_to_serialize: BankFieldsToSerialize,
230 pub bank_hash_stats: BankHashStats,
231 pub accounts_delta_hash: AccountsDeltaHash,
232 pub accounts_hash: AccountsHash,
233 pub epoch_accounts_hash: Option<EpochAccountsHash>,
234 pub write_version: StoredMetaWriteVersion,
235 pub bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
236
237 pub enqueued: Instant,
240}
241
242impl SnapshotPackage {
243 pub fn new(
244 accounts_package: AccountsPackage,
245 accounts_hash_kind: AccountsHashKind,
246 bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
247 ) -> Self {
248 let AccountsPackageKind::Snapshot(kind) = accounts_package.package_kind else {
249 panic!(
250 "The AccountsPackage must be of kind Snapshot in order to make a SnapshotPackage!"
251 );
252 };
253 let Some(snapshot_info) = accounts_package.snapshot_info else {
254 panic!(
255 "The AccountsPackage must have snapshot info in order to make a SnapshotPackage!"
256 );
257 };
258
259 let accounts_hash = match accounts_hash_kind {
260 AccountsHashKind::Full(accounts_hash) => accounts_hash,
261 AccountsHashKind::Incremental(_) => {
262 assert!(bank_incremental_snapshot_persistence.is_some());
268 AccountsHash(Hash::default())
269 }
270 };
271
272 Self {
273 snapshot_kind: kind,
274 slot: accounts_package.slot,
275 block_height: accounts_package.block_height,
276 hash: SnapshotHash::new(
277 &accounts_hash_kind,
278 snapshot_info.epoch_accounts_hash.as_ref(),
279 ),
280 snapshot_storages: accounts_package.snapshot_storages,
281 status_cache_slot_deltas: snapshot_info.status_cache_slot_deltas,
282 bank_fields_to_serialize: snapshot_info.bank_fields_to_serialize,
283 accounts_delta_hash: snapshot_info.accounts_delta_hash,
284 bank_hash_stats: snapshot_info.bank_hash_stats,
285 accounts_hash,
286 epoch_accounts_hash: snapshot_info.epoch_accounts_hash,
287 bank_incremental_snapshot_persistence,
288 write_version: snapshot_info.write_version,
289 enqueued: Instant::now(),
290 }
291 }
292}
293
294#[cfg(feature = "dev-context-only-utils")]
295impl SnapshotPackage {
296 pub fn default_for_tests() -> Self {
299 Self {
300 snapshot_kind: SnapshotKind::FullSnapshot,
301 slot: Slot::default(),
302 block_height: Slot::default(),
303 hash: SnapshotHash(Hash::default()),
304 snapshot_storages: Vec::default(),
305 status_cache_slot_deltas: Vec::default(),
306 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
307 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
308 bank_hash_stats: BankHashStats::default(),
309 accounts_hash: AccountsHash(Hash::default()),
310 epoch_accounts_hash: None,
311 bank_incremental_snapshot_persistence: None,
312 write_version: StoredMetaWriteVersion::default(),
313 enqueued: Instant::now(),
314 }
315 }
316}
317
318impl std::fmt::Debug for SnapshotPackage {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 f.debug_struct("SnapshotPackage")
321 .field("kind", &self.snapshot_kind)
322 .field("slot", &self.slot)
323 .field("block_height", &self.block_height)
324 .finish_non_exhaustive()
325 }
326}
327
328#[derive(Clone, Copy, Debug, Eq, PartialEq)]
331pub enum SnapshotKind {
332 FullSnapshot,
333 IncrementalSnapshot(Slot),
334}
335
336impl SnapshotKind {
337 pub fn is_full_snapshot(&self) -> bool {
338 matches!(self, SnapshotKind::FullSnapshot)
339 }
340 pub fn is_incremental_snapshot(&self) -> bool {
341 matches!(self, SnapshotKind::IncrementalSnapshot(_))
342 }
343}