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