1use std::io;
2
3use deadpool_sqlite::{InteractError, PoolError};
4use miden_objects::{
5 account::AccountId,
6 block::{BlockHeader, BlockNumber},
7 crypto::{
8 hash::rpo::RpoDigest,
9 merkle::{MerkleError, MmrError},
10 utils::DeserializationError,
11 },
12 note::Nullifier,
13 transaction::OutputNote,
14 AccountDeltaError, AccountError, BlockError, NoteError,
15};
16use rusqlite::types::FromSqlError;
17use thiserror::Error;
18use tokio::sync::oneshot::error::RecvError;
19use tonic::Status;
20
21#[derive(Debug, Error)]
25pub enum NullifierTreeError {
26 #[error("failed to create nullifier tree")]
27 CreationFailed(#[source] MerkleError),
28
29 #[error("failed to mutate nullifier tree")]
30 MutationFailed(#[source] MerkleError),
31}
32
33#[derive(Debug, Error)]
37pub enum DatabaseError {
38 #[error("account error")]
41 AccountError(#[from] AccountError),
42 #[error("account delta error")]
43 AccountDeltaError(#[from] AccountDeltaError),
44 #[error("block error")]
45 BlockError(#[from] BlockError),
46 #[error("closed channel")]
47 ClosedChannel(#[from] RecvError),
48 #[error("deserialization failed")]
49 DeserializationError(#[from] DeserializationError),
50 #[error("hex parsing error")]
51 FromHexError(#[from] hex::FromHexError),
52 #[error("SQLite deserialization error")]
53 FromSqlError(#[from] FromSqlError),
54 #[error("I/O error")]
55 IoError(#[from] io::Error),
56 #[error("migration failed")]
57 MigrationError(#[from] rusqlite_migration::Error),
58 #[error("missing database connection")]
59 MissingDbConnection(#[from] PoolError),
60 #[error("note error")]
61 NoteError(#[from] NoteError),
62 #[error("SQLite error")]
63 SqliteError(#[from] rusqlite::Error),
64
65 #[error("account hash mismatch (expected {expected}, but calculated is {calculated})")]
68 AccountHashesMismatch {
69 expected: RpoDigest,
70 calculated: RpoDigest,
71 },
72 #[error("account {0} not found")]
73 AccountNotFoundInDb(AccountId),
74 #[error("accounts {0:?} not found")]
75 AccountsNotFoundInDb(Vec<AccountId>),
76 #[error("account {0} is not on the chain")]
77 AccountNotPublic(AccountId),
78 #[error("block {0} not found")]
79 BlockNotFoundInDb(BlockNumber),
80 #[error("data corrupted: {0}")]
81 DataCorrupted(String),
82 #[error("SQLite pool interaction failed: {0}")]
83 InteractError(String),
84 #[error("invalid Felt: {0}")]
85 InvalidFelt(String),
86 #[error(
87 "unsupported database version. There is no migration chain from/to this version. \
88 Remove all database files and try again."
89 )]
90 UnsupportedDatabaseVersion,
91}
92
93impl From<DatabaseError> for Status {
94 fn from(err: DatabaseError) -> Self {
95 match err {
96 DatabaseError::AccountNotFoundInDb(_)
97 | DatabaseError::AccountsNotFoundInDb(_)
98 | DatabaseError::AccountNotPublic(_)
99 | DatabaseError::BlockNotFoundInDb(_) => Status::not_found(err.to_string()),
100
101 _ => Status::internal(err.to_string()),
102 }
103 }
104}
105
106#[derive(Error, Debug)]
110pub enum StateInitializationError {
111 #[error("database error")]
112 DatabaseError(#[from] DatabaseError),
113 #[error("failed to create nullifier tree")]
114 FailedToCreateNullifierTree(#[from] NullifierTreeError),
115 #[error("failed to create accounts tree")]
116 FailedToCreateAccountsTree(#[from] MerkleError),
117}
118
119#[derive(Debug, Error)]
120pub enum DatabaseSetupError {
121 #[error("I/O error")]
122 IoError(#[from] io::Error),
123 #[error("database error")]
124 DatabaseError(#[from] DatabaseError),
125 #[error("genesis block error")]
126 GenesisBlockError(#[from] GenesisError),
127 #[error("pool build error")]
128 PoolBuildError(#[from] deadpool_sqlite::BuildError),
129 #[error("SQLite migration error")]
130 SqliteMigrationError(#[from] rusqlite_migration::Error),
131}
132
133#[derive(Debug, Error)]
134pub enum GenesisError {
135 #[error("database error")]
138 DatabaseError(#[from] DatabaseError),
139 #[error("block error")]
140 BlockError(#[from] BlockError),
141 #[error("merkle error")]
142 MerkleError(#[from] MerkleError),
143 #[error("failed to deserialize genesis file")]
144 GenesisFileDeserializationError(#[from] DeserializationError),
145 #[error("retrieving genesis block header failed")]
146 SelectBlockHeaderByBlockNumError(#[from] Box<DatabaseError>),
147
148 #[error("apply block failed")]
151 ApplyBlockFailed(#[source] InteractError),
152 #[error("failed to read genesis file \"{genesis_filepath}\"")]
153 FailedToReadGenesisFile {
154 genesis_filepath: String,
155 source: io::Error,
156 },
157 #[error("block header in store doesn't match block header in genesis file. Expected {expected_genesis_header:?}, but store contained {block_header_in_store:?}")]
158 GenesisBlockHeaderMismatch {
159 expected_genesis_header: Box<BlockHeader>,
160 block_header_in_store: Box<BlockHeader>,
161 },
162}
163
164#[derive(Error, Debug)]
167pub enum InvalidBlockError {
168 #[error("duplicated nullifiers {0:?}")]
169 DuplicatedNullifiers(Vec<Nullifier>),
170 #[error("invalid output note type: {0:?}")]
171 InvalidOutputNoteType(Box<OutputNote>),
172 #[error("invalid block tx hash: expected {expected}, but got {actual}")]
173 InvalidBlockTxHash { expected: RpoDigest, actual: RpoDigest },
174 #[error("received invalid account tree root")]
175 NewBlockInvalidAccountRoot,
176 #[error("new block number must be 1 greater than the current block number")]
177 NewBlockInvalidBlockNum,
178 #[error("new block chain root is not consistent with chain MMR")]
179 NewBlockInvalidChainRoot,
180 #[error("received invalid note root")]
181 NewBlockInvalidNoteRoot,
182 #[error("received invalid nullifier root")]
183 NewBlockInvalidNullifierRoot,
184 #[error("new block `prev_hash` must match the chain's tip")]
185 NewBlockInvalidPrevHash,
186}
187
188#[derive(Error, Debug)]
189pub enum ApplyBlockError {
190 #[error("database error")]
193 DatabaseError(#[from] DatabaseError),
194 #[error("I/O error")]
195 IoError(#[from] io::Error),
196 #[error("task join error")]
197 TokioJoinError(#[from] tokio::task::JoinError),
198 #[error("invalid block error")]
199 InvalidBlockError(#[from] InvalidBlockError),
200
201 #[error("block applying was cancelled because of closed channel on database side")]
204 ClosedChannel(#[from] RecvError),
205 #[error("concurrent write detected")]
206 ConcurrentWrite,
207 #[error("database doesn't have any block header data")]
208 DbBlockHeaderEmpty,
209 #[error("database update failed: {0}")]
210 DbUpdateTaskFailed(String),
211}
212
213impl From<ApplyBlockError> for Status {
214 fn from(err: ApplyBlockError) -> Self {
215 match err {
216 ApplyBlockError::InvalidBlockError(_) => Status::invalid_argument(err.to_string()),
217
218 _ => Status::internal(err.to_string()),
219 }
220 }
221}
222
223#[derive(Error, Debug)]
224pub enum GetBlockHeaderError {
225 #[error("database error")]
226 DatabaseError(#[from] DatabaseError),
227 #[error("error retrieving the merkle proof for the block")]
228 MmrError(#[from] MmrError),
229}
230
231#[derive(Error, Debug)]
232pub enum GetBlockInputsError {
233 #[error("account error")]
234 AccountError(#[from] AccountError),
235 #[error("database error")]
236 DatabaseError(#[from] DatabaseError),
237 #[error("database doesn't have any block header data")]
238 DbBlockHeaderEmpty,
239 #[error("failed to get MMR peaks for forest ({forest}): {error}")]
240 FailedToGetMmrPeaksForForest { forest: usize, error: MmrError },
241 #[error("chain MMR forest expected to be 1 less than latest header's block num. Chain MMR forest: {forest}, block num: {block_num}")]
242 IncorrectChainMmrForestNumber { forest: usize, block_num: BlockNumber },
243 #[error("note inclusion proof MMR error")]
244 NoteInclusionMmr(#[from] MmrError),
245}
246
247impl From<GetNoteInclusionProofError> for GetBlockInputsError {
248 fn from(value: GetNoteInclusionProofError) -> Self {
249 match value {
250 GetNoteInclusionProofError::DatabaseError(db_err) => db_err.into(),
251 GetNoteInclusionProofError::MmrError(mmr_err) => Self::NoteInclusionMmr(mmr_err),
252 }
253 }
254}
255
256#[derive(Error, Debug)]
257pub enum StateSyncError {
258 #[error("database error")]
259 DatabaseError(#[from] DatabaseError),
260 #[error("block headers table is empty")]
261 EmptyBlockHeadersTable,
262 #[error("failed to build MMR delta")]
263 FailedToBuildMmrDelta(#[from] MmrError),
264}
265
266#[derive(Error, Debug)]
267pub enum NoteSyncError {
268 #[error("database error")]
269 DatabaseError(#[from] DatabaseError),
270 #[error("block headers table is empty")]
271 EmptyBlockHeadersTable,
272 #[error("error retrieving the merkle proof for the block")]
273 MmrError(#[from] MmrError),
274}
275
276#[derive(Error, Debug)]
277pub enum GetNoteInclusionProofError {
278 #[error("database error")]
279 DatabaseError(#[from] DatabaseError),
280 #[error("Mmr error")]
281 MmrError(#[from] MmrError),
282}