miden_node_store/
errors.rs

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// INTERNAL ERRORS
23// =================================================================================================
24
25#[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// DATABASE ERRORS
35// =================================================================================================
36
37#[derive(Debug, Error)]
38pub enum DatabaseError {
39    // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES
40    // ---------------------------------------------------------------------------------------------
41    #[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    // OTHER ERRORS
65    // ---------------------------------------------------------------------------------------------
66    #[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// INITIALIZATION ERRORS
103// =================================================================================================
104
105#[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    // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES
132    // ---------------------------------------------------------------------------------------------
133    #[error("database error")]
134    DatabaseError(#[from] DatabaseError),
135    // TODO: Check if needed.
136    #[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    // OTHER ERRORS
146    // ---------------------------------------------------------------------------------------------
147    #[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// ENDPOINT ERRORS
164// =================================================================================================
165#[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    // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES
190    // ---------------------------------------------------------------------------------------------
191    #[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    // OTHER ERRORS
201    // ---------------------------------------------------------------------------------------------
202    #[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}