iota_stardust_types/block/
error.rs

1// Copyright (c) 2026 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use alloc::string::{FromUtf8Error, String};
5use core::{convert::Infallible, fmt};
6
7use crypto::Error as CryptoError;
8use prefix_hex::Error as HexError;
9use primitive_types::U256;
10
11use crate::block::output::{
12    AliasId, ChainId, MetadataFeatureLength, NativeTokenCount, NftId, OutputIndex,
13    StateMetadataLength, TagFeatureLength, feature::FeatureCount,
14    unlock_condition::UnlockConditionCount,
15};
16
17/// Error occurring when creating/parsing/validating blocks.
18#[derive(Debug, PartialEq, Eq)]
19#[allow(missing_docs)]
20pub enum Error {
21    ConsumedAmountOverflow,
22    ConsumedNativeTokensAmountOverflow,
23    CreatedAmountOverflow,
24    CreatedNativeTokensAmountOverflow,
25    Crypto(CryptoError),
26    DuplicateSignatureUnlock(u16),
27    ExpirationUnlockConditionZero,
28    FeaturesNotUniqueSorted,
29    InputUnlockCountMismatch {
30        input_count: usize,
31        unlock_count: usize,
32    },
33    InvalidAddress,
34    InvalidAddressKind(u8),
35    InvalidBech32Hrp(String),
36    InvalidStorageDepositAmount(u64),
37    // The above is used by `Packable` to denote out-of-range values. The following denotes the
38    // actual amount.
39    InsufficientStorageDepositAmount {
40        amount: u64,
41        required: u64,
42    },
43    StorageDepositReturnExceedsOutputAmount {
44        deposit: u64,
45        amount: u64,
46    },
47    InsufficientStorageDepositReturnAmount {
48        deposit: u64,
49        required: u64,
50    },
51    InvalidEssenceKind(u8),
52    InvalidFeatureCount(<FeatureCount as TryFrom<usize>>::Error),
53    InvalidFeatureKind(u8),
54    InvalidFoundryOutputSupply {
55        minted: U256,
56        melted: U256,
57        max: U256,
58    },
59    Hex(HexError),
60    InvalidInputKind(u8),
61    InvalidInputOutputIndex(<OutputIndex as TryFrom<u16>>::Error),
62    InvalidBlockLength(usize),
63    InvalidStateMetadataLength(<StateMetadataLength as TryFrom<usize>>::Error),
64    InvalidMetadataFeatureLength(<MetadataFeatureLength as TryFrom<usize>>::Error),
65    InvalidMilestoneOptionKind(u8),
66    InvalidBinaryParametersLength(packable::bounded::InvalidBoundedU16<0, 8192>),
67    InvalidBinaryParametersLengthValue(usize),
68    InvalidMigratedFundsEntryAmount(u64),
69    InvalidNativeTokenCount(<NativeTokenCount as TryFrom<usize>>::Error),
70    InvalidNetworkName(FromUtf8Error),
71    InvalidOutputAmount(u64),
72    InvalidOutputKind(u8),
73    InvalidPayloadKind(u32),
74    InvalidPayloadLength {
75        expected: usize,
76        actual: usize,
77    },
78    InvalidReceiptFundsSum(u128),
79    InvalidSignature,
80    InvalidSignatureKind(u8),
81    InvalidStringPrefix(<u8 as TryFrom<usize>>::Error),
82    InvalidTagFeatureLength(<TagFeatureLength as TryFrom<usize>>::Error),
83    InvalidTailTransactionHash,
84    InvalidTokenSchemeKind(u8),
85    InvalidTransactionAmountSum(u128),
86    InvalidTransactionNativeTokensCount(u16),
87    InvalidTreasuryOutputAmount(u64),
88    InvalidUnlockKind(u8),
89    InvalidUnlockReference(u16),
90    InvalidUnlockAlias(u16),
91    InvalidUnlockNft(u16),
92    InvalidUnlockConditionCount(<UnlockConditionCount as TryFrom<usize>>::Error),
93    InvalidUnlockConditionKind(u8),
94    InvalidFoundryZeroSerialNumber,
95    MilestonePublicKeysSignaturesCountMismatch {
96        key_count: usize,
97        sig_count: usize,
98    },
99    MilestoneOptionsNotUniqueSorted,
100    MilestoneSignaturesNotUniqueSorted,
101    MissingAddressUnlockCondition,
102    MissingGovernorUnlockCondition,
103    MissingStateControllerUnlockCondition,
104    NativeTokensNotUniqueSorted,
105    NativeTokensNullAmount,
106    NativeTokensOverflow,
107    NetworkIdMismatch {
108        expected: u64,
109        actual: u64,
110    },
111    NonZeroStateIndexOrFoundryCounter,
112    ParentsNotUniqueSorted,
113    ProtocolVersionMismatch {
114        expected: u8,
115        actual: u8,
116    },
117    NonceNotFound,
118    ReceiptFundsNotUniqueSorted,
119    RemainingBytesAfterBlock,
120    SelfControlledAliasOutput(AliasId),
121    SelfDepositNft(NftId),
122    SignaturePublicKeyMismatch {
123        expected: String,
124        actual: String,
125    },
126    StorageDepositReturnOverflow,
127    TailTransactionHashNotUnique {
128        previous: usize,
129        current: usize,
130    },
131    TimelockUnlockConditionZero,
132    UnallowedFeature {
133        index: usize,
134        kind: u8,
135    },
136    UnallowedUnlockCondition {
137        index: usize,
138        kind: u8,
139    },
140    UnlockConditionsNotUniqueSorted,
141    UnsupportedOutputKind(u8),
142    DuplicateOutputChain(ChainId),
143    InvalidField(&'static str),
144}
145
146#[cfg(feature = "std")]
147impl std::error::Error for Error {}
148
149impl fmt::Display for Error {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        match self {
152            Self::ConsumedAmountOverflow => write!(f, "consumed amount overflow"),
153            Self::ConsumedNativeTokensAmountOverflow => {
154                write!(f, "consumed native tokens amount overflow")
155            }
156            Self::CreatedAmountOverflow => write!(f, "created amount overflow"),
157            Self::CreatedNativeTokensAmountOverflow => {
158                write!(f, "created native tokens amount overflow")
159            }
160            Self::Crypto(e) => write!(f, "cryptographic error: {e}"),
161            Self::DuplicateSignatureUnlock(index) => {
162                write!(f, "duplicate signature unlock at index: {index}")
163            }
164            Self::ExpirationUnlockConditionZero => {
165                write!(
166                    f,
167                    "expiration unlock condition with milestone index and timestamp set to 0",
168                )
169            }
170            Self::FeaturesNotUniqueSorted => write!(f, "features are not unique and/or sorted"),
171            Self::InputUnlockCountMismatch {
172                input_count,
173                unlock_count,
174            } => {
175                write!(
176                    f,
177                    "input count and unlock count mismatch: {input_count} != {unlock_count}",
178                )
179            }
180            Self::InvalidAddress => write!(f, "invalid address provided"),
181            Self::InvalidAddressKind(k) => write!(f, "invalid address kind: {k}"),
182            Self::InvalidBech32Hrp(hrp) => write!(f, "invalid bech32 hrp: {hrp}"),
183            Self::InvalidStorageDepositAmount(amount) => {
184                write!(f, "invalid storage deposit amount: {amount}")
185            }
186            Self::InsufficientStorageDepositAmount { amount, required } => {
187                write!(
188                    f,
189                    "insufficient output amount for storage deposit: {amount} (should be at least {required})"
190                )
191            }
192            Self::InsufficientStorageDepositReturnAmount { deposit, required } => {
193                write!(
194                    f,
195                    "the return deposit ({deposit}) must be greater than the minimum storage deposit ({required})"
196                )
197            }
198            Self::StorageDepositReturnExceedsOutputAmount { deposit, amount } => write!(
199                f,
200                "storage deposit return of {deposit} exceeds the original output amount of {amount}"
201            ),
202            Self::InvalidEssenceKind(k) => write!(f, "invalid essence kind: {k}"),
203            Self::InvalidFeatureCount(count) => write!(f, "invalid feature count: {count}"),
204            Self::InvalidFeatureKind(k) => write!(f, "invalid feature kind: {k}"),
205            Self::InvalidFoundryOutputSupply {
206                minted,
207                melted,
208                max,
209            } => write!(
210                f,
211                "invalid foundry output supply: minted {minted}, melted {melted} max {max}",
212            ),
213            Self::Hex(error) => write!(f, "hex error: {error}"),
214            Self::InvalidInputKind(k) => write!(f, "invalid input kind: {k}"),
215            Self::InvalidInputOutputIndex(index) => {
216                write!(f, "invalid input or output index: {index}")
217            }
218            Self::InvalidBlockLength(length) => write!(f, "invalid block length {length}"),
219            Self::InvalidStateMetadataLength(length) => {
220                write!(f, "invalid state metadata length {length}")
221            }
222            Self::InvalidMetadataFeatureLength(length) => {
223                write!(f, "invalid metadata feature length {length}")
224            }
225
226            Self::InvalidMilestoneOptionKind(k) => write!(f, "invalid milestone option kind: {k}"),
227            Self::InvalidBinaryParametersLength(length) => {
228                write!(f, "invalid binary parameters length: {length}")
229            }
230            Self::InvalidBinaryParametersLengthValue(length) => {
231                write!(f, "invalid binary parameters length: {length}")
232            }
233            Self::InvalidMigratedFundsEntryAmount(amount) => {
234                write!(f, "invalid migrated funds entry amount: {amount}")
235            }
236            Self::InvalidNativeTokenCount(count) => {
237                write!(f, "invalid native token count: {count}")
238            }
239            Self::InvalidNetworkName(err) => write!(f, "invalid network name: {err}"),
240            Self::InvalidOutputAmount(amount) => write!(f, "invalid output amount: {amount}"),
241            Self::InvalidOutputKind(k) => write!(f, "invalid output kind: {k}"),
242
243            Self::InvalidPayloadKind(k) => write!(f, "invalid payload kind: {k}"),
244            Self::InvalidPayloadLength { expected, actual } => {
245                write!(
246                    f,
247                    "invalid payload length: expected {expected} but got {actual}"
248                )
249            }
250
251            Self::InvalidReceiptFundsSum(sum) => write!(f, "invalid receipt amount sum: {sum}"),
252            Self::InvalidSignature => write!(f, "invalid signature provided"),
253            Self::InvalidSignatureKind(k) => write!(f, "invalid signature kind: {k}"),
254            Self::InvalidStringPrefix(p) => write!(f, "invalid string prefix: {p}"),
255            Self::InvalidTagFeatureLength(length) => {
256                write!(f, "invalid tag feature length {length}")
257            }
258            Self::InvalidTailTransactionHash => write!(f, "invalid tail transaction hash"),
259            Self::InvalidTokenSchemeKind(k) => write!(f, "invalid token scheme kind {k}"),
260            Self::InvalidTransactionAmountSum(value) => {
261                write!(f, "invalid transaction amount sum: {value}")
262            }
263            Self::InvalidTransactionNativeTokensCount(count) => {
264                write!(f, "invalid transaction native tokens count: {count}")
265            }
266            Self::InvalidTreasuryOutputAmount(amount) => {
267                write!(f, "invalid treasury amount: {amount}")
268            }
269            Self::InvalidUnlockKind(k) => write!(f, "invalid unlock kind: {k}"),
270            Self::InvalidUnlockReference(index) => {
271                write!(f, "invalid unlock reference: {index}")
272            }
273            Self::InvalidUnlockAlias(index) => {
274                write!(f, "invalid unlock alias: {index}")
275            }
276            Self::InvalidUnlockNft(index) => {
277                write!(f, "invalid unlock nft: {index}")
278            }
279            Self::InvalidUnlockConditionCount(count) => {
280                write!(f, "invalid unlock condition count: {count}")
281            }
282            Self::InvalidUnlockConditionKind(k) => write!(f, "invalid unlock condition kind: {k}"),
283            Self::InvalidFoundryZeroSerialNumber => write!(f, "invalid foundry zero serial number"),
284
285            Self::MilestonePublicKeysSignaturesCountMismatch {
286                key_count,
287                sig_count,
288            } => {
289                write!(
290                    f,
291                    "milestone public keys and signatures count mismatch: {key_count} != {sig_count}",
292                )
293            }
294            Self::MilestoneOptionsNotUniqueSorted => {
295                write!(f, "milestone options are not unique and/or sorted")
296            }
297            Self::MilestoneSignaturesNotUniqueSorted => {
298                write!(f, "milestone signatures are not unique and/or sorted")
299            }
300            Self::MissingAddressUnlockCondition => write!(f, "missing address unlock condition"),
301            Self::MissingGovernorUnlockCondition => write!(f, "missing governor unlock condition"),
302            Self::MissingStateControllerUnlockCondition => {
303                write!(f, "missing state controller unlock condition")
304            }
305            Self::NativeTokensNotUniqueSorted => {
306                write!(f, "native tokens are not unique and/or sorted")
307            }
308            Self::NativeTokensNullAmount => write!(f, "native tokens null amount"),
309            Self::NativeTokensOverflow => write!(f, "native tokens overflow"),
310            Self::NetworkIdMismatch { expected, actual } => {
311                write!(
312                    f,
313                    "network ID mismatch: expected {expected} but got {actual}"
314                )
315            }
316            Self::NonZeroStateIndexOrFoundryCounter => {
317                write!(
318                    f,
319                    "non zero state index or foundry counter while alias ID is all zero"
320                )
321            }
322            Self::ParentsNotUniqueSorted => {
323                write!(f, "parents are not unique and/or sorted")
324            }
325            Self::ProtocolVersionMismatch { expected, actual } => {
326                write!(
327                    f,
328                    "protocol version mismatch: expected {expected} but got {actual}"
329                )
330            }
331            Self::NonceNotFound => {
332                write!(f, "nonce miner could not find a nonce")
333            }
334            Self::ReceiptFundsNotUniqueSorted => {
335                write!(f, "receipt funds are not unique and/or sorted")
336            }
337            Self::RemainingBytesAfterBlock => {
338                write!(f, "remaining bytes after block")
339            }
340            Self::SelfControlledAliasOutput(alias_id) => {
341                write!(f, "self controlled alias output, alias ID {alias_id}")
342            }
343            Self::SelfDepositNft(nft_id) => {
344                write!(f, "self deposit nft output, NFT ID {nft_id}")
345            }
346            Self::SignaturePublicKeyMismatch { expected, actual } => {
347                write!(
348                    f,
349                    "signature public key mismatch: expected {expected} but got {actual}",
350                )
351            }
352            Self::StorageDepositReturnOverflow => {
353                write!(f, "storage deposit return overflow",)
354            }
355            Self::TailTransactionHashNotUnique { previous, current } => {
356                write!(
357                    f,
358                    "tail transaction hash is not unique at indices: {previous} and {current}",
359                )
360            }
361            Self::TimelockUnlockConditionZero => {
362                write!(
363                    f,
364                    "timelock unlock condition with milestone index and timestamp set to 0",
365                )
366            }
367            Self::UnallowedFeature { index, kind } => {
368                write!(f, "unallowed feature at index {index} with kind {kind}")
369            }
370            Self::UnallowedUnlockCondition { index, kind } => {
371                write!(
372                    f,
373                    "unallowed unlock condition at index {index} with kind {kind}"
374                )
375            }
376            Self::UnlockConditionsNotUniqueSorted => {
377                write!(f, "unlock conditions are not unique and/or sorted")
378            }
379            Self::UnsupportedOutputKind(k) => write!(f, "unsupported output kind: {k}"),
380            Self::DuplicateOutputChain(chain_id) => write!(f, "duplicate output chain {chain_id}"),
381            Self::InvalidField(field) => write!(f, "invalid field: {field}"),
382        }
383    }
384}
385
386impl From<CryptoError> for Error {
387    fn from(error: CryptoError) -> Self {
388        Self::Crypto(error)
389    }
390}
391
392impl From<Infallible> for Error {
393    fn from(error: Infallible) -> Self {
394        match error {}
395    }
396}