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 #[error("transaction preparation failed: {0}")]
45 TransactionPreparation(#[source] TransactionExecutorError),
46 #[error("transaction execution prologue failed: {0}")]
47 PrologueExecution(#[source] TransactionExecutorError),
48}
49
50#[derive(Debug, Error)]
54pub(crate) enum TransactionCheckerError {
55 #[error("transaction preparation failed: {0}")]
56 TransactionPreparation(#[source] TransactionExecutorError),
57 #[error("transaction execution prologue failed: {0}")]
58 PrologueExecution(#[source] TransactionExecutorError),
59 #[error("transaction execution epilogue failed: {0}")]
60 EpilogueExecution(#[source] TransactionExecutorError),
61 #[error("transaction note execution failed on note index {failed_note_index}: {error}")]
62 NoteExecution {
63 failed_note_index: usize,
64 error: TransactionExecutorError,
65 },
66}
67
68impl From<TransactionCheckerError> for TransactionExecutorError {
69 fn from(error: TransactionCheckerError) -> Self {
70 match error {
71 TransactionCheckerError::TransactionPreparation(error) => error,
72 TransactionCheckerError::PrologueExecution(error) => error,
73 TransactionCheckerError::EpilogueExecution(error) => error,
74 TransactionCheckerError::NoteExecution { error, .. } => error,
75 }
76 }
77}
78
79#[derive(Debug, Error)]
83pub enum TransactionExecutorError {
84 #[error("the advice map contains conflicting map entries")]
85 ConflictingAdviceMapEntry(#[source] TransactionAdviceMapMismatch),
86 #[error("failed to fetch transaction inputs from the data store")]
87 FetchTransactionInputsFailed(#[source] DataStoreError),
88 #[error("foreign account inputs for ID {0} are not anchored on reference block")]
89 ForeignAccountNotAnchoredInReference(AccountId),
90 #[error(
91 "execution options' cycles must be between {min_cycles} and {max_cycles}, but found {actual}"
92 )]
93 InvalidExecutionOptionsCycles {
94 min_cycles: u32,
95 max_cycles: u32,
96 actual: u32,
97 },
98 #[error("failed to create transaction inputs")]
99 InvalidTransactionInputs(#[source] TransactionInputError),
100 #[error("failed to process account update commitment: {0}")]
101 AccountUpdateCommitment(&'static str),
102 #[error(
103 "account delta commitment computed in transaction kernel ({in_kernel_commitment}) does not match account delta computed via the host ({host_commitment})"
104 )]
105 InconsistentAccountDeltaCommitment {
106 in_kernel_commitment: Word,
107 host_commitment: Word,
108 },
109 #[error("failed to remove the fee asset from the pre-fee account delta")]
110 RemoveFeeAssetFromDelta(#[source] AccountDeltaError),
111 #[error("input account ID {input_id} does not match output account ID {output_id}")]
112 InconsistentAccountId {
113 input_id: AccountId,
114 output_id: AccountId,
115 },
116 #[error("expected account nonce delta to be {expected}, found {actual}")]
117 InconsistentAccountNonceDelta { expected: Felt, actual: Felt },
118 #[error(
119 "native asset amount {account_balance} in the account vault is not sufficient to cover the transaction fee of {tx_fee}"
120 )]
121 InsufficientFee { account_balance: u64, tx_fee: u64 },
122 #[error("account witness provided for account ID {0} is invalid")]
123 InvalidAccountWitness(AccountId, #[source] SmtProofError),
124 #[error(
125 "input note {0} was created in a block past the transaction reference block number ({1})"
126 )]
127 NoteBlockPastReferenceBlock(NoteId, BlockNumber),
128 #[error("failed to create transaction host")]
129 TransactionHostCreationFailed(#[source] TransactionHostError),
130 #[error("failed to construct transaction outputs")]
131 TransactionOutputConstructionFailed(#[source] TransactionOutputError),
132 #[error("failed to execute transaction kernel program:\n{}", PrintDiagnostic::new(.0))]
135 TransactionProgramExecutionFailed(ExecutionError),
136 #[error("transaction is unauthorized with summary {0:?}")]
139 Unauthorized(Box<TransactionSummary>),
140 #[error(
141 "failed to respond to signature requested since no authenticator is assigned to the host"
142 )]
143 MissingAuthenticator,
144}
145
146#[derive(Debug, Error)]
150pub enum TransactionProverError {
151 #[error("failed to apply account delta")]
152 AccountDeltaApplyFailed(#[source] AccountError),
153 #[error("failed to remove the fee asset from the pre-fee account delta")]
154 RemoveFeeAssetFromDelta(#[source] AccountDeltaError),
155 #[error("failed to construct transaction outputs")]
156 TransactionOutputConstructionFailed(#[source] TransactionOutputError),
157 #[error("failed to build proven transaction")]
158 ProvenTransactionBuildFailed(#[source] ProvenTransactionError),
159 #[error("the advice map contains conflicting map entries")]
160 ConflictingAdviceMapEntry(#[source] TransactionAdviceMapMismatch),
161 #[error("failed to execute transaction kernel program:\n{}", PrintDiagnostic::new(.0))]
164 TransactionProgramExecutionFailed(ExecutionError),
165 #[error("failed to create transaction host")]
166 TransactionHostCreationFailed(#[source] TransactionHostError),
167 #[error("{error_msg}")]
169 Other {
170 error_msg: Box<str>,
171 source: Option<Box<dyn Error + Send + Sync + 'static>>,
173 },
174}
175
176impl TransactionProverError {
177 pub fn other(message: impl Into<String>) -> Self {
180 let message: String = message.into();
181 Self::Other { error_msg: message.into(), source: None }
182 }
183
184 pub fn other_with_source(
187 message: impl Into<String>,
188 source: impl Error + Send + Sync + 'static,
189 ) -> Self {
190 let message: String = message.into();
191 Self::Other {
192 error_msg: message.into(),
193 source: Some(Box::new(source)),
194 }
195 }
196}
197
198#[derive(Debug, Error)]
202pub enum TransactionVerifierError {
203 #[error("failed to verify transaction")]
204 TransactionVerificationFailed(#[source] VerificationError),
205 #[error("transaction proof security level is {actual} but must be at least {expected_minimum}")]
206 InsufficientProofSecurityLevel { actual: u32, expected_minimum: u32 },
207}
208
209#[derive(Debug, Error)]
213pub enum TransactionHostError {
214 #[error("{0}")]
215 AccountProcedureIndexMapError(String),
216 #[error("failed to create account procedure info")]
217 AccountProcedureInfoCreationFailed(#[source] AccountError),
218}
219
220#[derive(Debug, Error)]
224pub enum DataStoreError {
225 #[error("account with id {0} not found in data store")]
226 AccountNotFound(AccountId),
227 #[error("block with number {0} not found in data store")]
228 BlockNotFound(BlockNumber),
229 #[error("{error_msg}")]
232 Other {
233 error_msg: Box<str>,
234 source: Option<Box<dyn Error + Send + Sync + 'static>>,
236 },
237}
238
239impl DataStoreError {
240 pub fn other(message: impl Into<String>) -> Self {
242 let message: String = message.into();
243 Self::Other { error_msg: message.into(), source: None }
244 }
245
246 pub fn other_with_source(
249 message: impl Into<String>,
250 source: impl Error + Send + Sync + 'static,
251 ) -> Self {
252 let message: String = message.into();
253 Self::Other {
254 error_msg: message.into(),
255 source: Some(Box::new(source)),
256 }
257 }
258}
259
260#[derive(Debug, Error)]
264pub enum AuthenticationError {
265 #[error("signature rejected: {0}")]
266 RejectedSignature(String),
267 #[error("unknown public key: {0}")]
268 UnknownPublicKey(String),
269 #[error("{error_msg}")]
272 Other {
273 error_msg: Box<str>,
274 source: Option<Box<dyn Error + Send + Sync + 'static>>,
276 },
277}
278
279impl AuthenticationError {
280 pub fn other(message: impl Into<String>) -> Self {
283 let message: String = message.into();
284 Self::Other { error_msg: message.into(), source: None }
285 }
286
287 pub fn other_with_source(
290 message: impl Into<String>,
291 source: impl Error + Send + Sync + 'static,
292 ) -> Self {
293 let message: String = message.into();
294 Self::Other {
295 error_msg: message.into(),
296 source: Some(Box::new(source)),
297 }
298 }
299}
300
301#[cfg(test)]
302mod error_assertions {
303 use super::*;
304
305 fn _assert_error_is_send_sync_static<E: core::error::Error + Send + Sync + 'static>(_: E) {}
307
308 fn _assert_data_store_error_bounds(err: DataStoreError) {
309 _assert_error_is_send_sync_static(err);
310 }
311
312 fn _assert_authentication_error_bounds(err: AuthenticationError) {
313 _assert_error_is_send_sync_static(err);
314 }
315}