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 accounts::Accounts,
11 accounts_db::AccountStorageEntry,
12 accounts_hash::{
13 AccountsDeltaHash, AccountsHash, AccountsHashKind, MerkleOrLatticeAccountsHash,
14 },
15 epoch_accounts_hash::EpochAccountsHash,
16 },
17 solana_clock::Slot,
18 solana_epoch_schedule::EpochSchedule,
19 solana_hash::Hash,
20 solana_rent_collector::RentCollector,
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 must_include_epoch_accounts_hash: bank
99 .must_include_epoch_accounts_hash_in_snapshot(),
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_epoch_accounts_hash(
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::EpochAccountsHash);
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 fn _new(
139 package_kind: AccountsPackageKind,
140 bank: &Bank,
141 snapshot_storages: Vec<Arc<AccountStorageEntry>>,
142 accounts_hash_for_testing: Option<AccountsHash>,
143 accounts_hash_algorithm: AccountsHashAlgorithm,
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 accounts_hash_algorithm,
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::EpochAccountsHash,
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 accounts_hash_algorithm: AccountsHashAlgorithm::Merkle,
180 snapshot_info: Some(SupplementalSnapshotInfo {
181 status_cache_slot_deltas: Vec::default(),
182 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
183 bank_hash_stats: BankHashStats::default(),
184 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
185 must_include_epoch_accounts_hash: false,
186 write_version: u64::default(),
187 }),
188 enqueued: Instant::now(),
189 }
190 }
191}
192
193impl std::fmt::Debug for AccountsPackage {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 f.debug_struct("AccountsPackage")
196 .field("kind", &self.package_kind)
197 .field("slot", &self.slot)
198 .field("block_height", &self.block_height)
199 .field("accounts_hash_algorithm", &self.accounts_hash_algorithm)
200 .finish_non_exhaustive()
201 }
202}
203
204pub struct SupplementalSnapshotInfo {
206 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
207 pub bank_fields_to_serialize: BankFieldsToSerialize,
208 pub bank_hash_stats: BankHashStats,
209 pub accounts_delta_hash: AccountsDeltaHash,
210 pub must_include_epoch_accounts_hash: bool,
211 pub write_version: u64,
212}
213
214#[derive(Debug, Copy, Clone, Eq, PartialEq)]
218pub enum AccountsPackageKind {
219 Snapshot(SnapshotKind),
220 EpochAccountsHash,
221}
222
223pub struct SnapshotPackage {
225 pub snapshot_kind: SnapshotKind,
226 pub slot: Slot,
227 pub block_height: Slot,
228 pub hash: SnapshotHash,
229 pub snapshot_storages: Vec<Arc<AccountStorageEntry>>,
230 pub status_cache_slot_deltas: Vec<BankSlotDelta>,
231 pub bank_fields_to_serialize: BankFieldsToSerialize,
232 pub bank_hash_stats: BankHashStats,
233 pub accounts_delta_hash: AccountsDeltaHash,
234 pub accounts_hash: AccountsHash,
235 pub epoch_accounts_hash: Option<EpochAccountsHash>,
236 pub write_version: u64,
237 pub bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
238
239 pub enqueued: Instant,
242}
243
244impl SnapshotPackage {
245 pub fn new(
246 accounts_package: AccountsPackage,
247 merkle_or_lattice_accounts_hash: MerkleOrLatticeAccountsHash,
248 bank_incremental_snapshot_persistence: Option<BankIncrementalSnapshotPersistence>,
249 ) -> Self {
250 let AccountsPackageKind::Snapshot(kind) = accounts_package.package_kind else {
251 panic!(
252 "The AccountsPackage must be of kind Snapshot in order to make a SnapshotPackage!"
253 );
254 };
255 let Some(snapshot_info) = accounts_package.snapshot_info else {
256 panic!(
257 "The AccountsPackage must have snapshot info in order to make a SnapshotPackage!"
258 );
259 };
260
261 let accounts_hash = match merkle_or_lattice_accounts_hash {
262 MerkleOrLatticeAccountsHash::Merkle(accounts_hash_kind) => {
263 match accounts_hash_kind {
264 AccountsHashKind::Full(accounts_hash) => accounts_hash,
265 AccountsHashKind::Incremental(_) => {
266 assert!(bank_incremental_snapshot_persistence.is_some());
272 AccountsHash(Hash::default())
273 }
274 }
275 }
276 MerkleOrLatticeAccountsHash::Lattice => {
277 AccountsHash(Hash::default())
280 }
281 };
282
283 let epoch_accounts_hash = snapshot_info.must_include_epoch_accounts_hash.then(|| {
284 accounts_package
290 .accounts
291 .accounts_db
292 .epoch_accounts_hash_manager
293 .try_get_epoch_accounts_hash()
294 .unwrap()
295 });
296
297 Self {
298 snapshot_kind: kind,
299 slot: accounts_package.slot,
300 block_height: accounts_package.block_height,
301 hash: SnapshotHash::new(
302 &merkle_or_lattice_accounts_hash,
303 epoch_accounts_hash.as_ref(),
304 snapshot_info
305 .bank_fields_to_serialize
306 .accounts_lt_hash
307 .as_ref()
308 .map(|accounts_lt_hash| accounts_lt_hash.0.checksum()),
309 ),
310 snapshot_storages: accounts_package.snapshot_storages,
311 status_cache_slot_deltas: snapshot_info.status_cache_slot_deltas,
312 bank_fields_to_serialize: snapshot_info.bank_fields_to_serialize,
313 accounts_delta_hash: snapshot_info.accounts_delta_hash,
314 bank_hash_stats: snapshot_info.bank_hash_stats,
315 accounts_hash,
316 epoch_accounts_hash,
317 bank_incremental_snapshot_persistence,
318 write_version: snapshot_info.write_version,
319 enqueued: Instant::now(),
320 }
321 }
322}
323
324#[cfg(feature = "dev-context-only-utils")]
325impl SnapshotPackage {
326 pub fn default_for_tests() -> Self {
329 Self {
330 snapshot_kind: SnapshotKind::FullSnapshot,
331 slot: Slot::default(),
332 block_height: Slot::default(),
333 hash: SnapshotHash(Hash::default()),
334 snapshot_storages: Vec::default(),
335 status_cache_slot_deltas: Vec::default(),
336 bank_fields_to_serialize: BankFieldsToSerialize::default_for_tests(),
337 accounts_delta_hash: AccountsDeltaHash(Hash::default()),
338 bank_hash_stats: BankHashStats::default(),
339 accounts_hash: AccountsHash(Hash::default()),
340 epoch_accounts_hash: None,
341 bank_incremental_snapshot_persistence: None,
342 write_version: u64::default(),
343 enqueued: Instant::now(),
344 }
345 }
346}
347
348impl std::fmt::Debug for SnapshotPackage {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 f.debug_struct("SnapshotPackage")
351 .field("kind", &self.snapshot_kind)
352 .field("slot", &self.slot)
353 .field("block_height", &self.block_height)
354 .finish_non_exhaustive()
355 }
356}
357
358#[derive(Clone, Copy, Debug, Eq, PartialEq)]
361pub enum SnapshotKind {
362 FullSnapshot,
363 IncrementalSnapshot(Slot),
364}
365
366impl SnapshotKind {
367 pub fn is_full_snapshot(&self) -> bool {
368 matches!(self, SnapshotKind::FullSnapshot)
369 }
370 pub fn is_incremental_snapshot(&self) -> bool {
371 matches!(self, SnapshotKind::IncrementalSnapshot(_))
372 }
373}
374
375#[derive(Debug, Copy, Clone, Eq, PartialEq)]
377pub enum AccountsHashAlgorithm {
378 Merkle,
380 Lattice,
382}