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(
57        "After decoding the extrinsic at index {extrinsic_index}, {num_leftover_bytes} bytes were left, suggesting that decoding may have failed"
58    )]
59    LeftoverBytes {
60        /// Index of the extrinsic that failed to decode.
61        extrinsic_index: usize,
62        /// Number of bytes leftover after decoding the extrinsic.
63        num_leftover_bytes: usize,
64    },
65    /// Something went wrong decoding the extrinsic.
66    #[error("Failed to decode extrinsic at index {extrinsic_index}: {error}")]
67    ExtrinsicDecodeError {
68        /// Index of the extrinsic that failed to decode.
69        extrinsic_index: usize,
70        /// The decode error.
71        error: ExtrinsicDecodeError,
72    },
73}
74
75/// An alias for [`frame_decode::extrinsics::ExtrinsicDecodeError`].
76///
77pub type ExtrinsicDecodeError = frame_decode::extrinsics::ExtrinsicDecodeError;
78
79/// Something went wrong trying to access details in the metadata.
80#[derive(Clone, Debug, PartialEq, DeriveError)]
81#[non_exhaustive]
82pub enum MetadataError {
83    /// The DispatchError type isn't available in the metadata
84    #[error("The DispatchError type isn't available")]
85    DispatchErrorNotFound,
86    /// Type not found in metadata.
87    #[error("Type with ID {0} not found")]
88    TypeNotFound(u32),
89    /// Pallet not found (index).
90    #[error("Pallet with index {0} not found")]
91    PalletIndexNotFound(u8),
92    /// Pallet not found (name).
93    #[error("Pallet with name {0} not found")]
94    PalletNameNotFound(String),
95    /// Variant not found.
96    #[error("Variant with index {0} not found")]
97    VariantIndexNotFound(u8),
98    /// Constant not found.
99    #[error("Constant with name {0} not found")]
100    ConstantNameNotFound(String),
101    /// Call not found.
102    #[error("Call with name {0} not found")]
103    CallNameNotFound(String),
104    /// Runtime trait not found.
105    #[error("Runtime trait with name {0} not found")]
106    RuntimeTraitNotFound(String),
107    /// Runtime method not found.
108    #[error("Runtime method with name {0} not found")]
109    RuntimeMethodNotFound(String),
110    /// View Function not found.
111    #[error("View Function with query ID {} not found", hex::encode(.0))]
112    ViewFunctionNotFound([u8; 32]),
113    /// Call type not found in metadata.
114    #[error("Call type not found in pallet with index {0}")]
115    CallTypeNotFoundInPallet(u8),
116    /// Event type not found in metadata.
117    #[error("Event type not found in pallet with index {0}")]
118    EventTypeNotFoundInPallet(u8),
119    /// Storage details not found in metadata.
120    #[error("Storage details not found in pallet with name {0}")]
121    StorageNotFoundInPallet(String),
122    /// Storage entry not found.
123    #[error("Storage entry {0} not found")]
124    StorageEntryNotFound(String),
125    /// The generated interface used is not compatible with the node.
126    #[error("The generated code is not compatible with the node")]
127    IncompatibleCodegen,
128    /// Custom value not found.
129    #[error("Custom value with name {0} not found")]
130    CustomValueNameNotFound(String),
131}
132
133/// Something went wrong trying to encode or decode a storage address.
134#[derive(Clone, Debug, DeriveError)]
135#[non_exhaustive]
136pub enum StorageAddressError {
137    /// Storage lookup does not have the expected number of keys.
138    #[error("Storage lookup requires {expected} keys but more keys have been provided.")]
139    TooManyKeys {
140        /// The number of keys provided in the storage address.
141        expected: usize,
142    },
143    /// This storage entry in the metadata does not have the correct number of hashers to fields.
144    #[error("Storage entry in metadata does not have the correct number of hashers to fields")]
145    WrongNumberOfHashers {
146        /// The number of hashers in the metadata for this storage entry.
147        hashers: usize,
148        /// The number of fields in the metadata for this storage entry.
149        fields: usize,
150    },
151    /// We weren't given enough bytes to decode the storage address/key.
152    #[error("Not enough remaining bytes to decode the storage address/key")]
153    NotEnoughBytes,
154    /// We have leftover bytes after decoding the storage address.
155    #[error("We have leftover bytes after decoding the storage address")]
156    TooManyBytes,
157    /// The bytes of a storage address are not the expected address for decoding the storage keys of the address.
158    #[error(
159        "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"
160    )]
161    UnexpectedAddressBytes,
162    /// 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.
163    #[error(
164        "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"
165    )]
166    HasherCannotReconstructKey {
167        /// Type id of the key's type.
168        ty_id: u32,
169        /// The invalid hasher that caused this error.
170        hasher: StorageHasher,
171    },
172}
173
174/// An error that can be encountered when constructing a transaction.
175#[derive(Debug, DeriveError)]
176#[non_exhaustive]
177pub enum ExtrinsicError {
178    /// Transaction version not supported by Subxt.
179    #[error("Subxt does not support the extrinsic versions expected by the chain")]
180    UnsupportedVersion,
181    /// Issue encoding transaction extensions.
182    #[error("Cannot construct the required transaction extensions: {0}")]
183    Params(#[from] ExtrinsicParamsError),
184}
185
186impl From<ExtrinsicParamsError> for Error {
187    fn from(value: ExtrinsicParamsError) -> Self {
188        Error::Extrinsic(value.into())
189    }
190}
191
192/// An error that can be emitted when trying to construct an instance of [`crate::config::ExtrinsicParams`],
193/// encode data from the instance, or match on signed extensions.
194#[derive(Debug, DeriveError)]
195#[non_exhaustive]
196pub enum ExtrinsicParamsError {
197    /// Cannot find a type id in the metadata. The context provides some additional
198    /// information about the source of the error (eg the signed extension name).
199    #[error("Cannot find type id '{type_id} in the metadata (context: {context})")]
200    MissingTypeId {
201        /// Type ID.
202        type_id: u32,
203        /// Some arbitrary context to help narrow the source of the error.
204        context: &'static str,
205    },
206    /// A signed extension in use on some chain was not provided.
207    #[error("The chain expects a signed extension with the name {0}, but we did not provide one")]
208    UnknownTransactionExtension(String),
209    /// Some custom error.
210    #[error("Error constructing extrinsic parameters: {0}")]
211    Custom(Box<dyn core::error::Error + Send + Sync + 'static>),
212}
213
214impl ExtrinsicParamsError {
215    /// Create a custom [`ExtrinsicParamsError`] from a string.
216    pub fn custom<S: Into<String>>(error: S) -> Self {
217        let error: String = error.into();
218        let error: Box<dyn core::error::Error + Send + Sync + 'static> = Box::from(error);
219        ExtrinsicParamsError::Custom(error)
220    }
221}
222
223impl From<core::convert::Infallible> for ExtrinsicParamsError {
224    fn from(value: core::convert::Infallible) -> Self {
225        match value {}
226    }
227}