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