substrate_parser/
error.rs

1//! Errors.
2use external_memory_tools::{BufferError, ExternalMemory};
3use primitive_types::H256;
4
5use crate::std::string::String;
6
7#[cfg(feature = "std")]
8use std::{
9    error::Error,
10    fmt::{Display, Formatter, Result as FmtResult},
11};
12
13#[cfg(not(feature = "std"))]
14use core::fmt::{Display, Formatter, Result as FmtResult};
15
16use crate::traits::AsMetadata;
17
18/// Errors in signable transactions parsing.
19#[derive(Debug, Eq, PartialEq)]
20pub enum SignableError<E, M>
21where
22    E: ExternalMemory,
23    M: AsMetadata<E>,
24{
25    CutSignable,
26    ExtensionsList(ExtensionsError),
27    ImmortalHashMismatch,
28    MetaStructure(M::MetaStructureError),
29    NotACall(u32),
30    Parsing(ParserError<E>),
31    SomeDataNotUsedCall {
32        from: usize,
33        to: usize,
34    },
35    SomeDataNotUsedExtensions {
36        from: usize,
37    },
38    WrongGenesisHash {
39        as_decoded: H256,
40        expected: H256,
41    },
42    WrongSpecVersion {
43        as_decoded: String,
44        in_metadata: String,
45    },
46}
47
48impl<E, M> SignableError<E, M>
49where
50    E: ExternalMemory,
51    M: AsMetadata<E>,
52{
53    fn error_text(&self) -> String {
54        match &self {
55            SignableError::CutSignable => String::from("Unable to separate signable transaction data into call data and extensions data."),
56            SignableError::ExtensionsList(extensions_error) => extensions_error.error_text(),
57            SignableError::ImmortalHashMismatch => String::from("Extensions error. Block hash does not match the chain genesis hash in transaction with immortal `Era`."),
58            SignableError::MetaStructure(meta_structure_error) => format!("Unexpected structure of the metadata. {meta_structure_error}"),
59            SignableError::NotACall(all_calls_ty_id) => format!("Decoded signable transaction is not a call. Unexpected structure of calls descriptor type {all_calls_ty_id}."),
60            SignableError::Parsing(parser_error) => format!("Parsing error. {parser_error}"),
61            SignableError::SomeDataNotUsedCall { from, to } => format!("Some call data (input positions [{from}..{to}]) remained unused after decoding."),
62            SignableError::SomeDataNotUsedExtensions { from } => format!("Some extensions data (input positions [{from}..]) remained unused after decoding."),
63            SignableError::WrongGenesisHash { as_decoded, expected } => format!("Wrong chain. Apparent genesis hash in extensions {} does not match the expected one {}.", hex::encode(as_decoded.0), hex::encode(expected.0)),
64            SignableError::WrongSpecVersion { as_decoded, in_metadata} => format!("Wrong metadata spec version. When decoding extensions data with metadata version {in_metadata}, the apparent spec version in extensions is {as_decoded}."),
65        }
66    }
67}
68
69/// Errors in storage entry parsing.
70#[derive(Debug, Eq, PartialEq)]
71pub enum StorageError<E: ExternalMemory> {
72    KeyPartHashMismatch,
73    KeyPartsUnused,
74    KeyShorterThanPrefix,
75    MultipleHashesNotATuple,
76    MultipleHashesNumberMismatch,
77    ParsingKey(ParserError<E>),
78    ParsingValue(ParserError<E>),
79    PlainKeyExceedsPrefix,
80}
81
82impl<E: ExternalMemory> StorageError<E> {
83    fn error_text(&self) -> String {
84        match &self {
85            StorageError::KeyPartHashMismatch => {
86                String::from("Hash part of the storage key does not match the key data.")
87            }
88            StorageError::KeyPartsUnused => {
89                String::from("During the storage key parsing a part of the key remained unused.")
90            }
91            StorageError::KeyShorterThanPrefix => {
92                String::from("Provided storage key is shorter than the expected prefix.")
93            }
94            StorageError::MultipleHashesNotATuple => {
95                String::from("Hashers length is not 1, but the key type is not a tuple.")
96            }
97            StorageError::MultipleHashesNumberMismatch => String::from(
98                "Hashers length does not match the number of fields in a tuple key type.",
99            ),
100            StorageError::ParsingKey(parser_error) => {
101                format!("Error parsing the storage key. {parser_error}")
102            }
103            StorageError::ParsingValue(parser_error) => {
104                format!("Error parsing the storage value. {parser_error}")
105            }
106            StorageError::PlainKeyExceedsPrefix => {
107                String::from("Plain storage key contains data other than the prefix.")
108            }
109        }
110    }
111}
112
113/// Errors in data parsing.
114#[derive(Debug, Eq, PartialEq)]
115pub enum ParserError<E: ExternalMemory> {
116    Buffer(BufferError<E>),
117    Registry(RegistryError<E>),
118    NoCompact { position: usize },
119    SomeDataNotUsedBlob { from: usize },
120    TypeFailure { position: usize, ty: &'static str },
121    UnexpectedEnumVariant { position: usize },
122}
123
124impl<E: ExternalMemory> ParserError<E> {
125    fn error_text(&self) -> String {
126        match &self {
127            ParserError::Buffer(buffer_error) => format!("{buffer_error}"),
128            ParserError::Registry(registry_error) => {
129                format!("{registry_error}")
130            }
131            ParserError::NoCompact { position } => {
132                format!("Expected compact starting at position {position}, not found one.")
133            }
134            ParserError::SomeDataNotUsedBlob { from } => {
135                format!("Some data (input positions [{from}..]) remained unused after decoding.")
136            }
137            ParserError::TypeFailure { position, ty } => {
138                format!("Unable to decode data starting at position {position} as {ty}.")
139            }
140            ParserError::UnexpectedEnumVariant { position } => {
141                format!("Encountered unexpected enum variant at position {position}.")
142            }
143        }
144    }
145}
146
147/// Errors in metadata types registry
148#[derive(Debug, Eq, PartialEq)]
149pub enum RegistryError<E: ExternalMemory> {
150    External(E::ExternalMemoryError),
151    Internal(RegistryInternalError),
152}
153
154impl<E: ExternalMemory> RegistryError<E> {
155    fn error_text(&self) -> String {
156        match &self {
157            RegistryError::External(external_memory_error) => {
158                format!("Error accessing type from external memory. {external_memory_error}")
159            }
160            RegistryError::Internal(registry_internal_error) => {
161                format!("{registry_internal_error}")
162            }
163        }
164    }
165}
166
167/// Internal errors in metadata types registry.
168#[derive(Debug, Eq, PartialEq)]
169pub enum RegistryInternalError {
170    CyclicMetadata { id: u32 },
171    ExtrinsicNoCallParam,
172    NotBitOrderType { id: u32 },
173    NotBitStoreType { id: u32 },
174    TypeNotResolved { id: u32 },
175    UnexpectedCompactInsides { id: u32 },
176    UnexpectedExtrinsicType { extrinsic_ty_id: u32 },
177}
178
179impl RegistryInternalError {
180    fn error_text(&self) -> String {
181        match &self {
182            RegistryInternalError::CyclicMetadata { id } => format!("Resolving type id {id} in metadata type registry results in cycling."),
183            RegistryInternalError::ExtrinsicNoCallParam => String::from("Extrinsic type in provided metadata has no specified call parameter."),
184            RegistryInternalError::NotBitOrderType { id } => format!("BitVec type {id} in metadata type registry has unexpected BitOrder type."),
185            RegistryInternalError::NotBitStoreType { id } => format!("BitVec type {id} in metadata type registry has unexpected BitStore type."),
186            RegistryInternalError::TypeNotResolved { id } => format!("Unable to resolve type id {id} in metadata type registry."),
187            RegistryInternalError::UnexpectedCompactInsides { id } => format!("Compact type {id} in metadata type registry has unexpected type inside compact."),
188            RegistryInternalError::UnexpectedExtrinsicType { extrinsic_ty_id } => format!("Decoding is based on assumption that extrinsic type resolves into a SCALE-encoded opaque `Vec<u8>`. Unexpected type description is found for type {extrinsic_ty_id} in metadata type registry."),
189        }
190    }
191}
192
193impl<E: ExternalMemory> From<RegistryInternalError> for RegistryError<E> {
194    fn from(registry_internal_error: RegistryInternalError) -> Self {
195        RegistryError::Internal(registry_internal_error)
196    }
197}
198
199/// Errors caused by the extensions set.
200///
201/// Decoding signable transactions puts a set of requirements on the metadata
202/// itself. Extensions are expected to contain:
203///
204/// - no more than one `Era`
205/// - no more than one block hash
206/// - metadata `spec_version` (exactly once)
207/// - chain genesis hash (exactly once)
208///
209/// Spec version of the metadata and genesis hash are required to check that the
210/// correct metadata was used for signable transaction parsing.
211///
212/// If `Era` is encountered and immortal, block hash (if encountered) must be
213/// checked to match the genesis hash.
214#[derive(Debug, Eq, PartialEq)]
215pub enum ExtensionsError {
216    BlockHashTwice,
217    EraTwice,
218    GenesisHashTwice,
219    NoGenesisHash,
220    NoSpecVersion,
221    SpecVersionTwice,
222}
223
224impl ExtensionsError {
225    fn error_text(&self) -> String {
226        match &self {
227            ExtensionsError::BlockHashTwice => String::from("Signable transaction extensions contain more than one block hash entry."),
228            ExtensionsError::EraTwice => String::from("Signable transaction extensions contain more than one `Era` entry."),
229            ExtensionsError::GenesisHashTwice => String::from("Signable transaction extensions contain more than one genesis hash entry. Unable to verify that correct chain is used for parsing."),
230            ExtensionsError::NoGenesisHash => String::from("Signable transaction extensions do not include chain genesis hash. Unable to verify that correct chain is used for parsing."),
231            ExtensionsError::NoSpecVersion => String::from("Signable transaction extensions do not include metadata spec version. Unable to verify that correct metadata version is used for parsing."),
232            ExtensionsError::SpecVersionTwice => String::from("Signable transaction extensions contain more than one metadata spec version. Unable to verify that correct metadata version is used for parsing."),
233        }
234    }
235}
236
237/// Errors in expected structure of V14 metadata.
238#[derive(Debug, Eq, PartialEq)]
239pub enum MetaStructureErrorV14 {
240    ExtrinsicTypeNotResolved(RegistryInternalError),
241    NoAddressParam,
242    NoCallParam,
243    NoExtraParam,
244    NoSignatureParam,
245    UnexpectedExtrinsicType { extrinsic_ty_id: u32 },
246    Version(MetaVersionErrorPallets),
247}
248
249impl MetaStructureErrorV14 {
250    fn error_text(&self) -> String {
251        match &self {
252            MetaStructureErrorV14::ExtrinsicTypeNotResolved(registry_error_extrinsic) => format!("Unable to resolve in registry the chain extrinsic type. {registry_error_extrinsic}"),
253            MetaStructureErrorV14::NoAddressParam => String::from("Unchecked extrinsic type in provided metadata has no specified address parameter."),
254            MetaStructureErrorV14::NoCallParam => String::from("Unchecked extrinsic type in provided metadata has no specified call parameter."),
255            MetaStructureErrorV14::NoExtraParam => String::from("Unchecked extrinsic type in provided metadata has no specified extra parameter."),
256            MetaStructureErrorV14::NoSignatureParam => String::from("Unchecked extrinsic type in provided metadata has no specified signature parameter."),
257            MetaStructureErrorV14::UnexpectedExtrinsicType { extrinsic_ty_id } => format!("Decoding is based on assumption that extrinsic type resolves into a SCALE-encoded opaque `Vec<u8>`. Unexpected type description is found for type {extrinsic_ty_id} in metadata type registry."),
258            MetaStructureErrorV14::Version(meta_version_error_pallets) => format!("{meta_version_error_pallets}"),
259        }
260    }
261}
262
263impl From<MetaVersionErrorPallets> for MetaStructureErrorV14 {
264    fn from(meta_version_error_pallets: MetaVersionErrorPallets) -> Self {
265        MetaStructureErrorV14::Version(meta_version_error_pallets)
266    }
267}
268
269impl From<RegistryInternalError> for MetaStructureErrorV14 {
270    fn from(registry_error_extrinsic: RegistryInternalError) -> Self {
271        MetaStructureErrorV14::ExtrinsicTypeNotResolved(registry_error_extrinsic)
272    }
273}
274
275impl From<RegistryError<()>> for MetaStructureErrorV14 {
276    fn from(registry_error_extrinsic: RegistryError<()>) -> Self {
277        let RegistryError::Internal(internal) = registry_error_extrinsic;
278        MetaStructureErrorV14::ExtrinsicTypeNotResolved(internal)
279    }
280}
281
282/// Error in metadata version constant search.
283#[derive(Debug, Eq, PartialEq)]
284pub enum MetaVersionErrorPallets {
285    NoSpecNameIdentifier,
286    NoSpecVersionIdentifier,
287    NoSystemPallet,
288    NoVersionInConstants,
289    RuntimeVersionNotDecodeable,
290    SpecNameIdentifierTwice,
291    SpecVersionIdentifierTwice,
292    UnexpectedRuntimeVersionFormat,
293}
294
295impl MetaVersionErrorPallets {
296    fn error_text(&self) -> String {
297        match &self {
298            MetaVersionErrorPallets::NoSpecNameIdentifier => {
299                String::from("No spec name found in decoded `Version` constant.")
300            }
301            MetaVersionErrorPallets::NoSpecVersionIdentifier => {
302                String::from("No spec version found in decoded `Version` constant.")
303            }
304            MetaVersionErrorPallets::NoSystemPallet => {
305                String::from("No `System` pallet in metadata.")
306            }
307            MetaVersionErrorPallets::NoVersionInConstants => {
308                String::from("No `Version` constant in metadata `System` pallet.")
309            }
310            MetaVersionErrorPallets::RuntimeVersionNotDecodeable => String::from(
311                "`Version` constant from metadata `System` pallet could not be decoded.",
312            ),
313            MetaVersionErrorPallets::SpecNameIdentifierTwice => String::from(
314                "Spec name associated identifier found twice when decoding `Version` constant.",
315            ),
316            MetaVersionErrorPallets::SpecVersionIdentifierTwice => String::from(
317                "Spec version associated identifier found twice when decoding `Version` constant.",
318            ),
319            MetaVersionErrorPallets::UnexpectedRuntimeVersionFormat => {
320                String::from("Decoded `Version` constant is not a composite.")
321            }
322        }
323    }
324}
325
326/// Error in parsing of an unchecked extrinsic.
327#[derive(Debug, Eq, PartialEq)]
328pub enum UncheckedExtrinsicError<E: ExternalMemory, M: AsMetadata<E>> {
329    FormatNoCompact,
330    MetaStructure(M::MetaStructureError),
331    Parsing(ParserError<E>),
332    VersionMismatch { version_byte: u8, version: u8 },
333    UnexpectedCallTy { call_ty_id: u32 },
334}
335
336impl<E, M> UncheckedExtrinsicError<E, M>
337where
338    E: ExternalMemory,
339    M: AsMetadata<E>,
340{
341    fn error_text(&self) -> String {
342        match &self {
343            UncheckedExtrinsicError::FormatNoCompact => String::from("Unchecked extrinsic was expected to be a SCALE-encoded opaque `Vec<u8>`. Have not found a compact indicating vector length."),
344            UncheckedExtrinsicError::MetaStructure(meta_structure_error) => format!("Unexpected structure of the metadata. {meta_structure_error}"),
345            UncheckedExtrinsicError::Parsing(parser_error) => format!("Error parsing unchecked extrinsic data. {parser_error}"),
346            UncheckedExtrinsicError::VersionMismatch { version_byte, version } => format!("Version byte in unchecked extrinsic {version_byte} does not match with version {version} from provided metadata. Last 7 bits were expected to be identical."),
347            UncheckedExtrinsicError::UnexpectedCallTy { call_ty_id } => format!("Parameter type for call {call_ty_id} in metadata type registry is not a call type, and does not match known call type descriptors."),
348        }
349    }
350}
351
352/// Implement [`Display`] and `Error` (`std` only). Errors with no generics.
353macro_rules! impl_display_and_error {
354    ($($ty: ty), *) => {
355        $(
356            impl Display for $ty {
357                fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
358                    write!(f, "{}", self.error_text())
359                }
360            }
361
362            #[cfg(feature = "std")]
363            impl Error for $ty {
364                fn source(&self) -> Option<&(dyn Error + 'static)> {
365                    None
366                }
367            }
368        )*
369    }
370}
371
372impl_display_and_error!(
373    ExtensionsError,
374    MetaStructureErrorV14,
375    MetaVersionErrorPallets,
376    RegistryInternalError
377);
378
379/// Implement [`Display`] and `Error` (`std` only). Errors with single `<E>` generic.
380macro_rules! impl_display_and_error_gen {
381    ($($ty: ty), *) => {
382        $(
383            impl <E: ExternalMemory> Display for $ty {
384                fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
385                    write!(f, "{}", self.error_text())
386                }
387            }
388
389            #[cfg(feature = "std")]
390            impl <E: ExternalMemory> Error for $ty {
391                fn source(&self) -> Option<&(dyn Error + 'static)> {
392                    None
393                }
394            }
395        )*
396    }
397}
398
399impl_display_and_error_gen!(ParserError<E>, RegistryError<E>, StorageError<E>);
400
401impl<E: ExternalMemory> From<BufferError<E>> for ParserError<E> {
402    fn from(buffer_error: BufferError<E>) -> Self {
403        ParserError::Buffer(buffer_error)
404    }
405}
406
407impl<E: ExternalMemory> From<RegistryInternalError> for ParserError<E> {
408    fn from(registry_error: RegistryInternalError) -> Self {
409        ParserError::Registry(RegistryError::Internal(registry_error))
410    }
411}
412
413impl<E: ExternalMemory> From<RegistryError<E>> for ParserError<E> {
414    fn from(registry_error: RegistryError<E>) -> Self {
415        ParserError::Registry(registry_error)
416    }
417}
418
419/// Implement [`Display`], `Error` (`std` only), and `From<ParserError<E>>` conversion.
420macro_rules! impl_display_error_from_2gen {
421    ($($ty: ty), *) => {
422        $(
423            impl <E, M> Display for $ty
424            where
425                E: ExternalMemory,
426                M: AsMetadata<E>,
427            {
428                fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
429                    write!(f, "{}", self.error_text())
430                }
431            }
432
433            #[cfg(feature = "std")]
434            impl <E, M> Error for $ty
435            where
436                E: ExternalMemory,
437                M: AsMetadata<E>,
438            {
439                fn source(&self) -> Option<&(dyn Error + 'static)> {
440                    None
441                }
442            }
443
444            impl <E, M> From<ParserError<E>> for $ty
445            where
446                E: ExternalMemory,
447                M: AsMetadata<E>,
448            {
449                fn from(parser_error: ParserError<E>) -> Self {
450                    <$ty>::Parsing(parser_error)
451                }
452            }
453        )*
454    }
455}
456
457impl_display_error_from_2gen!(SignableError<E, M>, UncheckedExtrinsicError<E, M>);