1use {
2 crate::{
3 bank::{Bank, BankFieldsToSerialize, BankHashStats, 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::AccountStorageEntry,
12 accounts_hash::{
13 AccountsDeltaHash, AccountsHash, AccountsHashKind, MerkleOrLatticeAccountsHash,
14 },
15 epoch_accounts_hash::EpochAccountsHash,
16 },
17 solana_sdk::{
18 clock::Slot, feature_set, hash::Hash, rent_collector::RentCollector,
19 sysvar::epoch_schedule::EpochSchedule,
20 },
21 std::{
22 sync::{atomic::Ordering, Arc},
23 time::Instant,
24 },
25};
26
27mod compare;
28pub use compare::*;
29
30pub struct AccountsPackage {
32 pub package_kind: AccountsPackageKind,
33 pub slot: Slot,
34 pub block_height: Slot,
35 pub snapshot_storages: Vec<Arc<AccountStorageEntry>>,
36 pub expected_capitalization: u64,
37 pub accounts_hash_for_testing: Option<AccountsHash>,
38 pub accounts: Arc<Accounts>,
39 pub epoch_schedule: EpochSchedule,
40 pub rent_collector: RentCollector,
41 pub accounts_hash_algorithm: AccountsHashAlgorithm,
42
43 pub snapshot_info: Option<SupplementalSnapshotInfo>,
45
46 pub enqueued: Instant,
49}
50
51impl AccountsPackage {
52 pub fn new_for_snapshot(
54 package_kind: AccountsPackageKind,
55 bank: &Bank,
56 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
57 status_cache_slot_deltas: Vec<BankSlotDelta>,
58 accounts_hash_for_testing: Option<AccountsHash>,
59 ) -> Self {
60 let slot = bank.slot();
61 if let AccountsPackageKind::Snapshot(snapshot_kind) = package_kind {
62 info!(
63 "Package snapshot for bank {} has {} account storage entries (snapshot kind: {:?})",
64 slot,
65 snapshot_storages.len(),
66 snapshot_kind,
67 );
68 if let SnapshotKind::IncrementalSnapshot(incremental_snapshot_base_slot) = snapshot_kind
69 {
70 assert!(
71 slot > incremental_snapshot_base_slot,
72 "Incremental snapshot base slot must be less than the bank being snapshotted!"
73 );
74 }
75 }
76
77 let snapshot_info = {
78 let accounts_db = &bank.rc.accounts.accounts_db;
79 let write_version = accounts_db.write_version.load(Ordering::Acquire);
80 let accounts_delta_hash = if bank
81 .feature_set
82 .is_active(&feature_set::remove_accounts_delta_hash::id())
83 {
84 AccountsDeltaHash(Hash::default())
85 } else {
86 accounts_db.get_accounts_delta_hash(slot).unwrap()
90 };
91 let bank_hash_stats = bank.get_bank_hash_stats();
92 let bank_fields_to_serialize = bank.get_fields_to_serialize();
93 SupplementalSnapshotInfo {
94 status_cache_slot_deltas,
95 bank_fields_to_serialize,
96 bank_hash_stats,
97 accounts_delta_hash,
98 epoch_accounts_hash: bank.get_epoch_accounts_hash_to_serialize(),
99 write_version,
100 }
101 };
102
103 let accounts_hash_algorithm = if bank.is_snapshots_lt_hash_enabled() {
104 AccountsHashAlgorithm::Lattice
105 } else {
106 AccountsHashAlgorithm::Merkle
107 };
108 Self::_new(
109 package_kind,
110 bank,
111 snapshot_storages,
112 accounts_hash_for_testing,
113 accounts_hash_algorithm,
114 Some(snapshot_info),
115 )
116 }
117
118 #[must_use]
120 pub fn new_for_accounts_hash_verifier(
121 package_kind: AccountsPackageKind,
122 bank: &Bank,
123 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
124 accounts_hash_for_testing: Option<AccountsHash>,
125 ) -> Self {
126 assert_eq!(package_kind, AccountsPackageKind::AccountsHashVerifier);
127 Self::_new(
128 package_kind,
129 bank,
130 snapshot_storages,
131 accounts_hash_for_testing,
132 AccountsHashAlgorithm::Merkle,
133 None,
134 )
135 }
136
137 #[must_use]
139 pub fn new_for_epoch_accounts_hash(
140 package_kind: AccountsPackageKind,
141 bank: &Bank,
142 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
143 accounts_hash_for_testing: Option<AccountsHash>,
144 ) -> Self {
145 assert_eq!(package_kind, AccountsPackageKind::EpochAccountsHash);
146 Self::_new(
147 package_kind,
148 bank,
149 snapshot_storages,
150 accounts_hash_for_testing,
151 AccountsHashAlgorithm::Merkle,
152 None,
153 )
154 }
155
156 fn _new(
157 package_kind: AccountsPackageKind,
158 bank: &Bank,
159 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
160 accounts_hash_for_testing: Option<AccountsHash>,
161 accounts_hash_algorithm: AccountsHashAlgorithm,
162 snapshot_info: Option<SupplementalSnapshotInfo>,
163 ) -> Self {
164 Self {
165 package_kind,
166 slot: bank.slot(),
167 block_height: bank.block_height(),
168 snapshot_storages,
169 expected_capitalization: bank.capitalization(),
170 accounts_hash_for_testing,
171 accounts: bank.accounts(),
172 epoch_schedule: bank.epoch_schedule().clone(),
173 rent_collector: bank.rent_collector().clone(),
174 accounts_hash_algorithm,
175 snapshot_info,
176 enqueued: Instant::now(),
177 }
178 }
179
180 #[cfg(feature = "dev-context-only-utils")]
183 pub fn default_for_tests() -> Self {
184 use solana_accounts_db::accounts_db::AccountsDb;
185 let accounts_db = AccountsDb::default_for_tests();
186 let accounts = Accounts::new(Arc::new(accounts_db));
187 Self {
188 package_kind: AccountsPackageKind::AccountsHashVerifier,
189 slot: Slot::default(),
190 block_height: Slot::default(),
191 snapshot_storages: Vec::default(),
192 expected_capitalization: u64::default(),
193 accounts_hash_for_testing: Option::default(),
194 accounts: Arc::new(accounts),
195 epoch_schedule: EpochSchedule::default(),
196 rent_collector: RentCollector::default(),
197 accounts_hash_algorithm: AccountsHashAlgorithm::Merkle,
198 snapshot_info: Some(SupplementalSnapshotInfo {
199 status_cache_slot_deltas: Vec::default(),
200 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
201 bank_hash_stats: BankHashStats::default(),
202 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
203 epoch_accounts_hash: Option::default(),
204 write_version: StoredMetaWriteVersion::default(),
205 }),
206 enqueued: Instant::now(),
207 }
208 }
209}
210
211impl std::fmt::Debug for AccountsPackage {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 f.debug_struct("AccountsPackage")
214 .field("kind", &self.package_kind)
215 .field("slot", &self.slot)
216 .field("block_height", &self.block_height)
217 .field("accounts_hash_algorithm", &self.accounts_hash_algorithm)
218 .finish_non_exhaustive()
219 }
220}
221
222pub struct SupplementalSnapshotInfo {
224 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
225 pub bank_fields_to_serialize: BankFieldsToSerialize,
226 pub bank_hash_stats: BankHashStats,
227 pub accounts_delta_hash: AccountsDeltaHash,
228 pub epoch_accounts_hash: Option<EpochAccountsHash>,
229 pub write_version: StoredMetaWriteVersion,
230}
231
232#[derive(Debug, Copy, Clone, Eq, PartialEq)]
236pub enum AccountsPackageKind {
237 AccountsHashVerifier,
238 Snapshot(SnapshotKind),
239 EpochAccountsHash,
240}
241
242pub struct SnapshotPackage {
244 pub snapshot_kind: SnapshotKind,
245 pub slot: Slot,
246 pub block_height: Slot,
247 pub hash: SnapshotHash,
248 pub snapshot_storages: Vec<Arc<AccountStorageEntry>>,
249 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
250 pub bank_fields_to_serialize: BankFieldsToSerialize,
251 pub bank_hash_stats: BankHashStats,
252 pub accounts_delta_hash: AccountsDeltaHash,
253 pub accounts_hash: AccountsHash,
254 pub epoch_accounts_hash: Option<EpochAccountsHash>,
255 pub write_version: StoredMetaWriteVersion,
256 pub bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
257
258 pub enqueued: Instant,
261}
262
263impl SnapshotPackage {
264 pub fn new(
265 accounts_package: AccountsPackage,
266 merkle_or_lattice_accounts_hash: MerkleOrLatticeAccountsHash,
267 bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
268 ) -> Self {
269 let AccountsPackageKind::Snapshot(kind) = accounts_package.package_kind else {
270 panic!(
271 "The AccountsPackage must be of kind Snapshot in order to make a SnapshotPackage!"
272 );
273 };
274 let Some(snapshot_info) = accounts_package.snapshot_info else {
275 panic!(
276 "The AccountsPackage must have snapshot info in order to make a SnapshotPackage!"
277 );
278 };
279
280 let accounts_hash = match merkle_or_lattice_accounts_hash {
281 MerkleOrLatticeAccountsHash::Merkle(accounts_hash_kind) => {
282 match accounts_hash_kind {
283 AccountsHashKind::Full(accounts_hash) => accounts_hash,
284 AccountsHashKind::Incremental(_) => {
285 assert!(bank_incremental_snapshot_persistence.is_some());
291 AccountsHash(Hash::default())
292 }
293 }
294 }
295 MerkleOrLatticeAccountsHash::Lattice => {
296 AccountsHash(Hash::default())
299 }
300 };
301
302 Self {
303 snapshot_kind: kind,
304 slot: accounts_package.slot,
305 block_height: accounts_package.block_height,
306 hash: SnapshotHash::new(
307 &merkle_or_lattice_accounts_hash,
308 snapshot_info.epoch_accounts_hash.as_ref(),
309 snapshot_info
310 .bank_fields_to_serialize
311 .accounts_lt_hash
312 .as_ref()
313 .map(|accounts_lt_hash| accounts_lt_hash.0.checksum()),
314 ),
315 snapshot_storages: accounts_package.snapshot_storages,
316 status_cache_slot_deltas: snapshot_info.status_cache_slot_deltas,
317 bank_fields_to_serialize: snapshot_info.bank_fields_to_serialize,
318 accounts_delta_hash: snapshot_info.accounts_delta_hash,
319 bank_hash_stats: snapshot_info.bank_hash_stats,
320 accounts_hash,
321 epoch_accounts_hash: snapshot_info.epoch_accounts_hash,
322 bank_incremental_snapshot_persistence,
323 write_version: snapshot_info.write_version,
324 enqueued: Instant::now(),
325 }
326 }
327}
328
329#[cfg(feature = "dev-context-only-utils")]
330impl SnapshotPackage {
331 pub fn default_for_tests() -> Self {
334 Self {
335 snapshot_kind: SnapshotKind::FullSnapshot,
336 slot: Slot::default(),
337 block_height: Slot::default(),
338 hash: SnapshotHash(Hash::default()),
339 snapshot_storages: Vec::default(),
340 status_cache_slot_deltas: Vec::default(),
341 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
342 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
343 bank_hash_stats: BankHashStats::default(),
344 accounts_hash: AccountsHash(Hash::default()),
345 epoch_accounts_hash: None,
346 bank_incremental_snapshot_persistence: None,
347 write_version: StoredMetaWriteVersion::default(),
348 enqueued: Instant::now(),
349 }
350 }
351}
352
353impl std::fmt::Debug for SnapshotPackage {
354 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355 f.debug_struct("SnapshotPackage")
356 .field("kind", &self.snapshot_kind)
357 .field("slot", &self.slot)
358 .field("block_height", &self.block_height)
359 .finish_non_exhaustive()
360 }
361}
362
363#[derive(Clone, Copy, Debug, Eq, PartialEq)]
366pub enum SnapshotKind {
367 FullSnapshot,
368 IncrementalSnapshot(Slot),
369}
370
371impl SnapshotKind {
372 pub fn is_full_snapshot(&self) -> bool {
373 matches!(self, SnapshotKind::FullSnapshot)
374 }
375 pub fn is_incremental_snapshot(&self) -> bool {
376 matches!(self, SnapshotKind::IncrementalSnapshot(_))
377 }
378}
379
380#[derive(Debug, Copy, Clone, Eq, PartialEq)]
382pub enum AccountsHashAlgorithm {
383 Merkle,
385 Lattice,
387}