Skip to main content

agave_snapshots/
error.rs

1use {
2    crate::{hardened_unpack::UnpackError, snapshot_hash::SnapshotHash},
3    agave_fs::FileInfo,
4    crossbeam_channel::SendError,
5    semver::Version,
6    solana_accounts_db::{accounts_db::AccountsFileId, accounts_file::AccountsFileError},
7    solana_clock::{Epoch, Slot},
8    std::{io, ops::RangeInclusive, path::PathBuf, process::ExitStatus},
9    thiserror::Error,
10};
11
12#[derive(Error, Debug)]
13#[allow(clippy::large_enum_variant)]
14pub enum SnapshotError {
15    #[error("I/O error: {0}")]
16    Io(#[from] io::Error),
17
18    #[error("AccountsFile error: {0}")]
19    AccountsFileError(#[from] AccountsFileError),
20
21    #[error("serialization error: {0}")]
22    Serialize(#[from] bincode::Error),
23
24    #[error("deserialization error: {0}")]
25    DeserializeWincode(#[from] wincode::ReadError),
26
27    #[error("serialization error: {0}")]
28    SerializeWincode(#[from] wincode::WriteError),
29
30    #[error("crossbeam send error: {0}")]
31    CrossbeamSend(#[from] crossbeam_channel::SendError<PathBuf>),
32
33    #[error("archive generation failure {0}")]
34    ArchiveGenerationFailure(ExitStatus),
35
36    #[error("Unpack error: {0}")]
37    UnpackError(#[from] UnpackError),
38
39    #[error("source({1}) - I/O error: {0}")]
40    IoWithSource(io::Error, &'static str),
41
42    #[error("could not get file name from path '{0}'")]
43    PathToFileNameError(PathBuf),
44
45    #[error("could not get str from file name '{0}'")]
46    FileNameToStrError(PathBuf),
47
48    #[error("could not parse snapshot archive's file name '{0}'")]
49    ParseSnapshotArchiveFileNameError(String),
50
51    #[error(
52        "snapshots are incompatible: full snapshot slot ({0}) and incremental snapshot base slot \
53         ({1}) do not match"
54    )]
55    MismatchedBaseSlot(Slot, Slot),
56
57    #[error("no snapshot archives to load from '{0}'")]
58    NoSnapshotArchives(PathBuf),
59
60    #[error("snapshot slot mismatch: deserialized bank: {0}, snapshot archive: {1}")]
61    MismatchedSlot(Slot, Slot),
62
63    #[error("snapshot hash mismatch: deserialized bank: {0:?}, snapshot archive: {1:?}")]
64    MismatchedHash(SnapshotHash, SnapshotHash),
65
66    #[error(
67        "snapshot accounts file id mismatch: deserialized obsolete accounts file id: {0}, \
68         snapshot archive: {1}"
69    )]
70    MismatchedAccountsFileId(AccountsFileId, AccountsFileId),
71
72    #[error("snapshot slot deltas are invalid: {0}")]
73    VerifySlotDeltas(#[from] VerifySlotDeltasError),
74
75    #[error("snapshot epoch stakes are invalid: {0}")]
76    VerifyEpochStakes(#[from] VerifyEpochStakesError),
77
78    #[error("bank_snapshot_info new_from_dir failed: {0}")]
79    NewFromDir(#[from] SnapshotNewFromDirError),
80
81    #[error("invalid snapshot dir path '{0}'")]
82    InvalidSnapshotDirPath(PathBuf),
83
84    #[error("invalid AppendVec path '{0}'")]
85    InvalidAppendVecPath(PathBuf),
86
87    #[error("invalid account path '{0}'")]
88    InvalidAccountPath(PathBuf),
89
90    #[error("no valid snapshot dir found under '{0}'")]
91    NoSnapshotSlotDir(PathBuf),
92
93    #[error("snapshot dir account paths mismatching")]
94    AccountPathsMismatch,
95
96    #[error("failed to add bank snapshot for slot {1}: {0}")]
97    AddBankSnapshot(#[source] AddBankSnapshotError, Slot),
98
99    #[error("failed to archive snapshot package: {0}")]
100    ArchiveSnapshotPackage(#[from] ArchiveSnapshotPackageError),
101
102    #[error("failed to rebuild snapshot storages: {0}")]
103    RebuildStorages(String),
104
105    #[error("capitalization mismatch: expected: {0}, calculated: {1}")]
106    MismatchedCapitalization(u64, u64),
107}
108
109impl From<SendError<FileInfo>> for SnapshotError {
110    fn from(err: SendError<FileInfo>) -> Self {
111        Self::CrossbeamSend(SendError(err.into_inner().path))
112    }
113}
114
115#[derive(Error, Debug)]
116pub enum SnapshotFastbootError {
117    #[error("incompatible fastboot version '{0}'")]
118    IncompatibleVersion(Version),
119}
120
121#[derive(Error, Debug)]
122pub enum SnapshotNewFromDirError {
123    #[error("invalid bank snapshot directory '{0}'")]
124    InvalidBankSnapshotDir(PathBuf),
125
126    #[error("missing status cache file '{0}'")]
127    MissingStatusCacheFile(PathBuf),
128
129    #[error("missing version file '{0}'")]
130    MissingVersionFile(PathBuf),
131
132    #[error("invalid snapshot version '{0}'")]
133    InvalidVersion(String),
134
135    #[error("invalid version string for fastboot '{0}'")]
136    InvalidFastbootVersion(String),
137
138    #[error("snapshot directory incomplete '{1}': {0}")]
139    IncompleteDir(#[source] io::Error, PathBuf),
140
141    #[error("missing snapshot file '{0}'")]
142    MissingSnapshotFile(PathBuf),
143}
144
145/// Errors that can happen in `verify_slot_deltas()`
146#[derive(Error, Debug, PartialEq, Eq)]
147pub enum VerifySlotDeltasError {
148    #[error("too many entries: {0} (max: {1})")]
149    TooManyEntries(usize, usize),
150
151    #[error("slot {0} is not a root")]
152    SlotIsNotRoot(Slot),
153
154    #[error("slot {0} is greater than bank slot {1}")]
155    SlotGreaterThanMaxRoot(Slot, Slot),
156
157    #[error("slot {0} has multiple entries")]
158    SlotHasMultipleEntries(Slot),
159
160    #[error("slot {0} was not found in slot history")]
161    SlotNotFoundInHistory(Slot),
162
163    #[error("slot {0} was in history but missing from slot deltas")]
164    SlotNotFoundInDeltas(Slot),
165
166    #[error("snapshot slot history is invalid: {0}")]
167    VerifySlotHistory(#[from] VerifySlotHistoryError),
168}
169
170/// Errors that can happen in `verify_slot_history()`
171#[derive(Error, Debug, PartialEq, Eq)]
172pub enum VerifySlotHistoryError {
173    #[error("newest slot does not match snapshot")]
174    InvalidNewestSlot,
175
176    #[error("invalid number of entries")]
177    InvalidNumEntries,
178}
179
180/// Errors that can happen in `verify_epoch_stakes()`
181#[derive(Error, Debug, PartialEq, Eq)]
182pub enum VerifyEpochStakesError {
183    #[error("epoch {0} is greater than the max {1}")]
184    EpochGreaterThanMax(Epoch, Epoch),
185
186    #[error("stakes not found for epoch {0} (required epochs: {1:?})")]
187    StakesNotFound(Epoch, RangeInclusive<Epoch>),
188}
189
190/// Errors that can happen in `add_bank_snapshot()`
191#[derive(Error, Debug)]
192pub enum AddBankSnapshotError {
193    #[error("bank snapshot dir already exists '{0}'")]
194    SnapshotDirAlreadyExists(PathBuf),
195
196    #[error("failed to create snapshot dir '{1}': {0}")]
197    CreateSnapshotDir(#[source] io::Error, PathBuf),
198
199    #[error("failed to flush storage '{1}': {0}")]
200    FlushStorage(#[source] AccountsFileError, PathBuf),
201
202    #[error("failed to serialize bank: {0}")]
203    SerializeBank(#[source] Box<SnapshotError>),
204
205    #[error("failed to serialize status cache: {0}")]
206    SerializeStatusCache(#[source] Box<SnapshotError>),
207
208    #[error("failed to serialize obsolete accounts: {0}")]
209    SerializeObsoleteAccounts(#[source] Box<SnapshotError>),
210
211    #[error("failed to write storages list: {0}")]
212    WriteStoragesList(#[source] Box<SnapshotError>),
213
214    #[error("failed to write snapshot version file '{1}': {0}")]
215    WriteSnapshotVersionFile(#[source] io::Error, PathBuf),
216
217    #[error("failed to mark snapshot as 'loadable': {0}")]
218    MarkSnapshotLoadable(#[source] io::Error),
219}
220
221/// Errors that can happen in `archive_snapshot_package()`
222#[derive(Error, Debug)]
223pub enum ArchiveSnapshotPackageError {
224    #[error("failed to create archive path '{1}': {0}")]
225    CreateArchiveDir(#[source] io::Error, PathBuf),
226
227    #[error("failed to create staging dir inside '{1}': {0}")]
228    CreateStagingDir(#[source] io::Error, PathBuf),
229
230    #[error("failed to create snapshot staging dir '{1}': {0}")]
231    CreateSnapshotStagingDir(#[source] io::Error, PathBuf),
232
233    #[error("failed to canonicalize snapshot source dir '{1}': {0}")]
234    CanonicalizeSnapshotSourceDir(#[source] io::Error, PathBuf),
235
236    #[error("failed to symlink snapshot from '{1}' to '{2}': {0}")]
237    SymlinkSnapshot(#[source] io::Error, PathBuf, PathBuf),
238
239    #[error("failed to symlink status cache from '{1}' to '{2}': {0}")]
240    SymlinkStatusCache(#[source] io::Error, PathBuf, PathBuf),
241
242    #[error("failed to symlink version file from '{1}' to '{2}': {0}")]
243    SymlinkVersionFile(#[source] io::Error, PathBuf, PathBuf),
244
245    #[error("failed to create archive file '{1}': {0}")]
246    CreateArchiveFile(#[source] io::Error, PathBuf),
247
248    #[error("failed to archive version file: {0}")]
249    ArchiveVersionFile(#[source] io::Error),
250
251    #[error("failed to archive snapshots dir: {0}")]
252    ArchiveSnapshotsDir(#[source] io::Error),
253
254    #[error("failed to archive account storage file '{1}': {0}")]
255    ArchiveAccountStorageFile(#[source] io::Error, PathBuf),
256
257    #[error("failed to archive snapshot: {0}")]
258    FinishArchive(#[source] io::Error),
259
260    #[error("failed to create encoder: {0}")]
261    CreateEncoder(#[source] io::Error),
262
263    #[error("failed to encode archive: {0}")]
264    FinishEncoder(#[source] io::Error),
265
266    #[error("failed to query archive metadata '{1}': {0}")]
267    QueryArchiveMetadata(#[source] io::Error, PathBuf),
268
269    #[error("failed to move archive from '{1}' to '{2}': {0}")]
270    MoveArchive(#[source] io::Error, PathBuf, PathBuf),
271
272    #[error("failed to create account storage reader '{1}': {0}")]
273    AccountStorageReaderError(#[source] io::Error, PathBuf),
274
275    #[error("failed to initialize file buffered reader: {0}")]
276    StorageFileBufReaderError(#[source] io::Error),
277}