fix: Convert vendor/pezkuwi-subxt from submodule to regular directory
This commit is contained in:
@@ -0,0 +1,358 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! A representation of the dispatch error; an error returned when
|
||||
//! something fails in trying to submit/execute a transaction.
|
||||
|
||||
use super::{DispatchErrorDecodeError, ModuleErrorDecodeError, ModuleErrorDetailsError};
|
||||
use crate::metadata::Metadata;
|
||||
use core::fmt::Debug;
|
||||
use scale_decode::{DecodeAsType, TypeResolver, visitor::DecodeAsTypeResult};
|
||||
use std::{borrow::Cow, marker::PhantomData};
|
||||
|
||||
/// An error dispatching a transaction.
|
||||
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[non_exhaustive]
|
||||
pub enum DispatchError {
|
||||
/// Some error occurred.
|
||||
#[error("Some unknown error occurred.")]
|
||||
Other,
|
||||
/// Failed to lookup some data.
|
||||
#[error("Failed to lookup some data.")]
|
||||
CannotLookup,
|
||||
/// A bad origin.
|
||||
#[error("Bad origin.")]
|
||||
BadOrigin,
|
||||
/// A custom error in a module.
|
||||
#[error("Pallet error: {0}")]
|
||||
Module(ModuleError),
|
||||
/// At least one consumer is remaining so the account cannot be destroyed.
|
||||
#[error("At least one consumer is remaining so the account cannot be destroyed.")]
|
||||
ConsumerRemaining,
|
||||
/// There are no providers so the account cannot be created.
|
||||
#[error("There are no providers so the account cannot be created.")]
|
||||
NoProviders,
|
||||
/// There are too many consumers so the account cannot be created.
|
||||
#[error("There are too many consumers so the account cannot be created.")]
|
||||
TooManyConsumers,
|
||||
/// An error to do with tokens.
|
||||
#[error("Token error: {0}")]
|
||||
Token(TokenError),
|
||||
/// An arithmetic error.
|
||||
#[error("Arithmetic error: {0}")]
|
||||
Arithmetic(ArithmeticError),
|
||||
/// The number of transactional layers has been reached, or we are not in a transactional layer.
|
||||
#[error("Transactional error: {0}")]
|
||||
Transactional(TransactionalError),
|
||||
/// Resources exhausted, e.g. attempt to read/write data which is too large to manipulate.
|
||||
#[error(
|
||||
"Resources exhausted, e.g. attempt to read/write data which is too large to manipulate."
|
||||
)]
|
||||
Exhausted,
|
||||
/// The state is corrupt; this is generally not going to fix itself.
|
||||
#[error("The state is corrupt; this is generally not going to fix itself.")]
|
||||
Corruption,
|
||||
/// Some resource (e.g. a preimage) is unavailable right now. This might fix itself later.
|
||||
#[error(
|
||||
"Some resource (e.g. a preimage) is unavailable right now. This might fix itself later."
|
||||
)]
|
||||
Unavailable,
|
||||
/// Root origin is not allowed.
|
||||
#[error("Root origin is not allowed.")]
|
||||
RootNotAllowed,
|
||||
}
|
||||
|
||||
/// An error relating to tokens when dispatching a transaction.
|
||||
#[derive(scale_decode::DecodeAsType, Debug, thiserror::Error, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum TokenError {
|
||||
/// Funds are unavailable.
|
||||
#[error("Funds are unavailable.")]
|
||||
FundsUnavailable,
|
||||
/// Some part of the balance gives the only provider reference to the account and thus cannot be (re)moved.
|
||||
#[error(
|
||||
"Some part of the balance gives the only provider reference to the account and thus cannot be (re)moved."
|
||||
)]
|
||||
OnlyProvider,
|
||||
/// Account cannot exist with the funds that would be given.
|
||||
#[error("Account cannot exist with the funds that would be given.")]
|
||||
BelowMinimum,
|
||||
/// Account cannot be created.
|
||||
#[error("Account cannot be created.")]
|
||||
CannotCreate,
|
||||
/// The asset in question is unknown.
|
||||
#[error("The asset in question is unknown.")]
|
||||
UnknownAsset,
|
||||
/// Funds exist but are frozen.
|
||||
#[error("Funds exist but are frozen.")]
|
||||
Frozen,
|
||||
/// Operation is not supported by the asset.
|
||||
#[error("Operation is not supported by the asset.")]
|
||||
Unsupported,
|
||||
/// Account cannot be created for a held balance.
|
||||
#[error("Account cannot be created for a held balance.")]
|
||||
CannotCreateHold,
|
||||
/// Withdrawal would cause unwanted loss of account.
|
||||
#[error("Withdrawal would cause unwanted loss of account.")]
|
||||
NotExpendable,
|
||||
/// Account cannot receive the assets.
|
||||
#[error("Account cannot receive the assets.")]
|
||||
Blocked,
|
||||
}
|
||||
|
||||
/// An error relating to arithmetic when dispatching a transaction.
|
||||
#[derive(scale_decode::DecodeAsType, Debug, thiserror::Error, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum ArithmeticError {
|
||||
/// Underflow.
|
||||
#[error("Underflow.")]
|
||||
Underflow,
|
||||
/// Overflow.
|
||||
#[error("Overflow.")]
|
||||
Overflow,
|
||||
/// Division by zero.
|
||||
#[error("Division by zero.")]
|
||||
DivisionByZero,
|
||||
}
|
||||
|
||||
/// An error relating to the transactional layers when dispatching a transaction.
|
||||
#[derive(scale_decode::DecodeAsType, Debug, thiserror::Error, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum TransactionalError {
|
||||
/// Too many transactional layers have been spawned.
|
||||
#[error("Too many transactional layers have been spawned.")]
|
||||
LimitReached,
|
||||
/// A transactional layer was expected, but does not exist.
|
||||
#[error("A transactional layer was expected, but does not exist.")]
|
||||
NoLayer,
|
||||
}
|
||||
|
||||
/// Details about a module error that has occurred.
|
||||
#[derive(Clone, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub struct ModuleError {
|
||||
metadata: Metadata,
|
||||
/// Bytes representation:
|
||||
/// - `bytes[0]`: pallet index
|
||||
/// - `bytes[1]`: error index
|
||||
/// - `bytes[2..]`: 3 bytes specific for the module error
|
||||
bytes: [u8; 5],
|
||||
}
|
||||
|
||||
impl PartialEq for ModuleError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// A module error is the same if the raw underlying details are the same.
|
||||
self.bytes == other.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ModuleError {}
|
||||
|
||||
/// Custom `Debug` implementation, ignores the very large `metadata` field, using it instead (as
|
||||
/// intended) to resolve the actual pallet and error names. This is much more useful for debugging.
|
||||
impl Debug for ModuleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let details = self.details_string();
|
||||
write!(f, "ModuleError(<{details}>)")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ModuleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let details = self.details_string();
|
||||
write!(f, "{details}")
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleError {
|
||||
/// Return more details about this error.
|
||||
pub fn details(&self) -> Result<ModuleErrorDetails<'_>, ModuleErrorDetailsError> {
|
||||
let pallet = self
|
||||
.metadata
|
||||
.pallet_by_error_index(self.pallet_index())
|
||||
.ok_or(ModuleErrorDetailsError::PalletNotFound {
|
||||
pallet_index: self.pallet_index(),
|
||||
})?;
|
||||
|
||||
let variant = pallet
|
||||
.error_variant_by_index(self.error_index())
|
||||
.ok_or_else(|| ModuleErrorDetailsError::ErrorVariantNotFound {
|
||||
pallet_name: pallet.name().into(),
|
||||
error_index: self.error_index(),
|
||||
})?;
|
||||
|
||||
Ok(ModuleErrorDetails { pallet, variant })
|
||||
}
|
||||
|
||||
/// Return a formatted string of the resolved error details for debugging/display purposes.
|
||||
pub fn details_string(&self) -> String {
|
||||
match self.details() {
|
||||
Ok(details) => format!(
|
||||
"{pallet_name}::{variant_name}",
|
||||
pallet_name = details.pallet.name(),
|
||||
variant_name = details.variant.name,
|
||||
),
|
||||
Err(_) => format!(
|
||||
"Unknown pallet error '{bytes:?}' (pallet and error details cannot be retrieved)",
|
||||
bytes = self.bytes
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the underlying module error data that was decoded.
|
||||
pub fn bytes(&self) -> [u8; 5] {
|
||||
self.bytes
|
||||
}
|
||||
|
||||
/// Obtain the pallet index from the underlying byte data.
|
||||
pub fn pallet_index(&self) -> u8 {
|
||||
self.bytes[0]
|
||||
}
|
||||
|
||||
/// Obtain the error index from the underlying byte data.
|
||||
pub fn error_index(&self) -> u8 {
|
||||
self.bytes[1]
|
||||
}
|
||||
|
||||
/// Attempts to decode the ModuleError into the top outer Error enum.
|
||||
pub fn as_root_error<E: DecodeAsType>(&self) -> Result<E, ModuleErrorDecodeError> {
|
||||
let decoded = E::decode_as_type(
|
||||
&mut &self.bytes[..],
|
||||
self.metadata.outer_enums().error_enum_ty(),
|
||||
self.metadata.types(),
|
||||
)
|
||||
.map_err(ModuleErrorDecodeError)?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
}
|
||||
|
||||
/// Details about the module error.
|
||||
pub struct ModuleErrorDetails<'a> {
|
||||
/// The pallet that the error is in
|
||||
pub pallet: pezkuwi_subxt_metadata::PalletMetadata<'a>,
|
||||
/// The variant representing the error
|
||||
pub variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
|
||||
}
|
||||
|
||||
impl DispatchError {
|
||||
/// Attempt to decode a runtime [`DispatchError`].
|
||||
#[doc(hidden)]
|
||||
pub fn decode_from<'a>(
|
||||
bytes: impl Into<Cow<'a, [u8]>>,
|
||||
metadata: Metadata,
|
||||
) -> Result<Self, DispatchErrorDecodeError> {
|
||||
let bytes = bytes.into();
|
||||
let dispatch_error_ty_id = metadata
|
||||
.dispatch_error_ty()
|
||||
.ok_or(DispatchErrorDecodeError::DispatchErrorTypeIdNotFound)?;
|
||||
|
||||
// The aim is to decode our bytes into roughly this shape. This is copied from
|
||||
// `sp_runtime::DispatchError`; we need the variant names and any inner variant
|
||||
// names/shapes to line up in order for decoding to be successful.
|
||||
#[derive(scale_decode::DecodeAsType)]
|
||||
enum DecodedDispatchError {
|
||||
Other,
|
||||
CannotLookup,
|
||||
BadOrigin,
|
||||
Module(DecodedModuleErrorBytes),
|
||||
ConsumerRemaining,
|
||||
NoProviders,
|
||||
TooManyConsumers,
|
||||
Token(TokenError),
|
||||
Arithmetic(ArithmeticError),
|
||||
Transactional(TransactionalError),
|
||||
Exhausted,
|
||||
Corruption,
|
||||
Unavailable,
|
||||
RootNotAllowed,
|
||||
}
|
||||
|
||||
// ModuleError is a bit special; we want to support being decoded from either
|
||||
// a legacy format of 2 bytes, or a newer format of 5 bytes. So, just grab the bytes
|
||||
// out when decoding to manually work with them.
|
||||
struct DecodedModuleErrorBytes(Vec<u8>);
|
||||
struct DecodedModuleErrorBytesVisitor<R: TypeResolver>(PhantomData<R>);
|
||||
impl<R: TypeResolver> scale_decode::Visitor for DecodedModuleErrorBytesVisitor<R> {
|
||||
type Error = scale_decode::Error;
|
||||
type Value<'scale, 'info> = DecodedModuleErrorBytes;
|
||||
type TypeResolver = R;
|
||||
|
||||
fn unchecked_decode_as_type<'scale, 'info>(
|
||||
self,
|
||||
input: &mut &'scale [u8],
|
||||
_type_id: R::TypeId,
|
||||
_types: &'info R,
|
||||
) -> DecodeAsTypeResult<Self, Result<Self::Value<'scale, 'info>, Self::Error>>
|
||||
{
|
||||
DecodeAsTypeResult::Decoded(Ok(DecodedModuleErrorBytes(input.to_vec())))
|
||||
}
|
||||
}
|
||||
|
||||
impl scale_decode::IntoVisitor for DecodedModuleErrorBytes {
|
||||
type AnyVisitor<R: TypeResolver> = DecodedModuleErrorBytesVisitor<R>;
|
||||
fn into_visitor<R: TypeResolver>() -> DecodedModuleErrorBytesVisitor<R> {
|
||||
DecodedModuleErrorBytesVisitor(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
// Decode into our temporary error:
|
||||
let decoded_dispatch_err = DecodedDispatchError::decode_as_type(
|
||||
&mut &*bytes,
|
||||
dispatch_error_ty_id,
|
||||
metadata.types(),
|
||||
)
|
||||
.map_err(DispatchErrorDecodeError::CouldNotDecodeDispatchError)?;
|
||||
|
||||
// Convert into the outward-facing error, mainly by handling the Module variant.
|
||||
let dispatch_error = match decoded_dispatch_err {
|
||||
// Mostly we don't change anything from our decoded to our outward-facing error:
|
||||
DecodedDispatchError::Other => DispatchError::Other,
|
||||
DecodedDispatchError::CannotLookup => DispatchError::CannotLookup,
|
||||
DecodedDispatchError::BadOrigin => DispatchError::BadOrigin,
|
||||
DecodedDispatchError::ConsumerRemaining => DispatchError::ConsumerRemaining,
|
||||
DecodedDispatchError::NoProviders => DispatchError::NoProviders,
|
||||
DecodedDispatchError::TooManyConsumers => DispatchError::TooManyConsumers,
|
||||
DecodedDispatchError::Token(val) => DispatchError::Token(val),
|
||||
DecodedDispatchError::Arithmetic(val) => DispatchError::Arithmetic(val),
|
||||
DecodedDispatchError::Transactional(val) => DispatchError::Transactional(val),
|
||||
DecodedDispatchError::Exhausted => DispatchError::Exhausted,
|
||||
DecodedDispatchError::Corruption => DispatchError::Corruption,
|
||||
DecodedDispatchError::Unavailable => DispatchError::Unavailable,
|
||||
DecodedDispatchError::RootNotAllowed => DispatchError::RootNotAllowed,
|
||||
// But we apply custom logic to transform the module error into the outward facing version:
|
||||
DecodedDispatchError::Module(module_bytes) => {
|
||||
let module_bytes = module_bytes.0;
|
||||
|
||||
// The old version is 2 bytes; a pallet and error index.
|
||||
// The new version is 5 bytes; a pallet and error index and then 3 extra bytes.
|
||||
let bytes = if module_bytes.len() == 2 {
|
||||
[module_bytes[0], module_bytes[1], 0, 0, 0]
|
||||
} else if module_bytes.len() == 5 {
|
||||
[
|
||||
module_bytes[0],
|
||||
module_bytes[1],
|
||||
module_bytes[2],
|
||||
module_bytes[3],
|
||||
module_bytes[4],
|
||||
]
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Can't decode error sp_runtime::DispatchError: bytes do not match known shapes"
|
||||
);
|
||||
// Return _all_ of the bytes; every "unknown" return should be consistent.
|
||||
return Err(DispatchErrorDecodeError::CouldNotDecodeModuleError {
|
||||
bytes: bytes.to_vec(),
|
||||
});
|
||||
};
|
||||
|
||||
// And return our outward-facing version:
|
||||
DispatchError::Module(ModuleError { metadata, bytes })
|
||||
}
|
||||
};
|
||||
|
||||
Ok(dispatch_error)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/// Display hex strings.
|
||||
#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord)]
|
||||
pub struct Hex(String);
|
||||
|
||||
impl<T: AsRef<[u8]>> From<T> for Hex {
|
||||
fn from(value: T) -> Self {
|
||||
Hex(hex::encode(value.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Hex {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
+702
@@ -0,0 +1,702 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! Types representing the errors that can be returned.
|
||||
|
||||
mod dispatch_error;
|
||||
mod hex;
|
||||
|
||||
crate::macros::cfg_unstable_light_client! {
|
||||
pub use pezkuwi_subxt_lightclient::LightClientError;
|
||||
}
|
||||
|
||||
// Re-export dispatch error types:
|
||||
pub use dispatch_error::{
|
||||
ArithmeticError, DispatchError, ModuleError, TokenError, TransactionalError,
|
||||
};
|
||||
|
||||
// Re-expose the errors we use from other crates here:
|
||||
pub use crate::Metadata;
|
||||
pub use hex::Hex;
|
||||
pub use scale_decode::Error as DecodeError;
|
||||
pub use scale_encode::Error as EncodeError;
|
||||
pub use pezkuwi_subxt_metadata::TryFromError as MetadataTryFromError;
|
||||
|
||||
// Re-export core error types we're just reusing.
|
||||
pub use pezkuwi_subxt_core::error::{
|
||||
ConstantError,
|
||||
CustomValueError,
|
||||
EventsError as CoreEventsError,
|
||||
// These errors are exposed as-is:
|
||||
ExtrinsicDecodeErrorAt,
|
||||
// These errors are wrapped:
|
||||
ExtrinsicError as CoreExtrinsicError,
|
||||
RuntimeApiError as CoreRuntimeApiError,
|
||||
StorageError as CoreStorageError,
|
||||
StorageKeyError,
|
||||
StorageValueError,
|
||||
ViewFunctionError as CoreViewFunctionError,
|
||||
};
|
||||
|
||||
/// A global error type. Any of the errors exposed here can convert into this
|
||||
/// error via `.into()`, but this error isn't itself exposed from anything.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
ExtrinsicDecodeErrorAt(#[from] ExtrinsicDecodeErrorAt),
|
||||
#[error(transparent)]
|
||||
ConstantError(#[from] ConstantError),
|
||||
#[error(transparent)]
|
||||
CustomValueError(#[from] CustomValueError),
|
||||
#[error(transparent)]
|
||||
StorageKeyError(#[from] StorageKeyError),
|
||||
#[error(transparent)]
|
||||
StorageValueError(#[from] StorageValueError),
|
||||
#[error(transparent)]
|
||||
BackendError(#[from] BackendError),
|
||||
#[error(transparent)]
|
||||
BlockError(#[from] BlockError),
|
||||
#[error(transparent)]
|
||||
AccountNonceError(#[from] AccountNonceError),
|
||||
#[error(transparent)]
|
||||
OnlineClientError(#[from] OnlineClientError),
|
||||
#[error(transparent)]
|
||||
RuntimeUpdaterError(#[from] RuntimeUpdaterError),
|
||||
#[error(transparent)]
|
||||
RuntimeUpdateeApplyError(#[from] RuntimeUpdateeApplyError),
|
||||
#[error(transparent)]
|
||||
RuntimeApiError(#[from] RuntimeApiError),
|
||||
#[error(transparent)]
|
||||
EventsError(#[from] EventsError),
|
||||
#[error(transparent)]
|
||||
ExtrinsicError(#[from] ExtrinsicError),
|
||||
#[error(transparent)]
|
||||
ViewFunctionError(#[from] ViewFunctionError),
|
||||
#[error(transparent)]
|
||||
TransactionProgressError(#[from] TransactionProgressError),
|
||||
#[error(transparent)]
|
||||
TransactionStatusError(#[from] TransactionStatusError),
|
||||
#[error(transparent)]
|
||||
TransactionEventsError(#[from] TransactionEventsError),
|
||||
#[error(transparent)]
|
||||
TransactionFinalizedSuccessError(#[from] TransactionFinalizedSuccessError),
|
||||
#[error(transparent)]
|
||||
ModuleErrorDetailsError(#[from] ModuleErrorDetailsError),
|
||||
#[error(transparent)]
|
||||
ModuleErrorDecodeError(#[from] ModuleErrorDecodeError),
|
||||
#[error(transparent)]
|
||||
DispatchErrorDecodeError(#[from] DispatchErrorDecodeError),
|
||||
#[error(transparent)]
|
||||
StorageError(#[from] StorageError),
|
||||
// Dev note: Subxt doesn't directly return Raw* errors. These exist so that when
|
||||
// users use common crates (like parity-scale-codec and subxt-rpcs), errors returned
|
||||
// there can be handled automatically using ? when the expected error is subxt::Error.
|
||||
#[error("Other RPC client error: {0}")]
|
||||
OtherRpcClientError(#[from] pezkuwi_subxt_rpcs::Error),
|
||||
#[error("Other codec error: {0}")]
|
||||
OtherCodecError(#[from] codec::Error),
|
||||
#[cfg(feature = "unstable-light-client")]
|
||||
#[error("Other light client error: {0}")]
|
||||
OtherLightClientError(#[from] pezkuwi_subxt_lightclient::LightClientError),
|
||||
#[cfg(feature = "unstable-light-client")]
|
||||
#[error("Other light client RPC error: {0}")]
|
||||
OtherLightClientRpcError(#[from] pezkuwi_subxt_lightclient::LightClientRpcError),
|
||||
// Dev note: Nothing in subxt should ever emit this error. It can instead be used
|
||||
// to easily map other errors into a subxt::Error for convenience. Some From impls
|
||||
// make this automatic for common "other" error types.
|
||||
#[error("Other error: {0}")]
|
||||
Other(Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
}
|
||||
|
||||
impl From<std::convert::Infallible> for Error {
|
||||
fn from(value: std::convert::Infallible) -> Self {
|
||||
match value {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Create a generic error. This is a quick workaround when you are using
|
||||
/// [`Error`] and have a non-Subxt error to return.
|
||||
pub fn other<E: std::error::Error + Send + Sync + 'static>(error: E) -> Error {
|
||||
Error::Other(Box::new(error))
|
||||
}
|
||||
|
||||
/// Create a generic error from a string. This is a quick workaround when you are using
|
||||
/// [`Error`] and have a non-Subxt error to return.
|
||||
pub fn other_str(error: impl Into<String>) -> Error {
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
#[error("{0}")]
|
||||
struct StrError(String);
|
||||
Error::Other(Box::new(StrError(error.into())))
|
||||
}
|
||||
|
||||
/// Checks whether the error was caused by a RPC re-connection.
|
||||
pub fn is_disconnected_will_reconnect(&self) -> bool {
|
||||
matches!(
|
||||
self.backend_error(),
|
||||
Some(BackendError::Rpc(RpcError::ClientError(
|
||||
pezkuwi_subxt_rpcs::Error::DisconnectedWillReconnect(_)
|
||||
)))
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks whether the error was caused by a RPC request being rejected.
|
||||
pub fn is_rpc_limit_reached(&self) -> bool {
|
||||
matches!(
|
||||
self.backend_error(),
|
||||
Some(BackendError::Rpc(RpcError::LimitReached))
|
||||
)
|
||||
}
|
||||
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
Error::BlockError(e) => e.backend_error(),
|
||||
Error::AccountNonceError(e) => e.backend_error(),
|
||||
Error::OnlineClientError(e) => e.backend_error(),
|
||||
Error::RuntimeUpdaterError(e) => e.backend_error(),
|
||||
Error::RuntimeApiError(e) => e.backend_error(),
|
||||
Error::EventsError(e) => e.backend_error(),
|
||||
Error::ExtrinsicError(e) => e.backend_error(),
|
||||
Error::ViewFunctionError(e) => e.backend_error(),
|
||||
Error::TransactionProgressError(e) => e.backend_error(),
|
||||
Error::TransactionEventsError(e) => e.backend_error(),
|
||||
Error::TransactionFinalizedSuccessError(e) => e.backend_error(),
|
||||
Error::StorageError(e) => e.backend_error(),
|
||||
// Any errors that **don't** return a BackendError anywhere will return None:
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum BackendError {
|
||||
#[error("Backend error: RPC error: {0}")]
|
||||
Rpc(#[from] RpcError),
|
||||
#[error("Backend error: Could not find metadata version {0}")]
|
||||
MetadataVersionNotFound(u32),
|
||||
#[error("Backend error: Could not codec::Decode Runtime API response: {0}")]
|
||||
CouldNotScaleDecodeRuntimeResponse(codec::Error),
|
||||
#[error("Backend error: Could not codec::Decode metadata bytes into subxt::Metadata: {0}")]
|
||||
CouldNotDecodeMetadata(codec::Error),
|
||||
// This is for errors in `Backend` implementations which aren't any of the "pre-defined" set above:
|
||||
#[error("Custom backend error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl BackendError {
|
||||
/// Checks whether the error was caused by a RPC re-connection.
|
||||
pub fn is_disconnected_will_reconnect(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
BackendError::Rpc(RpcError::ClientError(
|
||||
pezkuwi_subxt_rpcs::Error::DisconnectedWillReconnect(_)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks whether the error was caused by a RPC request being rejected.
|
||||
pub fn is_rpc_limit_reached(&self) -> bool {
|
||||
matches!(self, BackendError::Rpc(RpcError::LimitReached))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pezkuwi_subxt_rpcs::Error> for BackendError {
|
||||
fn from(value: pezkuwi_subxt_rpcs::Error) -> Self {
|
||||
BackendError::Rpc(RpcError::ClientError(value))
|
||||
}
|
||||
}
|
||||
|
||||
/// An RPC error. Since we are generic over the RPC client that is used,
|
||||
/// the error is boxed and could be casted.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum RpcError {
|
||||
/// Error related to the RPC client.
|
||||
#[error("RPC error: {0}")]
|
||||
ClientError(#[from] pezkuwi_subxt_rpcs::Error),
|
||||
/// This error signals that we got back a [`pezkuwi_subxt_rpcs::methods::chain_head::MethodResponse::LimitReached`],
|
||||
/// which is not technically an RPC error but is treated as an error in our own APIs.
|
||||
#[error("RPC error: limit reached")]
|
||||
LimitReached,
|
||||
/// The RPC subscription was dropped.
|
||||
#[error("RPC error: subscription dropped.")]
|
||||
SubscriptionDropped,
|
||||
}
|
||||
|
||||
/// Block error
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum BlockError {
|
||||
#[error(
|
||||
"Could not find the block body with hash {block_hash} (perhaps it was on a non-finalized fork?)"
|
||||
)]
|
||||
BlockNotFound { block_hash: Hex },
|
||||
#[error("Could not download the block header with hash {block_hash}: {reason}")]
|
||||
CouldNotGetBlockHeader {
|
||||
block_hash: Hex,
|
||||
reason: BackendError,
|
||||
},
|
||||
#[error("Could not download the latest block header: {0}")]
|
||||
CouldNotGetLatestBlock(BackendError),
|
||||
#[error("Could not subscribe to all blocks: {0}")]
|
||||
CouldNotSubscribeToAllBlocks(BackendError),
|
||||
#[error("Could not subscribe to best blocks: {0}")]
|
||||
CouldNotSubscribeToBestBlocks(BackendError),
|
||||
#[error("Could not subscribe to finalized blocks: {0}")]
|
||||
CouldNotSubscribeToFinalizedBlocks(BackendError),
|
||||
#[error("Error getting account nonce at block {block_hash}")]
|
||||
AccountNonceError {
|
||||
block_hash: Hex,
|
||||
account_id: Hex,
|
||||
reason: AccountNonceError,
|
||||
},
|
||||
}
|
||||
|
||||
impl BlockError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
BlockError::CouldNotGetBlockHeader { reason: e, .. }
|
||||
| BlockError::CouldNotGetLatestBlock(e)
|
||||
| BlockError::CouldNotSubscribeToAllBlocks(e)
|
||||
| BlockError::CouldNotSubscribeToBestBlocks(e)
|
||||
| BlockError::CouldNotSubscribeToFinalizedBlocks(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum AccountNonceError {
|
||||
#[error("Could not retrieve account nonce: {0}")]
|
||||
CouldNotRetrieve(#[from] BackendError),
|
||||
#[error("Could not decode account nonce: {0}")]
|
||||
CouldNotDecode(#[from] codec::Error),
|
||||
#[error("Wrong number of account nonce bytes returned: {0} (expected 2, 4 or 8)")]
|
||||
WrongNumberOfBytes(usize),
|
||||
}
|
||||
|
||||
impl AccountNonceError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
AccountNonceError::CouldNotRetrieve(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum OnlineClientError {
|
||||
#[error("Cannot construct OnlineClient: {0}")]
|
||||
RpcError(#[from] pezkuwi_subxt_rpcs::Error),
|
||||
#[error(
|
||||
"Cannot construct OnlineClient: Cannot fetch latest finalized block to obtain init details from: {0}"
|
||||
)]
|
||||
CannotGetLatestFinalizedBlock(BackendError),
|
||||
#[error("Cannot construct OnlineClient: Cannot fetch genesis hash: {0}")]
|
||||
CannotGetGenesisHash(BackendError),
|
||||
#[error("Cannot construct OnlineClient: Cannot fetch current runtime version: {0}")]
|
||||
CannotGetCurrentRuntimeVersion(BackendError),
|
||||
#[error("Cannot construct OnlineClient: Cannot fetch metadata: {0}")]
|
||||
CannotFetchMetadata(BackendError),
|
||||
}
|
||||
|
||||
impl OnlineClientError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
OnlineClientError::CannotGetLatestFinalizedBlock(e)
|
||||
| OnlineClientError::CannotGetGenesisHash(e)
|
||||
| OnlineClientError::CannotGetCurrentRuntimeVersion(e)
|
||||
| OnlineClientError::CannotFetchMetadata(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum RuntimeUpdaterError {
|
||||
#[error("Error subscribing to runtime updates: The update stream ended unexpectedly")]
|
||||
UnexpectedEndOfUpdateStream,
|
||||
#[error("Error subscribing to runtime updates: The finalized block stream ended unexpectedly")]
|
||||
UnexpectedEndOfBlockStream,
|
||||
#[error("Error subscribing to runtime updates: Can't stream runtime version: {0}")]
|
||||
CannotStreamRuntimeVersion(BackendError),
|
||||
#[error("Error subscribing to runtime updates: Can't get next runtime version in stream: {0}")]
|
||||
CannotGetNextRuntimeVersion(BackendError),
|
||||
#[error("Error subscribing to runtime updates: Cannot stream finalized blocks: {0}")]
|
||||
CannotStreamFinalizedBlocks(BackendError),
|
||||
#[error("Error subscribing to runtime updates: Cannot get next finalized block in stream: {0}")]
|
||||
CannotGetNextFinalizedBlock(BackendError),
|
||||
#[error("Cannot fetch new metadata for runtime update: {0}")]
|
||||
CannotFetchNewMetadata(BackendError),
|
||||
#[error(
|
||||
"Error subscribing to runtime updates: Cannot find the System.LastRuntimeUpgrade storage entry"
|
||||
)]
|
||||
CantFindSystemLastRuntimeUpgrade,
|
||||
#[error("Error subscribing to runtime updates: Cannot fetch last runtime upgrade: {0}")]
|
||||
CantFetchLastRuntimeUpgrade(StorageError),
|
||||
#[error("Error subscribing to runtime updates: Cannot decode last runtime upgrade: {0}")]
|
||||
CannotDecodeLastRuntimeUpgrade(StorageValueError),
|
||||
}
|
||||
|
||||
impl RuntimeUpdaterError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
RuntimeUpdaterError::CannotStreamRuntimeVersion(e)
|
||||
| RuntimeUpdaterError::CannotGetNextRuntimeVersion(e)
|
||||
| RuntimeUpdaterError::CannotStreamFinalizedBlocks(e)
|
||||
| RuntimeUpdaterError::CannotGetNextFinalizedBlock(e)
|
||||
| RuntimeUpdaterError::CannotFetchNewMetadata(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can occur during upgrade.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum RuntimeUpdateeApplyError {
|
||||
#[error("The proposed runtime update is the same as the current version")]
|
||||
SameVersion,
|
||||
}
|
||||
|
||||
/// Error working with Runtime APIs
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum RuntimeApiError {
|
||||
#[error("Cannot access Runtime APIs at latest block: Cannot fetch latest finalized block: {0}")]
|
||||
CannotGetLatestFinalizedBlock(BackendError),
|
||||
#[error("{0}")]
|
||||
OfflineError(#[from] CoreRuntimeApiError),
|
||||
#[error("Cannot call the Runtime API: {0}")]
|
||||
CannotCallApi(BackendError),
|
||||
}
|
||||
|
||||
impl RuntimeApiError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
RuntimeApiError::CannotGetLatestFinalizedBlock(e)
|
||||
| RuntimeApiError::CannotCallApi(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error working with events.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum EventsError {
|
||||
#[error("{0}")]
|
||||
OfflineError(#[from] CoreEventsError),
|
||||
#[error("Cannot access events at latest block: Cannot fetch latest finalized block: {0}")]
|
||||
CannotGetLatestFinalizedBlock(BackendError),
|
||||
#[error("Cannot fetch event bytes: {0}")]
|
||||
CannotFetchEventBytes(BackendError),
|
||||
}
|
||||
|
||||
impl EventsError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
EventsError::CannotGetLatestFinalizedBlock(e)
|
||||
| EventsError::CannotFetchEventBytes(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error working with extrinsics.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ExtrinsicError {
|
||||
#[error("{0}")]
|
||||
OfflineError(#[from] CoreExtrinsicError),
|
||||
#[error("Could not download block body to extract extrinsics from: {0}")]
|
||||
CannotGetBlockBody(BackendError),
|
||||
#[error("Block not found: {0}")]
|
||||
BlockNotFound(Hex),
|
||||
#[error("{0}")]
|
||||
CouldNotDecodeExtrinsics(#[from] ExtrinsicDecodeErrorAt),
|
||||
#[error(
|
||||
"Extrinsic submission error: Cannot get latest finalized block to grab account nonce at: {0}"
|
||||
)]
|
||||
CannotGetLatestFinalizedBlock(BackendError),
|
||||
#[error("Cannot find block header for block {block_hash}")]
|
||||
CannotFindBlockHeader { block_hash: Hex },
|
||||
#[error("Error getting account nonce at block {block_hash}")]
|
||||
AccountNonceError {
|
||||
block_hash: Hex,
|
||||
account_id: Hex,
|
||||
reason: AccountNonceError,
|
||||
},
|
||||
#[error("Cannot submit extrinsic: {0}")]
|
||||
ErrorSubmittingTransaction(BackendError),
|
||||
#[error("A transaction status error was returned while submitting the extrinsic: {0}")]
|
||||
TransactionStatusError(TransactionStatusError),
|
||||
#[error(
|
||||
"The transaction status stream encountered an error while submitting the extrinsic: {0}"
|
||||
)]
|
||||
TransactionStatusStreamError(BackendError),
|
||||
#[error(
|
||||
"The transaction status stream unexpectedly ended, so we don't know the status of the submitted extrinsic"
|
||||
)]
|
||||
UnexpectedEndOfTransactionStatusStream,
|
||||
#[error("Cannot get fee info from Runtime API: {0}")]
|
||||
CannotGetFeeInfo(BackendError),
|
||||
#[error("Cannot get validation info from Runtime API: {0}")]
|
||||
CannotGetValidationInfo(BackendError),
|
||||
#[error("Cannot decode ValidationResult bytes: {0}")]
|
||||
CannotDecodeValidationResult(codec::Error),
|
||||
#[error("ValidationResult bytes could not be decoded")]
|
||||
UnexpectedValidationResultBytes(Vec<u8>),
|
||||
}
|
||||
|
||||
impl ExtrinsicError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
ExtrinsicError::CannotGetBlockBody(e)
|
||||
| ExtrinsicError::CannotGetLatestFinalizedBlock(e)
|
||||
| ExtrinsicError::ErrorSubmittingTransaction(e)
|
||||
| ExtrinsicError::TransactionStatusStreamError(e)
|
||||
| ExtrinsicError::CannotGetFeeInfo(e)
|
||||
| ExtrinsicError::CannotGetValidationInfo(e) => Some(e),
|
||||
ExtrinsicError::AccountNonceError { reason, .. } => reason.backend_error(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error working with View Functions.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ViewFunctionError {
|
||||
#[error("{0}")]
|
||||
OfflineError(#[from] CoreViewFunctionError),
|
||||
#[error(
|
||||
"Cannot access View Functions at latest block: Cannot fetch latest finalized block: {0}"
|
||||
)]
|
||||
CannotGetLatestFinalizedBlock(BackendError),
|
||||
#[error("Cannot call the View Function Runtime API: {0}")]
|
||||
CannotCallApi(BackendError),
|
||||
}
|
||||
|
||||
impl ViewFunctionError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
ViewFunctionError::CannotGetLatestFinalizedBlock(e)
|
||||
| ViewFunctionError::CannotCallApi(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error during the transaction progress.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum TransactionProgressError {
|
||||
#[error("Cannot get the next transaction progress update: {0}")]
|
||||
CannotGetNextProgressUpdate(BackendError),
|
||||
#[error("Error during transaction progress: {0}")]
|
||||
TransactionStatusError(#[from] TransactionStatusError),
|
||||
#[error(
|
||||
"The transaction status stream unexpectedly ended, so we have no further transaction progress updates"
|
||||
)]
|
||||
UnexpectedEndOfTransactionStatusStream,
|
||||
}
|
||||
|
||||
impl TransactionProgressError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
TransactionProgressError::CannotGetNextProgressUpdate(e) => Some(e),
|
||||
TransactionProgressError::TransactionStatusError(_) => None,
|
||||
TransactionProgressError::UnexpectedEndOfTransactionStatusStream => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error emitted as the result of a transaction progress update.
|
||||
#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum TransactionStatusError {
|
||||
/// An error happened on the node that the transaction was submitted to.
|
||||
#[error("Error handling transaction: {0}")]
|
||||
Error(String),
|
||||
/// The transaction was deemed invalid.
|
||||
#[error("The transaction is not valid: {0}")]
|
||||
Invalid(String),
|
||||
/// The transaction was dropped.
|
||||
#[error("The transaction was dropped: {0}")]
|
||||
Dropped(String),
|
||||
}
|
||||
|
||||
/// Error fetching events for a just-submitted transaction
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum TransactionEventsError {
|
||||
#[error(
|
||||
"The block containing the submitted transaction ({block_hash}) could not be downloaded: {error}"
|
||||
)]
|
||||
CannotFetchBlockBody {
|
||||
block_hash: Hex,
|
||||
error: BackendError,
|
||||
},
|
||||
#[error(
|
||||
"Cannot find the the submitted transaction (hash: {transaction_hash}) in the block (hash: {block_hash}) it is supposed to be in."
|
||||
)]
|
||||
CannotFindTransactionInBlock {
|
||||
block_hash: Hex,
|
||||
transaction_hash: Hex,
|
||||
},
|
||||
#[error("The block containing the submitted transaction ({block_hash}) could not be found")]
|
||||
BlockNotFound { block_hash: Hex },
|
||||
#[error(
|
||||
"Could not decode event at index {event_index} for the submitted transaction at block {block_hash}: {error}"
|
||||
)]
|
||||
CannotDecodeEventInBlock {
|
||||
event_index: usize,
|
||||
block_hash: Hex,
|
||||
error: EventsError,
|
||||
},
|
||||
#[error("Could not fetch events for the submitted transaction: {error}")]
|
||||
CannotFetchEventsForTransaction {
|
||||
block_hash: Hex,
|
||||
transaction_hash: Hex,
|
||||
error: EventsError,
|
||||
},
|
||||
#[error("The transaction led to a DispatchError, but we failed to decode it: {error}")]
|
||||
CannotDecodeDispatchError {
|
||||
error: DispatchErrorDecodeError,
|
||||
bytes: Vec<u8>,
|
||||
},
|
||||
#[error("The transaction failed with the following dispatch error: {0}")]
|
||||
ExtrinsicFailed(#[from] DispatchError),
|
||||
}
|
||||
|
||||
impl TransactionEventsError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
TransactionEventsError::CannotFetchBlockBody { error, .. } => Some(error),
|
||||
TransactionEventsError::CannotDecodeEventInBlock { error, .. }
|
||||
| TransactionEventsError::CannotFetchEventsForTransaction { error, .. } => {
|
||||
error.backend_error()
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error waiting for the transaction to be finalized and successful.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs, clippy::large_enum_variant)]
|
||||
pub enum TransactionFinalizedSuccessError {
|
||||
#[error("Could not finalize the transaction: {0}")]
|
||||
FinalizationError(#[from] TransactionProgressError),
|
||||
#[error("The transaction did not succeed: {0}")]
|
||||
SuccessError(#[from] TransactionEventsError),
|
||||
}
|
||||
|
||||
impl TransactionFinalizedSuccessError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
TransactionFinalizedSuccessError::FinalizationError(e) => e.backend_error(),
|
||||
TransactionFinalizedSuccessError::SuccessError(e) => e.backend_error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error decoding the [`DispatchError`]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ModuleErrorDetailsError {
|
||||
#[error(
|
||||
"Could not get details for the DispatchError: could not find pallet index {pallet_index}"
|
||||
)]
|
||||
PalletNotFound { pallet_index: u8 },
|
||||
#[error(
|
||||
"Could not get details for the DispatchError: could not find error index {error_index} in pallet {pallet_name}"
|
||||
)]
|
||||
ErrorVariantNotFound {
|
||||
pallet_name: String,
|
||||
error_index: u8,
|
||||
},
|
||||
}
|
||||
|
||||
/// Error decoding the [`ModuleError`]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
#[error("Could not decode the DispatchError::Module payload into the given type: {0}")]
|
||||
pub struct ModuleErrorDecodeError(scale_decode::Error);
|
||||
|
||||
/// Error decoding the [`DispatchError`]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum DispatchErrorDecodeError {
|
||||
#[error(
|
||||
"Could not decode the DispatchError: could not find the corresponding type ID in the metadata"
|
||||
)]
|
||||
DispatchErrorTypeIdNotFound,
|
||||
#[error("Could not decode the DispatchError: {0}")]
|
||||
CouldNotDecodeDispatchError(scale_decode::Error),
|
||||
#[error("Could not decode the DispatchError::Module variant")]
|
||||
CouldNotDecodeModuleError {
|
||||
/// The bytes corresponding to the Module variant we were unable to decode:
|
||||
bytes: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Error working with storage.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum StorageError {
|
||||
#[error("{0}")]
|
||||
Offline(#[from] CoreStorageError),
|
||||
#[error("Cannot access storage at latest block: Cannot fetch latest finalized block: {0}")]
|
||||
CannotGetLatestFinalizedBlock(BackendError),
|
||||
#[error(
|
||||
"No storage value found at the given address, and no default value to fall back to using."
|
||||
)]
|
||||
NoValueFound,
|
||||
#[error("Cannot fetch the storage value: {0}")]
|
||||
CannotFetchValue(BackendError),
|
||||
#[error("Cannot iterate storage values: {0}")]
|
||||
CannotIterateValues(BackendError),
|
||||
#[error("Encountered an error iterating over storage values: {0}")]
|
||||
StreamFailure(BackendError),
|
||||
#[error("Cannot decode the storage version for a given entry: {0}")]
|
||||
CannotDecodeStorageVersion(codec::Error),
|
||||
}
|
||||
|
||||
impl StorageError {
|
||||
fn backend_error(&self) -> Option<&BackendError> {
|
||||
match self {
|
||||
StorageError::CannotGetLatestFinalizedBlock(e)
|
||||
| StorageError::CannotFetchValue(e)
|
||||
| StorageError::CannotIterateValues(e)
|
||||
| StorageError::StreamFailure(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user