1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::error::Error;
5
6use miden_assembly::Report;
7use miden_assembly::diagnostics::reporting::PrintDiagnostic;
8use miden_core::mast::MastForestError;
9use miden_crypto::merkle::mmr::MmrError;
10use miden_crypto::merkle::smt::{SmtLeafError, SmtProofError};
11use miden_crypto::utils::HexParseError;
12use miden_processor::ExecutionError;
13use miden_verifier::VerificationError;
14use thiserror::Error;
15
16use super::account::{AccountId, RoleSymbol};
17use super::asset::{AssetComposition, AssetId, FungibleAsset, NonFungibleAsset, TokenSymbol};
18use super::crypto::merkle::MerkleError;
19use super::note::NoteId;
20use super::{MAX_BATCHES_PER_BLOCK, MAX_OUTPUT_NOTES_PER_BATCH, Word};
21use crate::account::component::{SchemaTypeError, StorageValueName, StorageValueNameError};
22use crate::account::{
23 AccountCode,
24 AccountIdPrefix,
25 AccountProcedureRoot,
26 AccountStorage,
27 StorageMapKey,
28 StorageSlotId,
29 StorageSlotName,
30};
31use crate::address::AddressType;
32use crate::asset::AssetClass;
33use crate::batch::BatchId;
34use crate::block::BlockNumber;
35use crate::note::{
36 NoteAssets,
37 NoteAttachment,
38 NoteAttachmentScheme,
39 NoteAttachments,
40 NoteTag,
41 NoteType,
42 Nullifier,
43};
44use crate::transaction::TransactionId;
45use crate::utils::serde::DeserializationError;
46use crate::vm::EventId;
47use crate::{
48 ACCOUNT_UPDATE_MAX_SIZE,
49 Felt,
50 MAX_ACCOUNTS_PER_BATCH,
51 MAX_INPUT_NOTES_PER_BATCH,
52 MAX_INPUT_NOTES_PER_TX,
53 MAX_NOTE_STORAGE_ITEMS,
54 MAX_OUTPUT_NOTES_PER_TX,
55 NOTE_MAX_SIZE,
56};
57
58#[cfg(any(feature = "testing", test))]
59mod masm_error;
60#[cfg(any(feature = "testing", test))]
61pub use masm_error::MasmError;
62
63#[cfg(any(feature = "testing", test))]
65pub mod tx_kernel {
66 include!(concat!(env!("OUT_DIR"), "/tx_kernel_errors.rs"));
67}
68
69#[cfg(any(feature = "testing", test))]
71pub mod protocol {
72 include!(concat!(env!("OUT_DIR"), "/protocol_errors.rs"));
73}
74
75#[derive(Debug, Error)]
79pub enum ComponentMetadataError {
80 #[error("storage slot name `{0}` is duplicate")]
81 DuplicateSlotName(StorageSlotName),
82 #[error("storage init value name `{0}` is duplicate")]
83 DuplicateInitValueName(StorageValueName),
84 #[error("storage value name is incorrect: {0}")]
85 IncorrectStorageValueName(#[source] StorageValueNameError),
86 #[error("invalid storage schema: {0}")]
87 InvalidSchema(String),
88 #[error("type `{0}` is not valid for `{1}` slots")]
89 InvalidType(String, String),
90 #[error("error deserializing component metadata: {0}")]
91 MetadataDeserializationError(String),
92 #[error("init storage value `{0}` was not provided")]
93 InitValueNotProvided(StorageValueName),
94 #[error("invalid init storage value for `{0}`: {1}")]
95 InvalidInitStorageValue(StorageValueName, String),
96 #[error("error converting value into expected type: {0}")]
97 StorageValueParsingError(#[source] SchemaTypeError),
98 #[error("storage map contains duplicate keys")]
99 StorageMapHasDuplicateKeys(#[source] Box<dyn Error + Send + Sync + 'static>),
100 #[cfg(feature = "std")]
101 #[error("error trying to deserialize from toml")]
102 TomlDeserializationError(#[source] toml::de::Error),
103 #[cfg(feature = "std")]
104 #[error("error trying to deserialize from toml")]
105 TomlSerializationError(#[source] toml::ser::Error),
106}
107
108#[derive(Debug, Error)]
112pub enum AccountError {
113 #[error("account code does not contain an auth component")]
114 AccountCodeNoAuthComponent,
115 #[error("account code contains multiple auth components")]
116 AccountCodeMultipleAuthComponents,
117 #[error("account code must contain at least one non-auth procedure")]
118 AccountCodeNoProcedures,
119 #[error("account procedure {0} is not contained in the provided mast forest")]
120 AccountCodeProcedureNotInMastForest(AccountProcedureRoot),
121 #[error("account code contains {0} procedures but it may contain at most {max} procedures", max = AccountCode::MAX_NUM_PROCEDURES)]
122 AccountCodeTooManyProcedures(usize),
123 #[error("account code contains a duplicate procedure with root {0}")]
124 AccountCodeDuplicateProcedureRoot(Word),
125 #[error("failed to assemble account component:\n{}", PrintDiagnostic::new(.0))]
126 AccountComponentAssemblyError(Report),
127 #[error("failed to merge components into one account code mast forest")]
128 AccountComponentMastForestMergeError(#[source] MastForestError),
129 #[error("account component contains multiple authentication procedures")]
130 AccountComponentMultipleAuthProcedures,
131 #[error("failed to update asset vault")]
132 AssetVaultUpdateError(#[source] AssetVaultError),
133 #[error("account build error: {0}")]
134 BuildError(String, #[source] Option<Box<AccountError>>),
135 #[error("failed to parse account ID from final account header")]
136 FinalAccountHeaderIdParsingFailed(#[source] AccountIdError),
137 #[error("account header data has length {actual} but it must be of length {expected}")]
138 HeaderDataIncorrectLength { actual: usize, expected: usize },
139 #[error("final nonce {new} is not strictly greater than current account nonce {current}")]
140 NonceMustIncrease { current: Felt, new: Felt },
141 #[error(
142 "digest of the seed has {actual} trailing zeroes but must have at least {expected} trailing zeroes"
143 )]
144 SeedDigestTooFewTrailingZeros { expected: u32, actual: u32 },
145 #[error("account ID {actual} computed from seed does not match ID {expected} on account")]
146 AccountIdSeedMismatch { actual: AccountId, expected: AccountId },
147 #[error("account ID seed was provided for an existing account")]
148 ExistingAccountWithSeed,
149 #[error("account ID seed was not provided for a new account")]
150 NewAccountMissingSeed,
151 #[error(
152 "an account with a seed cannot be converted into a delta since it represents an unregistered account"
153 )]
154 DeltaFromAccountWithSeed,
155 #[error(
156 "an account with a seed cannot be converted into a patch since it represents an unregistered account"
157 )]
158 PatchFromAccountWithSeed,
159 #[error("seed converts to an invalid account ID")]
160 SeedConvertsToInvalidAccountId(#[source] AccountIdError),
161 #[error("storage map root {0} not found in the account storage")]
162 StorageMapRootNotFound(Word),
163 #[error("storage slot {0} is not of type map")]
164 StorageSlotNotMap(StorageSlotName),
165 #[error("storage slot {0} is not of type value")]
166 StorageSlotNotValue(StorageSlotName),
167 #[error("storage slot name {0} is assigned to more than one slot")]
168 DuplicateStorageSlotName(StorageSlotName),
169 #[error("storage does not contain a slot with name {slot_name}")]
170 StorageSlotNameNotFound { slot_name: StorageSlotName },
171 #[error("storage does not contain a slot with ID {slot_id}")]
172 StorageSlotIdNotFound { slot_id: StorageSlotId },
173 #[error("storage slots must be sorted by slot ID")]
174 UnsortedStorageSlots,
175 #[error("number of storage slots is {0} but max possible number is {max}", max = AccountStorage::MAX_NUM_STORAGE_SLOTS)]
176 StorageTooManySlots(u64),
177 #[error(
178 "failed to apply full state patch to existing account; full state patches can be converted to accounts directly"
179 )]
180 ApplyFullStatePatchToAccount,
181 #[error("patch is for account ID {patch_id} but is being applied to account {account_id}")]
182 PatchAccountIdMismatch {
183 account_id: AccountId,
184 patch_id: AccountId,
185 },
186 #[error("only account deltas representing a full account can be converted to a full account")]
187 PartialStateDeltaToAccount,
188 #[error("assets cannot be removed from a new account with an empty asset vault")]
189 AssetsRemovedFromNewAccount,
190 #[error("only account patches representing a full account can be converted to a full account")]
191 PartialStatePatchToAccount,
192 #[error("maximum number of storage map leaves exceeded")]
193 MaxNumStorageMapLeavesExceeded(#[source] MerkleError),
194 #[error("unknown storage patch operation tag {0}")]
195 UnknownStoragePatchOperation(u8),
196 #[error("{error_msg}")]
199 Other {
200 error_msg: Box<str>,
201 source: Option<Box<dyn Error + Send + Sync + 'static>>,
203 },
204}
205
206impl AccountError {
207 pub fn other(message: impl Into<String>) -> Self {
209 let message: String = message.into();
210 Self::Other { error_msg: message.into(), source: None }
211 }
212
213 pub fn other_with_source(
216 message: impl Into<String>,
217 source: impl Error + Send + Sync + 'static,
218 ) -> Self {
219 let message: String = message.into();
220 Self::Other {
221 error_msg: message.into(),
222 source: Some(Box::new(source)),
223 }
224 }
225}
226
227#[derive(Debug, Error)]
231pub enum AccountIdError {
232 #[error("failed to convert bytes into account ID prefix field element")]
233 AccountIdInvalidPrefixFieldElement(#[source] DeserializationError),
234 #[error("failed to convert bytes into account ID suffix field element")]
235 AccountIdInvalidSuffixFieldElement(#[source] DeserializationError),
236 #[error("`{0}` is not a known account type")]
237 UnknownAccountType(Box<str>),
238 #[error("failed to parse hex string into account ID")]
239 AccountIdHexParseError(#[source] HexParseError),
240 #[error("`{0}` is not a known account ID version")]
241 UnknownAccountIdVersion(u8),
242 #[error("most significant bit of account ID suffix must be zero")]
243 AccountIdSuffixMostSignificantBitMustBeZero,
244 #[error("least significant byte of account ID suffix must be zero")]
245 AccountIdSuffixLeastSignificantByteMustBeZero,
246 #[error("failed to decode bech32 string into account ID")]
247 Bech32DecodeError(#[source] Bech32Error),
248}
249
250#[derive(Debug, Error)]
254pub enum StorageSlotNameError {
255 #[error("slot name must only contain characters a..z, A..Z, 0..9, double colon or underscore")]
256 InvalidCharacter,
257 #[error("slot names must be separated by double colons")]
258 UnexpectedColon,
259 #[error("slot name components must not start with an underscore")]
260 UnexpectedUnderscore,
261 #[error(
262 "slot names must contain at least {} components separated by double colons",
263 StorageSlotName::MIN_NUM_COMPONENTS
264 )]
265 TooShort,
266 #[error("slot names must contain at most {} characters", StorageSlotName::MAX_LENGTH)]
267 TooLong,
268}
269
270#[derive(Debug, Error)]
274pub enum AccountCodeInterfaceError {
275 #[error(
276 "account code interface must contain at least {} procedures, but only {actual} were given",
277 AccountCode::MIN_NUM_PROCEDURES
278 )]
279 TooFewProcedures { actual: usize },
280 #[error(
281 "account code interface contains {actual} procedures but it may contain at most {} procedures",
282 AccountCode::MAX_NUM_PROCEDURES
283 )]
284 TooManyProcedures { actual: usize },
285}
286
287#[derive(Debug, Error)]
291pub enum AccountComponentNameError {
292 #[error(
293 "account component name must only contain characters a..z, A..Z, 0..9, double colon or underscore"
294 )]
295 InvalidCharacter,
296 #[error("account component names must be separated by double colons")]
297 UnexpectedColon,
298 #[error("account component name components must not start with an underscore")]
299 UnexpectedUnderscore,
300 #[error(
301 "account component names must contain at least {} components separated by double colons",
302 StorageSlotName::MIN_NUM_COMPONENTS
303 )]
304 TooShort,
305 #[error(
306 "account component names must contain at most {} characters",
307 StorageSlotName::MAX_LENGTH
308 )]
309 TooLong,
310}
311
312#[derive(Debug, Error)]
316pub enum AccountTreeError {
317 #[error(
318 "account tree contains multiple account IDs that share the same prefix {duplicate_prefix}"
319 )]
320 DuplicateIdPrefix { duplicate_prefix: AccountIdPrefix },
321 #[error(
322 "entries passed to account tree contain multiple state commitments for the same account ID prefix {prefix}"
323 )]
324 DuplicateStateCommitments { prefix: AccountIdPrefix },
325 #[error("untracked account ID {id} used in partial account tree")]
326 UntrackedAccountId { id: AccountId, source: MerkleError },
327 #[error("new tree root after account witness insertion does not match previous tree root")]
328 TreeRootConflict(#[source] MerkleError),
329 #[error("failed to apply mutations to account tree")]
330 ApplyMutations(#[source] MerkleError),
331 #[error("failed to compute account tree mutations")]
332 ComputeMutations(#[source] MerkleError),
333 #[error("provided smt contains an invalid account ID in key {key}")]
334 InvalidAccountIdKey { key: Word, source: AccountIdError },
335 #[error("smt leaf's index is not a valid account ID prefix")]
336 InvalidAccountIdPrefix(#[source] AccountIdError),
337 #[error("account witness merkle path depth {0} does not match AccountTree::DEPTH")]
338 WitnessMerklePathDepthDoesNotMatchAccountTreeDepth(usize),
339}
340
341#[derive(Debug, Error)]
345pub enum AddressError {
346 #[error("tag length {0} is too large, must be less than or equal to {max}",
347 max = NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH
348 )]
349 TagLengthTooLarge(u8),
350 #[error("unknown address interface `{0}`")]
351 UnknownAddressInterface(u16),
352 #[error("failed to decode account ID")]
353 AccountIdDecodeError(#[source] AccountIdError),
354 #[error("address separator must not be included without routing parameters")]
355 TrailingSeparator,
356 #[error("failed to decode bech32 string into an address")]
357 Bech32DecodeError(#[source] Bech32Error),
358 #[error("{error_msg}")]
359 DecodeError {
360 error_msg: Box<str>,
361 source: Option<Box<dyn Error + Send + Sync + 'static>>,
363 },
364 #[error("found unknown routing parameter key {0}")]
365 UnknownRoutingParameterKey(u8),
366}
367
368impl AddressError {
369 pub fn decode_error(message: impl Into<String>) -> Self {
371 let message: String = message.into();
372 Self::DecodeError { error_msg: message.into(), source: None }
373 }
374
375 pub fn decode_error_with_source(
378 message: impl Into<String>,
379 source: impl Error + Send + Sync + 'static,
380 ) -> Self {
381 let message: String = message.into();
382 Self::DecodeError {
383 error_msg: message.into(),
384 source: Some(Box::new(source)),
385 }
386 }
387}
388
389#[derive(Debug, Error)]
393pub enum Bech32Error {
394 #[error(transparent)]
395 DecodeError(Box<dyn Error + Send + Sync + 'static>),
396 #[error("found unknown address type {0} which is not the expected {account_addr} account ID address type",
397 account_addr = AddressType::AccountId as u8
398 )]
399 UnknownAddressType(u8),
400 #[error("expected bech32 data to be of length {expected} but it was of length {actual}")]
401 InvalidDataLength { expected: usize, actual: usize },
402}
403
404#[derive(Debug, Error)]
408pub enum NetworkIdError {
409 #[error("failed to parse string into a network ID")]
410 NetworkIdParseError(#[source] Box<dyn Error + Send + Sync + 'static>),
411}
412
413#[derive(Debug, Error)]
417pub enum AccountDeltaError {
418 #[error("storage slot {0} was used as different slot types")]
419 StorageSlotUsedAsDifferentTypes(StorageSlotName),
420 #[error("non fungible vault can neither be added nor removed twice")]
421 DuplicateNonFungibleVaultUpdate(NonFungibleAsset),
422 #[error(
423 "fungible asset issued by faucet {faucet_id} has delta {delta} which overflows when added to current value {current}"
424 )]
425 FungibleAssetDeltaOverflow {
426 faucet_id: AccountId,
427 current: i64,
428 delta: i64,
429 },
430 #[error(
431 "account update of type `{left_update_type}` cannot be merged with account update of type `{right_update_type}`"
432 )]
433 IncompatibleAccountUpdates {
434 left_update_type: &'static str,
435 right_update_type: &'static str,
436 },
437 #[error("account delta could not be applied to account {account_id}")]
438 AccountDeltaApplicationFailed {
439 account_id: AccountId,
440 source: AccountError,
441 },
442 #[error("non-empty account storage or vault delta with zero nonce delta is not allowed")]
443 NonEmptyStorageOrVaultDeltaWithZeroNonceDelta,
444 #[error(
445 "asset issued by faucet {0} in fungible asset delta does not have fungible composition"
446 )]
447 NotAFungibleFaucetId(AccountId),
448 #[error("cannot merge two full state deltas")]
449 MergingFullStateDeltas,
450 #[error("a full state delta must only contain storage create operations")]
451 FullStateDeltaContainsNonCreateOp,
452}
453
454#[derive(Debug, Error)]
455pub enum AccountPatchError {
456 #[error("final nonce can never be set to zero")]
457 FinalNonceIsZero,
458
459 #[error(
460 "state change to an account (store, vault or code) require that the final nonce is incremented"
461 )]
462 StateChangeRequiresNonceUpdate,
463
464 #[error("account code must be provided for new accounts (with nonce = 1)")]
465 CodeMustBeProvidedForNewAccounts,
466
467 #[error("a full state patch must only contain storage create operations")]
468 FullStatePatchContainsNonCreateStorageOp,
469
470 #[error("storage slot {0} was used as different slot types")]
471 StorageSlotUsedAsDifferentTypes(StorageSlotName),
472
473 #[error("storage slot name {0} is assigned to more than one slot patch")]
474 DuplicateStorageSlotName(StorageSlotName),
475
476 #[error("number of storage slot patches is {0} but max possible number is {max}", max = AccountStorage::MAX_NUM_STORAGE_SLOTS)]
477 TooManyStorageSlotPatches(usize),
478
479 #[error(
480 "a full state patch cannot be merged on top of another patch; it must be the merge base"
481 )]
482 MergeIncomingFullStatePatch,
483
484 #[error("failed to merge storage patch for slot {0}: cannot create a slot twice")]
485 StoragePatchMergeDoubleCreate(StorageSlotName),
486
487 #[error(
488 "failed to merge storage patch for slot {0}: cannot create a slot after it was updated, which indicates it already exists"
489 )]
490 StoragePatchMergeCreateAfterUpdate(StorageSlotName),
491
492 #[error("failed to merge storage patch for slot {0}: cannot update slot after it was removed")]
493 StoragePatchMergeUpdateAfterRemove(StorageSlotName),
494
495 #[error("failed to merge storage patch for slot {0}: cannot remove a slot twice")]
496 StoragePatchMergeDoubleRemove(StorageSlotName),
497
498 #[error(
499 "nonce in the patch being merged is {new} which is not exactly one greater than current patch nonce {current}"
500 )]
501 NonceMustIncrementByOne { current: Felt, new: Felt },
502
503 #[error(
504 "patch is for account ID {actual} but is being merged into patch for account {expected}"
505 )]
506 AccountIdMismatch { expected: AccountId, actual: AccountId },
507
508 #[error(
509 "account update of type `{left_update_type}` cannot be merged with account update of type `{right_update_type}`"
510 )]
511 IncompatibleAccountUpdates {
512 left_update_type: &'static str,
513 right_update_type: &'static str,
514 },
515}
516
517#[derive(Debug, Error)]
521pub enum StorageMapError {
522 #[error("map entries contain key {key} twice with values {value0} and {value1}")]
523 DuplicateKey {
524 key: StorageMapKey,
525 value0: Word,
526 value1: Word,
527 },
528 #[error("map key {key} is not present in provided SMT proof")]
529 MissingKey { key: StorageMapKey },
530}
531
532#[derive(Debug, Error)]
536pub enum BatchAccountUpdateError {
537 #[error(
538 "account update for account {expected_account_id} cannot be merged with update from transaction {transaction} which was executed against account {actual_account_id}"
539 )]
540 AccountUpdateIdMismatch {
541 transaction: TransactionId,
542 expected_account_id: AccountId,
543 actual_account_id: AccountId,
544 },
545 #[error(
546 "final state commitment in account update from transaction {0} does not match initial state of current update"
547 )]
548 AccountUpdateInitialStateMismatch(TransactionId),
549 #[error("failed to merge account patch from transaction {0}")]
550 TransactionUpdateMergeError(TransactionId, #[source] Box<AccountPatchError>),
551}
552
553#[derive(Debug, Error)]
557pub enum AssetError {
558 #[error(
559 "fungible asset amount {0} exceeds the max allowed amount of {max_amount}",
560 max_amount = FungibleAsset::MAX_AMOUNT
561 )]
562 FungibleAssetAmountTooBig(u64),
563 #[error("subtracting {subtrahend} from fungible asset amount {minuend} would underflow")]
564 FungibleAssetAmountNotSufficient { minuend: u64, subtrahend: u64 },
565 #[error(
566 "cannot combine fungible assets with different asset IDs: {original_id} and {other_id}"
567 )]
568 FungibleAssetInconsistentIds { original_id: AssetId, other_id: AssetId },
569 #[error("faucet account ID in asset is invalid")]
570 InvalidFaucetAccountId(#[source] Box<dyn Error + Send + Sync + 'static>),
571 #[error(
572 "asset class prefix and suffix in a non-fungible asset ID must match indices 0 and 1 in the value, but asset class was {asset_class} and value was {value}"
573 )]
574 NonFungibleAssetClassMustMatchValue { asset_class: AssetClass, value: Word },
575 #[error("asset class prefix and suffix in a fungible asset ID must be zero but was {0}")]
576 FungibleAssetClassMustBeZero(AssetClass),
577 #[error(
578 "the three most significant elements in a fungible asset's value must be zero but provided value was {0}"
579 )]
580 FungibleAssetValueMostSignificantElementsMustBeZero(Word),
581 #[error("smt proof in asset witness contains invalid ID or value")]
582 AssetWitnessInvalid(#[source] Box<AssetError>),
583 #[error("asset ID {id} is not present in the provided asset witness SMT proof")]
584 AssetWitnessMissingId { id: AssetId },
585 #[error("unknown asset composition encoding: {0}")]
586 UnknownAssetComposition(u8),
587 #[error("unknown asset delta operation encoding: {0}")]
588 UnknownAssetDeltaOperation(u8),
589 #[error("asset composition {0:?} is not supported at this operational site")]
590 UnsupportedAssetComposition(AssetComposition),
591 #[error(
592 "asset composition mismatch for faucet {faucet_id}: expected {expected:?}, found {actual:?}"
593 )]
594 AssetCompositionMismatch {
595 faucet_id: AccountId,
596 expected: AssetComposition,
597 actual: AssetComposition,
598 },
599 #[error("asset metadata byte 0x{0:02x} has reserved bits set to non-zero values")]
600 ReservedAssetMetadata(u8),
601}
602
603#[derive(Debug, Error)]
607pub enum TokenSymbolError {
608 #[error("token symbol value {0} cannot exceed {max}", max = TokenSymbol::MAX_ENCODED_VALUE)]
609 ValueTooLarge(u64),
610 #[error(
611 "token symbol value {0} cannot be less than {min}",
612 min = TokenSymbol::MIN_ENCODED_VALUE
613 )]
614 ValueTooSmall(u64),
615 #[error("token symbol should have length between 1 and 12 characters, but {0} was provided")]
616 InvalidLength(usize),
617 #[error("token symbol contains a character that is not uppercase ASCII")]
618 InvalidCharacter,
619 #[error("token symbol data left after decoding the specified number of characters")]
620 DataNotFullyDecoded,
621}
622
623impl From<ShortCapitalStringError> for TokenSymbolError {
624 fn from(value: ShortCapitalStringError) -> Self {
625 match value {
626 ShortCapitalStringError::ValueTooLarge(v) => Self::ValueTooLarge(v),
627 ShortCapitalStringError::ValueTooSmall(v) => Self::ValueTooSmall(v),
628 ShortCapitalStringError::InvalidLength(v) => Self::InvalidLength(v),
629 ShortCapitalStringError::InvalidCharacter => Self::InvalidCharacter,
630 ShortCapitalStringError::DataNotFullyDecoded => Self::DataNotFullyDecoded,
631 }
632 }
633}
634
635#[derive(Debug, Error)]
639pub enum RoleSymbolError {
640 #[error("role symbol value {0} cannot exceed {max}", max = RoleSymbol::MAX_ENCODED_VALUE)]
641 ValueTooLarge(u64),
642 #[error("role symbol value {0} cannot be less than {min}", min = RoleSymbol::MIN_ENCODED_VALUE)]
643 ValueTooSmall(u64),
644 #[error("role symbol should have length between 1 and 12 characters, but {0} was provided")]
645 InvalidLength(usize),
646 #[error("role symbol contains a character that is not uppercase ASCII or underscore")]
647 InvalidCharacter,
648 #[error("role symbol data left after decoding the specified number of characters")]
649 DataNotFullyDecoded,
650}
651
652impl From<ShortCapitalStringError> for RoleSymbolError {
653 fn from(value: ShortCapitalStringError) -> Self {
654 match value {
655 ShortCapitalStringError::ValueTooLarge(v) => Self::ValueTooLarge(v),
656 ShortCapitalStringError::ValueTooSmall(v) => Self::ValueTooSmall(v),
657 ShortCapitalStringError::InvalidLength(v) => Self::InvalidLength(v),
658 ShortCapitalStringError::InvalidCharacter => Self::InvalidCharacter,
659 ShortCapitalStringError::DataNotFullyDecoded => Self::DataNotFullyDecoded,
660 }
661 }
662}
663
664#[derive(Debug, Error)]
668pub(crate) enum ShortCapitalStringError {
669 #[error("short capital string value {0} is too large")]
670 ValueTooLarge(u64),
671 #[error("short capital string value {0} is too small")]
672 ValueTooSmall(u64),
673 #[error(
674 "short capital string should have length between 1 and 12 characters, but {0} was provided"
675 )]
676 InvalidLength(usize),
677 #[error("short capital string contains an invalid character")]
678 InvalidCharacter,
679 #[error("short capital string data left after decoding the specified number of characters")]
680 DataNotFullyDecoded,
681}
682
683#[derive(Debug, Error)]
687pub enum AssetVaultError {
688 #[error("adding fungible asset amounts would exceed maximum allowed amount")]
689 AddFungibleAssetBalanceError(#[source] AssetError),
690 #[error("provided assets contain duplicates")]
691 DuplicateAsset(#[source] MerkleError),
692 #[error("non fungible asset {0} already exists in the vault")]
693 DuplicateNonFungibleAsset(NonFungibleAsset),
694 #[error("fungible asset {0} does not exist in the vault")]
695 FungibleAssetNotFound(FungibleAsset),
696 #[error("non fungible asset {0} does not exist in the vault")]
697 NonFungibleAssetNotFound(NonFungibleAsset),
698 #[error("subtracting fungible asset amounts would underflow")]
699 SubtractFungibleAssetBalanceError(#[source] AssetError),
700 #[error("maximum number of asset vault leaves exceeded")]
701 MaxLeafEntriesExceeded(#[source] MerkleError),
702}
703
704#[derive(Debug, Error)]
708pub enum PartialAssetVaultError {
709 #[error("partial vault contains invalid asset value {value} at ID {id}")]
710 InvalidAssetForId {
711 id: AssetId,
712 value: Word,
713 #[source]
714 source: AssetError,
715 },
716 #[error("failed to add asset proof")]
717 FailedToAddProof(#[source] MerkleError),
718 #[error("asset is not tracked in the partial vault")]
719 UntrackedAsset(#[source] MerkleError),
720}
721
722#[derive(Debug, Error)]
726pub enum NoteError {
727 #[error("library does not contain a procedure with @note_script attribute")]
728 NoteScriptNoProcedureWithAttribute,
729 #[error("library contains multiple procedures with @note_script attribute")]
730 NoteScriptMultipleProceduresWithAttribute,
731 #[error("procedure at path '{0}' not found in library")]
732 NoteScriptProcedureNotFound(Box<str>),
733 #[error("procedure at path '{0}' does not have @note_script attribute")]
734 NoteScriptProcedureMissingAttribute(Box<str>),
735 #[error("note tag length {0} exceeds the maximum of {max}", max = NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH)]
736 NoteTagLengthTooLarge(u8),
737 #[error("duplicate fungible asset from issuer {0} in note")]
738 DuplicateFungibleAsset(AccountId),
739 #[error("duplicate non fungible asset {0} in note")]
740 DuplicateNonFungibleAsset(NonFungibleAsset),
741 #[error("note type {0} is inconsistent with note tag {1}")]
742 InconsistentNoteTag(NoteType, u64),
743 #[error("adding fungible asset amounts would exceed maximum allowed amount")]
744 AddFungibleAssetBalanceError(#[source] AssetError),
745 #[error("note sender is not a valid account ID")]
746 NoteSenderInvalidAccountId(#[source] AccountIdError),
747 #[error("note execution hint after block variant cannot contain u32::MAX")]
748 NoteExecutionHintAfterBlockCannotBeU32Max,
749 #[error("invalid note execution hint payload {1} for tag {0}")]
750 InvalidNoteExecutionHintPayload(u8, u32),
751 #[error(
752 "note type {0} does not match any of the valid note types {public} or {private}",
753 public = NoteType::Public,
754 private = NoteType::Private,
755 )]
756 UnknownNoteType(Box<str>),
757 #[error("block note tree index {block_note_tree_index} is out of bounds 0..={highest_index}")]
758 BlockNoteTreeIndexOutOfBounds {
759 block_note_tree_index: u16,
760 highest_index: usize,
761 },
762 #[error("note network execution requires a public note but note is of type {0}")]
763 NetworkExecutionRequiresPublicNote(NoteType),
764 #[error("failed to assemble note script:\n{}", PrintDiagnostic::new(.0))]
765 NoteScriptAssemblyError(Report),
766 #[error("failed to deserialize note script")]
767 NoteScriptDeserializationError(#[source] DeserializationError),
768 #[error("note contains {0} assets which exceeds the maximum of {max}", max = NoteAssets::MAX_NUM_ASSETS)]
769 TooManyAssets(usize),
770 #[error("note contains {0} storage items which exceeds the maximum of {max}", max = MAX_NOTE_STORAGE_ITEMS)]
771 TooManyStorageItems(usize),
772 #[error("invalid note storage length: expected {expected} items, got {actual}")]
773 InvalidNoteStorageLength { expected: usize, actual: usize },
774 #[error("note tag requires a public note but the note is of type {0}")]
775 PublicNoteRequired(NoteType),
776 #[error("note attachment content must have at least one word")]
777 NoteAttachmentContentEmpty,
778 #[error(
779 "note attachment content contains {0} words, but the maximum is {max} words",
780 max = NoteAttachment::MAX_NUM_WORDS
781 )]
782 NoteAttachmentContentTooManyWords(usize),
783 #[error(
784 "note attachments contain a total of {0} words, but the maximum allowed is {max} words",
785 max = NoteAttachments::MAX_NUM_WORDS
786 )]
787 NoteAttachmentsTooManyWords(usize),
788 #[error(
789 "attachment size {0} exceeds maximum {max}",
790 max = NoteAttachment::MAX_NUM_WORDS
791 )]
792 NoteAttachmentHeaderSizeExceeded(u8),
793 #[error("{0} attachments were provided but maximum is {max}", max = NoteAttachments::MAX_COUNT)]
794 TooManyAttachments(usize),
795 #[error("attachment scheme {0} exceeds maximum value of {max}", max = NoteAttachmentScheme::MAX)]
796 NoteAttachmentSchemeExceeded(u32),
797 #[error("attachment scheme value 0 is reserved")]
798 NoteAttachmentSchemeZeroReserved,
799 #[error("{error_msg}")]
800 Other {
801 error_msg: Box<str>,
802 source: Option<Box<dyn Error + Send + Sync + 'static>>,
804 },
805}
806
807impl NoteError {
808 pub fn other(message: impl Into<String>) -> Self {
810 let message: String = message.into();
811 Self::Other { error_msg: message.into(), source: None }
812 }
813
814 pub fn other_with_source(
817 message: impl Into<String>,
818 source: impl Error + Send + Sync + 'static,
819 ) -> Self {
820 let message: String = message.into();
821 Self::Other {
822 error_msg: message.into(),
823 source: Some(Box::new(source)),
824 }
825 }
826}
827
828#[derive(Debug, Error)]
832pub enum PartialBlockchainError {
833 #[error(
834 "block num {block_num} exceeds chain length {chain_length} implied by the partial blockchain"
835 )]
836 BlockNumTooBig {
837 chain_length: usize,
838 block_num: BlockNumber,
839 },
840
841 #[error("duplicate block {block_num} in partial blockchain")]
842 DuplicateBlock { block_num: BlockNumber },
843
844 #[error("partial blockchain does not track authentication paths for block {block_num}")]
845 UntrackedBlock { block_num: BlockNumber },
846
847 #[error(
848 "provided block header with number {block_num} and commitment {block_commitment} is not tracked by partial MMR"
849 )]
850 BlockHeaderCommitmentMismatch {
851 block_num: BlockNumber,
852 block_commitment: Word,
853 source: MmrError,
854 },
855}
856
857impl PartialBlockchainError {
858 pub fn block_num_too_big(chain_length: usize, block_num: BlockNumber) -> Self {
859 Self::BlockNumTooBig { chain_length, block_num }
860 }
861
862 pub fn duplicate_block(block_num: BlockNumber) -> Self {
863 Self::DuplicateBlock { block_num }
864 }
865
866 pub fn untracked_block(block_num: BlockNumber) -> Self {
867 Self::UntrackedBlock { block_num }
868 }
869}
870
871#[derive(Debug, Error)]
875pub enum TransactionScriptError {
876 #[error("failed to assemble transaction script:\n{}", PrintDiagnostic::new(.0))]
877 AssemblyError(Report),
878 #[error("failed to convert package to transaction script:\n{}", PrintDiagnostic::new(.0))]
879 PackageNotProgram(Report),
880 #[error("library does not contain a procedure with @transaction_script attribute")]
881 NoProcedureWithAttribute,
882 #[error("library contains multiple procedures with @transaction_script attribute")]
883 MultipleProceduresWithAttribute,
884 #[error("procedure at path '{0}' not found in library")]
885 ProcedureNotFound(Box<str>),
886 #[error("procedure at path '{0}' does not have @transaction_script attribute")]
887 ProcedureMissingAttribute(Box<str>),
888}
889
890#[derive(Debug, Error)]
894pub enum TransactionInputError {
895 #[error("transaction input note with nullifier {0} is a duplicate")]
896 DuplicateInputNote(Nullifier),
897 #[error("partial blockchain has length {actual} which does not match block number {expected}")]
898 InconsistentChainLength {
899 expected: BlockNumber,
900 actual: BlockNumber,
901 },
902 #[error(
903 "partial blockchain has commitment {actual} which does not match the block header's chain commitment {expected}"
904 )]
905 InconsistentChainCommitment { expected: Word, actual: Word },
906 #[error("block in which input note with id {0} was created is not in partial blockchain")]
907 InputNoteBlockNotInPartialBlockchain(NoteId),
908 #[error("input note with id {0} was not created in block {1}")]
909 InputNoteNotInBlock(NoteId, BlockNumber),
910 #[error(
911 "total number of input notes is {0} which exceeds the maximum of {MAX_INPUT_NOTES_PER_TX}"
912 )]
913 TooManyInputNotes(usize),
914}
915
916#[derive(Debug, Error)]
920pub enum TransactionInputsExtractionError {
921 #[error("specified foreign account id matches the transaction input's account id")]
922 AccountNotForeign,
923 #[error("foreign account data not found in advice map for account {0}")]
924 ForeignAccountNotFound(AccountId),
925 #[error("foreign account code not found for account {0}")]
926 ForeignAccountCodeNotFound(AccountId),
927 #[error("storage header data not found in advice map for account {0}")]
928 StorageHeaderNotFound(AccountId),
929 #[error("failed to handle account data")]
930 AccountError(#[from] AccountError),
931 #[error("failed to handle merkle data")]
932 MerkleError(#[from] MerkleError),
933 #[error("failed to handle account tree data")]
934 AccountTreeError(#[from] AccountTreeError),
935 #[error("missing vault root from Merkle store")]
936 MissingVaultRoot,
937 #[error("missing storage map root from Merkle store")]
938 MissingMapRoot,
939 #[error("failed to construct SMT proof")]
940 SmtProofError(#[from] SmtProofError),
941 #[error("failed to construct an asset")]
942 AssetError(#[from] AssetError),
943 #[error("failed to handle storage map data")]
944 StorageMapError(#[from] StorageMapError),
945 #[error("failed to convert elements to leaf index: {0}")]
946 LeafConversionError(String),
947 #[error("failed to construct SMT leaf")]
948 SmtLeafError(#[from] SmtLeafError),
949}
950
951#[derive(Debug, Error)]
955pub enum TransactionOutputError {
956 #[error("transaction output note with id {0} is a duplicate")]
957 DuplicateOutputNote(NoteId),
958 #[error("final account commitment is not in the advice map")]
959 FinalAccountCommitmentMissingInAdviceMap,
960 #[error("failed to parse final account header")]
961 FinalAccountHeaderParseFailure(#[source] AccountError),
962 #[error(
963 "output notes commitment {expected} from kernel does not match computed commitment {actual}"
964 )]
965 OutputNotesCommitmentInconsistent { expected: Word, actual: Word },
966 #[error("transaction kernel output stack is invalid: {0}")]
967 OutputStackInvalid(String),
968 #[error(
969 "total number of output notes is {0} which exceeds the maximum of {MAX_OUTPUT_NOTES_PER_TX}"
970 )]
971 TooManyOutputNotes(usize),
972 #[error("failed to process account update commitment: {0}")]
973 AccountUpdateCommitment(Box<str>),
974}
975
976#[derive(Debug, Error)]
983pub enum OutputNoteError {
984 #[error("note with id {0} is private but expected a public note")]
985 NoteIsPrivate(NoteId),
986 #[error("note with id {0} is public but expected a private note")]
987 NoteIsPublic(NoteId),
988 #[error(
989 "public note with id {note_id} has size {note_size} bytes which exceeds maximum note size of {NOTE_MAX_SIZE}"
990 )]
991 NoteSizeLimitExceeded { note_id: NoteId, note_size: usize },
992}
993
994#[derive(Debug, Error)]
998pub enum TransactionEventError {
999 #[error("event id {0} is not a valid transaction event")]
1000 InvalidTransactionEvent(EventId),
1001}
1002
1003#[derive(Debug, Error)]
1007pub enum TransactionTraceParsingError {
1008 #[error("trace id {0} is an unknown transaction kernel trace")]
1009 UnknownTransactionTrace(u32),
1010}
1011
1012#[derive(Debug, Error)]
1016pub enum ProvenTransactionError {
1017 #[error(
1018 "proven transaction's final account commitment {tx_final_commitment} and account details commitment {details_commitment} must match"
1019 )]
1020 AccountFinalCommitmentMismatch {
1021 tx_final_commitment: Word,
1022 details_commitment: Word,
1023 },
1024 #[error(
1025 "proven transaction's final account ID {tx_account_id} and account details id {details_account_id} must match"
1026 )]
1027 AccountIdMismatch {
1028 tx_account_id: AccountId,
1029 details_account_id: AccountId,
1030 },
1031 #[error("failed to construct input notes for proven transaction")]
1032 InputNotesError(TransactionInputError),
1033 #[error("private account {0} should not have account details")]
1034 PrivateAccountWithDetails(AccountId),
1035 #[error("account {0} with public state is missing its account details")]
1036 PublicStateAccountMissingDetails(AccountId),
1037 #[error("new account {id} with public state must be accompanied by a full state patch")]
1038 NewPublicStateAccountRequiresFullStatePatch { id: AccountId, source: AccountError },
1039 #[error(
1040 "existing account {0} with public state should only provide delta updates instead of full details"
1041 )]
1042 ExistingPublicStateAccountRequiresDeltaDetails(AccountId),
1043 #[error("failed to construct output notes for proven transaction")]
1044 OutputNotesError(#[source] TransactionOutputError),
1045 #[error(
1046 "account update of size {update_size} for account {account_id} exceeds maximum update size of {ACCOUNT_UPDATE_MAX_SIZE}"
1047 )]
1048 AccountUpdateSizeLimitExceeded {
1049 account_id: AccountId,
1050 update_size: usize,
1051 },
1052 #[error("proven transaction neither changed the account state, nor consumed any notes")]
1053 EmptyTransaction,
1054 #[error("failed to validate account patch in transaction account update")]
1055 AccountPatchCommitmentMismatch(#[source] Box<dyn Error + Send + Sync + 'static>),
1056 #[error("note with id {0} is both created and consumed by the transaction")]
1057 NoteCreatedAndConsumed(NoteId),
1058}
1059
1060#[derive(Debug, Error)]
1064pub enum ProposedBatchError {
1065 #[error("failed to verify transaction {transaction_id} in transaction batch")]
1066 TransactionVerificationFailed {
1067 transaction_id: TransactionId,
1068 source: TransactionVerifierError,
1069 },
1070
1071 #[error(
1072 "transaction batch has {0} input notes but at most {MAX_INPUT_NOTES_PER_BATCH} are allowed"
1073 )]
1074 TooManyInputNotes(usize),
1075
1076 #[error(
1077 "transaction batch has {0} output notes but at most {MAX_OUTPUT_NOTES_PER_BATCH} are allowed"
1078 )]
1079 TooManyOutputNotes(usize),
1080
1081 #[error(
1082 "transaction batch has {0} account updates but at most {MAX_ACCOUNTS_PER_BATCH} are allowed"
1083 )]
1084 TooManyAccountUpdates(usize),
1085
1086 #[error(
1087 "transaction {transaction_id} expires at block number {transaction_expiration_num} which is not greater than the number of the batch's reference block {reference_block_num}"
1088 )]
1089 ExpiredTransaction {
1090 transaction_id: TransactionId,
1091 transaction_expiration_num: BlockNumber,
1092 reference_block_num: BlockNumber,
1093 },
1094
1095 #[error("transaction batch must contain at least one transaction")]
1096 EmptyTransactionBatch,
1097
1098 #[error("transaction {transaction_id} appears twice in the proposed batch input")]
1099 DuplicateTransaction { transaction_id: TransactionId },
1100
1101 #[error(
1102 "transaction {second_transaction_id} consumes the note with nullifier {note_nullifier} that is also consumed by another transaction {first_transaction_id} in the batch"
1103 )]
1104 DuplicateInputNote {
1105 note_nullifier: Nullifier,
1106 first_transaction_id: TransactionId,
1107 second_transaction_id: TransactionId,
1108 },
1109
1110 #[error(
1111 "transaction {second_transaction_id} creates the note with id {note_id} that is also created by another transaction {first_transaction_id} in the batch"
1112 )]
1113 DuplicateOutputNote {
1114 note_id: NoteId,
1115 first_transaction_id: TransactionId,
1116 second_transaction_id: TransactionId,
1117 },
1118
1119 #[error(
1120 "transaction {consumed_by} that consumes the note with ID {note_id} must be ordered before transaction {created_by} that creates the note"
1121 )]
1122 NoteConsumedBeforeCreated {
1123 note_id: NoteId,
1124 consumed_by: TransactionId,
1125 created_by: TransactionId,
1126 },
1127
1128 #[error("failed to merge transaction patch into account {account_id}")]
1129 AccountUpdateError {
1130 account_id: AccountId,
1131 source: BatchAccountUpdateError,
1132 },
1133
1134 #[error(
1135 "unable to prove unauthenticated note inclusion because block {block_number} in which note with id {note_id} was created is not in partial blockchain"
1136 )]
1137 UnauthenticatedInputNoteBlockNotInPartialBlockchain {
1138 block_number: BlockNumber,
1139 note_id: NoteId,
1140 },
1141
1142 #[error(
1143 "unable to prove unauthenticated note inclusion of note {note_id} in block {block_num}"
1144 )]
1145 UnauthenticatedNoteAuthenticationFailed {
1146 note_id: NoteId,
1147 block_num: BlockNumber,
1148 source: MerkleError,
1149 },
1150
1151 #[error("partial blockchain has length {actual} which does not match block number {expected}")]
1152 InconsistentChainLength {
1153 expected: BlockNumber,
1154 actual: BlockNumber,
1155 },
1156
1157 #[error(
1158 "partial blockchain has root {actual} which does not match block header's root {expected}"
1159 )]
1160 InconsistentChainRoot { expected: Word, actual: Word },
1161
1162 #[error(
1163 "block {block_num} referenced by transaction {transaction_id} is not in the partial blockchain"
1164 )]
1165 MissingTransactionReferenceBlock {
1166 transaction_id: TransactionId,
1167 block_num: BlockNumber,
1168 },
1169
1170 #[error(
1171 "transaction {transaction_id} references block {block_num} with commitment {actual_block_commitment}, but the block in the chain with the same number has commitment {expected_block_commitment}"
1172 )]
1173 TransactionReferenceBlockCommitmentMismatch {
1174 transaction_id: TransactionId,
1175 block_num: BlockNumber,
1176 expected_block_commitment: Word,
1177 actual_block_commitment: Word,
1178 },
1179}
1180
1181#[derive(Debug, Error)]
1185pub enum ProvenBatchError {
1186 #[error(
1187 "batch expiration block number {batch_expiration_block_num} is not greater than the reference block number {reference_block_num}"
1188 )]
1189 InvalidBatchExpirationBlockNum {
1190 batch_expiration_block_num: BlockNumber,
1191 reference_block_num: BlockNumber,
1192 },
1193 #[error("batch kernel execution failed")]
1194 BatchKernelExecutionFailed(#[source] ExecutionError),
1195 #[error("batch kernel produced an invalid output stack")]
1196 BatchKernelOutputInvalid(#[source] BatchOutputError),
1197}
1198
1199#[derive(Debug, Error)]
1203pub enum BatchOutputError {
1204 #[error("batch kernel output stack is invalid: {0}")]
1205 OutputStackInvalid(String),
1206 #[error("batch expiration block number {0} does not fit into a u32")]
1207 ExpirationBlockNumberTooLarge(Felt),
1208}
1209
1210#[derive(Debug, Error)]
1214pub enum ProposedBlockError {
1215 #[error("block must contain at least one transaction batch")]
1216 EmptyBlock,
1217
1218 #[error("block must contain at most {MAX_BATCHES_PER_BLOCK} transaction batches")]
1219 TooManyBatches,
1220
1221 #[error(
1222 "batch {batch_id} expired at block {batch_expiration_block_num} but the current block number is {current_block_num}"
1223 )]
1224 ExpiredBatch {
1225 batch_id: BatchId,
1226 batch_expiration_block_num: BlockNumber,
1227 current_block_num: BlockNumber,
1228 },
1229
1230 #[error("batch {batch_id} appears twice in the block inputs")]
1231 DuplicateBatch { batch_id: BatchId },
1232
1233 #[error(
1234 "batch {second_batch_id} consumes the note with nullifier {note_nullifier} that is also consumed by another batch {first_batch_id} in the block"
1235 )]
1236 DuplicateInputNote {
1237 note_nullifier: Nullifier,
1238 first_batch_id: BatchId,
1239 second_batch_id: BatchId,
1240 },
1241
1242 #[error(
1243 "batch {second_batch_id} creates the note with ID {note_id} that is also created by another batch {first_batch_id} in the block"
1244 )]
1245 DuplicateOutputNote {
1246 note_id: NoteId,
1247 first_batch_id: BatchId,
1248 second_batch_id: BatchId,
1249 },
1250
1251 #[error(
1252 "batch {consumed_by} that consumes the note with ID {note_id} must be ordered before batch {created_by} that creates the note"
1253 )]
1254 NoteConsumedBeforeCreated {
1255 note_id: NoteId,
1256 consumed_by: BatchId,
1257 created_by: BatchId,
1258 },
1259
1260 #[error(
1261 "timestamp {provided_timestamp} does not increase monotonically compared to timestamp {previous_timestamp} from the previous block header"
1262 )]
1263 TimestampDoesNotIncreaseMonotonically {
1264 provided_timestamp: u32,
1265 previous_timestamp: u32,
1266 },
1267
1268 #[error(
1269 "account {account_id} is updated from the same initial state commitment {initial_state_commitment} by multiple conflicting batches with IDs {first_batch_id} and {second_batch_id}"
1270 )]
1271 ConflictingBatchesUpdateSameAccount {
1272 account_id: AccountId,
1273 initial_state_commitment: Word,
1274 first_batch_id: BatchId,
1275 second_batch_id: BatchId,
1276 },
1277
1278 #[error(
1279 "partial blockchain has length {chain_length} which does not match the block number {prev_block_num} of the previous block referenced by the to-be-built block"
1280 )]
1281 ChainLengthNotEqualToPreviousBlockNumber {
1282 chain_length: BlockNumber,
1283 prev_block_num: BlockNumber,
1284 },
1285
1286 #[error(
1287 "partial blockchain has commitment {chain_commitment} which does not match the chain commitment {prev_block_chain_commitment} of the previous block {prev_block_num}"
1288 )]
1289 ChainRootNotEqualToPreviousBlockChainCommitment {
1290 chain_commitment: Word,
1291 prev_block_chain_commitment: Word,
1292 prev_block_num: BlockNumber,
1293 },
1294
1295 #[error(
1296 "partial blockchain is missing block {reference_block_num} referenced by batch {batch_id} in the block"
1297 )]
1298 BatchReferenceBlockMissingFromChain {
1299 reference_block_num: BlockNumber,
1300 batch_id: BatchId,
1301 },
1302
1303 #[error(
1304 "failed to prove unauthenticated note inclusion because block {block_number} in which note with id {note_id} was created is not in partial blockchain"
1305 )]
1306 UnauthenticatedInputNoteBlockNotInPartialBlockchain {
1307 block_number: BlockNumber,
1308 note_id: NoteId,
1309 },
1310
1311 #[error(
1312 "failed to prove unauthenticated note inclusion of note {note_id} in block {block_num}"
1313 )]
1314 UnauthenticatedNoteAuthenticationFailed {
1315 note_id: NoteId,
1316 block_num: BlockNumber,
1317 source: MerkleError,
1318 },
1319
1320 #[error(
1321 "unauthenticated note with nullifier {nullifier} was not created in the same block and no inclusion proof to authenticate it was provided"
1322 )]
1323 UnauthenticatedNoteConsumed { nullifier: Nullifier },
1324
1325 #[error("block inputs do not contain a proof of inclusion for account {0}")]
1326 MissingAccountWitness(AccountId),
1327
1328 #[error(
1329 "account {account_id} with state {state_commitment} cannot transition to any of the remaining states {}",
1330 remaining_state_commitments.iter().map(Word::to_hex).collect::<Vec<_>>().join(", ")
1331 )]
1332 InconsistentAccountStateTransition {
1333 account_id: AccountId,
1334 state_commitment: Word,
1335 remaining_state_commitments: Vec<Word>,
1336 },
1337
1338 #[error("no proof for nullifier {0} was provided")]
1339 NullifierProofMissing(Nullifier),
1340
1341 #[error("note with nullifier {0} is already spent")]
1342 NullifierSpent(Nullifier),
1343
1344 #[error("failed to merge transaction patch into account {account_id}")]
1345 AccountUpdateError {
1346 account_id: AccountId,
1347 source: Box<AccountPatchError>,
1348 },
1349
1350 #[error("failed to track account witness")]
1351 AccountWitnessTracking { source: AccountTreeError },
1352
1353 #[error(
1354 "account tree root of the previous block header is {prev_block_account_root} but the root of the partial tree computed from account witnesses is {stale_account_root}, indicating that the witnesses are stale"
1355 )]
1356 StaleAccountTreeRoot {
1357 prev_block_account_root: Word,
1358 stale_account_root: Word,
1359 },
1360
1361 #[error("account ID prefix already exists in the tree")]
1362 AccountIdPrefixDuplicate { source: AccountTreeError },
1363
1364 #[error(
1365 "nullifier tree root of the previous block header is {prev_block_nullifier_root} but the root of the partial tree computed from nullifier witnesses is {stale_nullifier_root}, indicating that the witnesses are stale"
1366 )]
1367 StaleNullifierTreeRoot {
1368 prev_block_nullifier_root: Word,
1369 stale_nullifier_root: Word,
1370 },
1371
1372 #[error("nullifier witness has a different root than the current nullifier tree root")]
1373 NullifierWitnessRootMismatch(NullifierTreeError),
1374}
1375
1376#[derive(Debug, Error)]
1380pub enum NullifierTreeError {
1381 #[error(
1382 "entries passed to nullifier tree contain multiple block numbers for the same nullifier"
1383 )]
1384 DuplicateNullifierBlockNumbers(#[source] MerkleError),
1385
1386 #[error("attempt to mark nullifier {0} as spent but it is already spent")]
1387 NullifierAlreadySpent(Nullifier),
1388
1389 #[error("maximum number of nullifier tree leaves exceeded")]
1390 MaxLeafEntriesExceeded(#[source] MerkleError),
1391
1392 #[error("nullifier {nullifier} is not tracked by the partial nullifier tree")]
1393 UntrackedNullifier {
1394 nullifier: Nullifier,
1395 source: MerkleError,
1396 },
1397
1398 #[error("new tree root after nullifier witness insertion does not match previous tree root")]
1399 TreeRootConflict(#[source] MerkleError),
1400
1401 #[error("failed to compute nullifier tree mutations")]
1402 ComputeMutations(#[source] MerkleError),
1403
1404 #[error("invalid nullifier block number")]
1405 InvalidNullifierBlockNumber(Word),
1406}
1407
1408#[derive(Debug, Error)]
1412pub enum AuthSchemeError {
1413 #[error("auth scheme identifier `{0}` is not valid")]
1414 InvalidAuthSchemeIdentifier(String),
1415}
1416
1417#[derive(Debug, Error)]
1421pub enum TransactionVerifierError {
1422 #[error("failed to verify transaction")]
1423 TransactionVerificationFailed(#[source] VerificationError),
1424 #[error("transaction proof security level is {actual} but must be at least {expected_minimum}")]
1425 InsufficientProofSecurityLevel { actual: u32, expected_minimum: u32 },
1426}