bee_block/
error.rs

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