1use alloc::boxed::Box;
2use alloc::string::String;
3use core::error::Error;
4
5use miden_lib::transaction::TransactionAdviceMapMismatch;
6use miden_objects::account::AccountId;
7use miden_objects::assembly::diagnostics::reporting::PrintDiagnostic;
8use miden_objects::block::BlockNumber;
9use miden_objects::crypto::merkle::SmtProofError;
10use miden_objects::note::NoteId;
11use miden_objects::transaction::TransactionSummary;
12use miden_objects::{
13 AccountDeltaError,
14 AccountError,
15 Felt,
16 ProvenTransactionError,
17 TransactionInputError,
18 TransactionOutputError,
19 Word,
20};
21use miden_processor::ExecutionError;
22use miden_verifier::VerificationError;
23use thiserror::Error;
24
25#[derive(Debug, Error)]
29pub enum NoteCheckerError {
30 #[error("transaction preparation failed: {0}")]
31 TransactionPreparationFailed(#[source] TransactionExecutorError),
32 #[error("transaction execution prologue failed: {0}")]
33 PrologueExecutionFailed(#[source] TransactionExecutorError),
34 #[error("transaction execution epilogue failed: {0}")]
35 EpilogueExecutionFailed(#[source] TransactionExecutorError),
36 #[error("transaction note execution failed on note index {failed_note_index}: {error}")]
37 NoteExecutionFailed {
38 failed_note_index: usize,
39 error: TransactionExecutorError,
40 },
41}
42
43#[derive(Debug, Error)]
47pub enum TransactionExecutorError {
48 #[error("the advice map contains conflicting map entries")]
49 ConflictingAdviceMapEntry(#[source] TransactionAdviceMapMismatch),
50 #[error("failed to fetch transaction inputs from the data store")]
51 FetchTransactionInputsFailed(#[source] DataStoreError),
52 #[error("foreign account inputs for ID {0} are not anchored on reference block")]
53 ForeignAccountNotAnchoredInReference(AccountId),
54 #[error(
55 "execution options' cycles must be between {min_cycles} and {max_cycles}, but found {actual}"
56 )]
57 InvalidExecutionOptionsCycles {
58 min_cycles: u32,
59 max_cycles: u32,
60 actual: u32,
61 },
62 #[error("failed to create transaction inputs")]
63 InvalidTransactionInputs(#[source] TransactionInputError),
64 #[error("failed to process account update commitment: {0}")]
65 AccountUpdateCommitment(&'static str),
66 #[error(
67 "account delta commitment computed in transaction kernel ({in_kernel_commitment}) does not match account delta computed via the host ({host_commitment})"
68 )]
69 InconsistentAccountDeltaCommitment {
70 in_kernel_commitment: Word,
71 host_commitment: Word,
72 },
73 #[error("failed to remove the fee asset from the pre-fee account delta")]
74 RemoveFeeAssetFromDelta(#[source] AccountDeltaError),
75 #[error("input account ID {input_id} does not match output account ID {output_id}")]
76 InconsistentAccountId {
77 input_id: AccountId,
78 output_id: AccountId,
79 },
80 #[error("expected account nonce delta to be {expected}, found {actual}")]
81 InconsistentAccountNonceDelta { expected: Felt, actual: Felt },
82 #[error(
83 "native asset amount {account_balance} in the account vault is not sufficient to cover the transaction fee of {tx_fee}"
84 )]
85 InsufficientFee { account_balance: u64, tx_fee: u64 },
86 #[error("account witness provided for account ID {0} is invalid")]
87 InvalidAccountWitness(AccountId, #[source] SmtProofError),
88 #[error(
89 "input note {0} was created in a block past the transaction reference block number ({1})"
90 )]
91 NoteBlockPastReferenceBlock(NoteId, BlockNumber),
92 #[error("failed to create transaction host")]
93 TransactionHostCreationFailed(#[source] TransactionHostError),
94 #[error("failed to construct transaction outputs")]
95 TransactionOutputConstructionFailed(#[source] TransactionOutputError),
96 #[error("failed to execute transaction kernel program:\n{}", PrintDiagnostic::new(.0))]
99 TransactionProgramExecutionFailed(ExecutionError),
100 #[error("transaction is unauthorized with summary {0:?}")]
103 Unauthorized(Box<TransactionSummary>),
104}
105
106#[derive(Debug, Error)]
110pub enum TransactionProverError {
111 #[error("failed to apply account delta")]
112 AccountDeltaApplyFailed(#[source] AccountError),
113 #[error("failed to remove the fee asset from the pre-fee account delta")]
114 RemoveFeeAssetFromDelta(#[source] AccountDeltaError),
115 #[error("failed to construct transaction outputs")]
116 TransactionOutputConstructionFailed(#[source] TransactionOutputError),
117 #[error("failed to build proven transaction")]
118 ProvenTransactionBuildFailed(#[source] ProvenTransactionError),
119 #[error("the advice map contains conflicting map entries")]
120 ConflictingAdviceMapEntry(#[source] TransactionAdviceMapMismatch),
121 #[error("failed to execute transaction kernel program:\n{}", PrintDiagnostic::new(.0))]
124 TransactionProgramExecutionFailed(ExecutionError),
125 #[error("failed to create transaction host")]
126 TransactionHostCreationFailed(#[source] TransactionHostError),
127 #[error("{error_msg}")]
129 Other {
130 error_msg: Box<str>,
131 source: Option<Box<dyn Error + Send + Sync + 'static>>,
133 },
134}
135
136impl TransactionProverError {
137 pub fn other(message: impl Into<String>) -> Self {
140 let message: String = message.into();
141 Self::Other { error_msg: message.into(), source: None }
142 }
143
144 pub fn other_with_source(
147 message: impl Into<String>,
148 source: impl Error + Send + Sync + 'static,
149 ) -> Self {
150 let message: String = message.into();
151 Self::Other {
152 error_msg: message.into(),
153 source: Some(Box::new(source)),
154 }
155 }
156}
157
158#[derive(Debug, Error)]
162pub enum TransactionVerifierError {
163 #[error("failed to verify transaction")]
164 TransactionVerificationFailed(#[source] VerificationError),
165 #[error("transaction proof security level is {actual} but must be at least {expected_minimum}")]
166 InsufficientProofSecurityLevel { actual: u32, expected_minimum: u32 },
167}
168
169#[derive(Debug, Error)]
173pub enum TransactionHostError {
174 #[error("{0}")]
175 AccountProcedureIndexMapError(String),
176 #[error("failed to create account procedure info")]
177 AccountProcedureInfoCreationFailed(#[source] AccountError),
178}
179
180#[derive(Debug, Error)]
184pub enum DataStoreError {
185 #[error("account with id {0} not found in data store")]
186 AccountNotFound(AccountId),
187 #[error("block with number {0} not found in data store")]
188 BlockNotFound(BlockNumber),
189 #[error("{error_msg}")]
192 Other {
193 error_msg: Box<str>,
194 source: Option<Box<dyn Error + Send + Sync + 'static>>,
196 },
197}
198
199impl DataStoreError {
200 pub fn other(message: impl Into<String>) -> Self {
202 let message: String = message.into();
203 Self::Other { error_msg: message.into(), source: None }
204 }
205
206 pub fn other_with_source(
209 message: impl Into<String>,
210 source: impl Error + Send + Sync + 'static,
211 ) -> Self {
212 let message: String = message.into();
213 Self::Other {
214 error_msg: message.into(),
215 source: Some(Box::new(source)),
216 }
217 }
218}
219
220#[derive(Debug, Error)]
224pub enum AuthenticationError {
225 #[error("signature rejected: {0}")]
226 RejectedSignature(String),
227 #[error("unknown public key: {0}")]
228 UnknownPublicKey(String),
229 #[error("{error_msg}")]
232 Other {
233 error_msg: Box<str>,
234 source: Option<Box<dyn Error + Send + Sync + 'static>>,
236 },
237}
238
239impl AuthenticationError {
240 pub fn other(message: impl Into<String>) -> Self {
243 let message: String = message.into();
244 Self::Other { error_msg: message.into(), source: None }
245 }
246
247 pub fn other_with_source(
250 message: impl Into<String>,
251 source: impl Error + Send + Sync + 'static,
252 ) -> Self {
253 let message: String = message.into();
254 Self::Other {
255 error_msg: message.into(),
256 source: Some(Box::new(source)),
257 }
258 }
259}
260
261#[cfg(test)]
262mod error_assertions {
263 use super::*;
264
265 fn _assert_error_is_send_sync_static<E: core::error::Error + Send + Sync + 'static>(_: E) {}
267
268 fn _assert_data_store_error_bounds(err: DataStoreError) {
269 _assert_error_is_send_sync_static(err);
270 }
271
272 fn _assert_authentication_error_bounds(err: AuthenticationError) {
273 _assert_error_is_send_sync_static(err);
274 }
275}