miden_node_store/
errors.rs

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// INTERNAL ERRORS
22// =================================================================================================
23
24#[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// DATABASE ERRORS
34// =================================================================================================
35
36#[derive(Debug, Error)]
37pub enum DatabaseError {
38    // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES
39    // ---------------------------------------------------------------------------------------------
40    #[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    // OTHER ERRORS
66    // ---------------------------------------------------------------------------------------------
67    #[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// INITIALIZATION ERRORS
107// =================================================================================================
108
109#[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    // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES
136    // ---------------------------------------------------------------------------------------------
137    #[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    // OTHER ERRORS
149    // ---------------------------------------------------------------------------------------------
150    #[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// ENDPOINT ERRORS
165// =================================================================================================
166#[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    // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES
191    // ---------------------------------------------------------------------------------------------
192    #[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    // OTHER ERRORS
202    // ---------------------------------------------------------------------------------------------
203    #[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}