subxt_core/
error.rs

1// Copyright 2019-2024 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5//! The errors that can be emitted in this crate.
6
7use alloc::boxed::Box;
8use alloc::string::String;
9use subxt_metadata::StorageHasher;
10use thiserror::Error as DeriveError;
11
12/// The error emitted when something goes wrong.
13#[derive(Debug, DeriveError)]
14pub enum Error {
15    /// Codec error.
16    #[error("Codec error: {0}")]
17    Codec(codec::Error),
18    /// Metadata error.
19    #[error(transparent)]
20    Metadata(#[from] MetadataError),
21    /// Storage address error.
22    #[error(transparent)]
23    StorageAddress(#[from] StorageAddressError),
24    /// Error decoding to a [`crate::dynamic::Value`].
25    #[error("Error decoding into dynamic value: {0}")]
26    Decode(#[from] scale_decode::Error),
27    /// Error encoding from a [`crate::dynamic::Value`].
28    #[error("Error encoding from dynamic value: {0}")]
29    Encode(#[from] scale_encode::Error),
30    /// Error constructing an extrinsic.
31    #[error("Error constructing transaction: {0}")]
32    Extrinsic(#[from] ExtrinsicError),
33    /// Block body error.
34    #[error("Error working with block_body: {0}")]
35    Block(#[from] BlockError),
36}
37
38impl From<scale_decode::visitor::DecodeError> for Error {
39    fn from(err: scale_decode::visitor::DecodeError) -> Error {
40        Error::Decode(err.into())
41    }
42}
43
44// TODO: when `codec::Error` implements `core::Error`
45// remove this impl and replace it by thiserror #[from]
46impl From<codec::Error> for Error {
47    fn from(err: codec::Error) -> Error {
48        Error::Codec(err)
49    }
50}
51
52/// Block error
53#[derive(Debug, DeriveError)]
54pub enum BlockError {
55    /// Leftover bytes found after decoding the extrinsic.
56    #[error("After decoding the extrinsic at index {extrinsic_index}, {num_leftover_bytes} bytes were left, suggesting that decoding may have failed")]
57    LeftoverBytes {
58        /// Index of the extrinsic that failed to decode.
59        extrinsic_index: usize,
60        /// Number of bytes leftover after decoding the extrinsic.
61        num_leftover_bytes: usize,
62    },
63    /// Something went wrong decoding the extrinsic.
64    #[error("Failed to decode extrinsic at index {extrinsic_index}: {error}")]
65    ExtrinsicDecodeError {
66        /// Index of the extrinsic that failed to decode.
67        extrinsic_index: usize,
68        /// The decode error.
69        error: ExtrinsicDecodeError,
70    },
71}
72
73/// An alias for [`frame_decode::extrinsics::ExtrinsicDecodeError`].
74///
75pub type ExtrinsicDecodeError = frame_decode::extrinsics::ExtrinsicDecodeError;
76
77/// Something went wrong trying to access details in the metadata.
78#[derive(Clone, Debug, PartialEq, DeriveError)]
79#[non_exhaustive]
80pub enum MetadataError {
81    /// The DispatchError type isn't available in the metadata
82    #[error("The DispatchError type isn't available")]
83    DispatchErrorNotFound,
84    /// Type not found in metadata.
85    #[error("Type with ID {0} not found")]
86    TypeNotFound(u32),
87    /// Pallet not found (index).
88    #[error("Pallet with index {0} not found")]
89    PalletIndexNotFound(u8),
90    /// Pallet not found (name).
91    #[error("Pallet with name {0} not found")]
92    PalletNameNotFound(String),
93    /// Variant not found.
94    #[error("Variant with index {0} not found")]
95    VariantIndexNotFound(u8),
96    /// Constant not found.
97    #[error("Constant with name {0} not found")]
98    ConstantNameNotFound(String),
99    /// Call not found.
100    #[error("Call with name {0} not found")]
101    CallNameNotFound(String),
102    /// Runtime trait not found.
103    #[error("Runtime trait with name {0} not found")]
104    RuntimeTraitNotFound(String),
105    /// Runtime method not found.
106    #[error("Runtime method with name {0} not found")]
107    RuntimeMethodNotFound(String),
108    /// Call type not found in metadata.
109    #[error("Call type not found in pallet with index {0}")]
110    CallTypeNotFoundInPallet(u8),
111    /// Event type not found in metadata.
112    #[error("Event type not found in pallet with index {0}")]
113    EventTypeNotFoundInPallet(u8),
114    /// Storage details not found in metadata.
115    #[error("Storage details not found in pallet with name {0}")]
116    StorageNotFoundInPallet(String),
117    /// Storage entry not found.
118    #[error("Storage entry {0} not found")]
119    StorageEntryNotFound(String),
120    /// The generated interface used is not compatible with the node.
121    #[error("The generated code is not compatible with the node")]
122    IncompatibleCodegen,
123    /// Custom value not found.
124    #[error("Custom value with name {0} not found")]
125    CustomValueNameNotFound(String),
126}
127
128/// Something went wrong trying to encode or decode a storage address.
129#[derive(Clone, Debug, DeriveError)]
130#[non_exhaustive]
131pub enum StorageAddressError {
132    /// Storage lookup does not have the expected number of keys.
133    #[error("Storage lookup requires {expected} keys but more keys have been provided.")]
134    TooManyKeys {
135        /// The number of keys provided in the storage address.
136        expected: usize,
137    },
138    /// This storage entry in the metadata does not have the correct number of hashers to fields.
139    #[error("Storage entry in metadata does not have the correct number of hashers to fields")]
140    WrongNumberOfHashers {
141        /// The number of hashers in the metadata for this storage entry.
142        hashers: usize,
143        /// The number of fields in the metadata for this storage entry.
144        fields: usize,
145    },
146    /// We weren't given enough bytes to decode the storage address/key.
147    #[error("Not enough remaining bytes to decode the storage address/key")]
148    NotEnoughBytes,
149    /// We have leftover bytes after decoding the storage address.
150    #[error("We have leftover bytes after decoding the storage address")]
151    TooManyBytes,
152    /// The bytes of a storage address are not the expected address for decoding the storage keys of the address.
153    #[error("Storage address bytes are not the expected format. Addresses need to be at least 16 bytes (pallet ++ entry) and follow a structure given by the hashers defined in the metadata")]
154    UnexpectedAddressBytes,
155    /// An invalid hasher was used to reconstruct a value from a chunk of bytes that is part of a storage address. Hashers where the hash does not contain the original value are invalid for this purpose.
156    #[error("An invalid hasher was used to reconstruct a value with type ID {ty_id} from a hash formed by a {hasher:?} hasher. This is only possible for concat-style hashers or the identity hasher")]
157    HasherCannotReconstructKey {
158        /// Type id of the key's type.
159        ty_id: u32,
160        /// The invalid hasher that caused this error.
161        hasher: StorageHasher,
162    },
163}
164
165/// An error that can be encountered when constructing a transaction.
166#[derive(Debug, DeriveError)]
167#[non_exhaustive]
168pub enum ExtrinsicError {
169    /// Transaction version not supported by Subxt.
170    #[error("Subxt does not support the extrinsic versions expected by the chain")]
171    UnsupportedVersion,
172    /// Issue encoding transaction extensions.
173    #[error("Cannot construct the required transaction extensions: {0}")]
174    Params(#[from] ExtrinsicParamsError),
175}
176
177impl From<ExtrinsicParamsError> for Error {
178    fn from(value: ExtrinsicParamsError) -> Self {
179        Error::Extrinsic(value.into())
180    }
181}
182
183/// An error that can be emitted when trying to construct an instance of [`crate::config::ExtrinsicParams`],
184/// encode data from the instance, or match on signed extensions.
185#[derive(Debug, DeriveError)]
186#[non_exhaustive]
187pub enum ExtrinsicParamsError {
188    /// Cannot find a type id in the metadata. The context provides some additional
189    /// information about the source of the error (eg the signed extension name).
190    #[error("Cannot find type id '{type_id} in the metadata (context: {context})")]
191    MissingTypeId {
192        /// Type ID.
193        type_id: u32,
194        /// Some arbitrary context to help narrow the source of the error.
195        context: &'static str,
196    },
197    /// A signed extension in use on some chain was not provided.
198    #[error("The chain expects a signed extension with the name {0}, but we did not provide one")]
199    UnknownTransactionExtension(String),
200    /// Some custom error.
201    #[error("Error constructing extrinsic parameters: {0}")]
202    Custom(Box<dyn CustomError>),
203}
204
205/// Anything implementing this trait can be used in [`ExtrinsicParamsError::Custom`].
206#[cfg(feature = "std")]
207pub trait CustomError: std::error::Error + Send + Sync + 'static {}
208#[cfg(feature = "std")]
209impl<T: std::error::Error + Send + Sync + 'static> CustomError for T {}
210
211/// Anything implementing this trait can be used in [`ExtrinsicParamsError::Custom`].
212#[cfg(not(feature = "std"))]
213pub trait CustomError: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static {}
214#[cfg(not(feature = "std"))]
215impl<T: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static> CustomError for T {}
216
217impl From<core::convert::Infallible> for ExtrinsicParamsError {
218    fn from(value: core::convert::Infallible) -> Self {
219        match value {}
220    }
221}
222
223impl From<Box<dyn CustomError>> for ExtrinsicParamsError {
224    fn from(value: Box<dyn CustomError>) -> Self {
225        ExtrinsicParamsError::Custom(value)
226    }
227}