mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 08:51:09 +00:00
Begin 'fixing' errors
This commit is contained in:
@@ -7,7 +7,8 @@ use crate::config::transaction_extensions::{
|
||||
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce,
|
||||
};
|
||||
use crate::dynamic::Value;
|
||||
use crate::{Metadata, config::Config, error::Error};
|
||||
use crate::{Metadata, config::Config};
|
||||
use crate::error::ExtrinsicError;
|
||||
use frame_decode::extrinsics::ExtrinsicExtensions;
|
||||
use scale_decode::DecodeAsType;
|
||||
|
||||
@@ -50,7 +51,7 @@ impl<'a, T: Config> ExtrinsicTransactionExtensions<'a, T> {
|
||||
/// Searches through all signed extensions to find a specific one.
|
||||
/// If the Signed Extension is not found `Ok(None)` is returned.
|
||||
/// If the Signed Extension is found but decoding failed `Err(_)` is returned.
|
||||
pub fn find<S: TransactionExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> {
|
||||
pub fn find<S: TransactionExtension<T>>(&self) -> Result<Option<S::Decoded>, ExtrinsicError> {
|
||||
for ext in self.iter() {
|
||||
match ext.as_signed_extension::<S>() {
|
||||
// We found a match; return it:
|
||||
@@ -117,12 +118,15 @@ impl<'a, T: Config> ExtrinsicTransactionExtension<'a, T> {
|
||||
}
|
||||
|
||||
/// Signed Extension as a [`scale_value::Value`]
|
||||
pub fn value(&self) -> Result<Value<u32>, Error> {
|
||||
pub fn value(&self) -> Result<Value<u32>, ExtrinsicError> {
|
||||
let value = scale_value::scale::decode_as_type(
|
||||
&mut &self.bytes[..],
|
||||
self.ty_id,
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
).map_err(|e| ExtrinsicError::CouldNotDecodeTransactionExtension {
|
||||
name: self.identifier.to_owned(),
|
||||
error: e.into()
|
||||
})?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
@@ -131,15 +135,22 @@ impl<'a, T: Config> ExtrinsicTransactionExtension<'a, T> {
|
||||
/// decode with.
|
||||
pub fn as_signed_extension<S: TransactionExtension<T>>(
|
||||
&self,
|
||||
) -> Result<Option<S::Decoded>, Error> {
|
||||
) -> Result<Option<S::Decoded>, ExtrinsicError> {
|
||||
if !S::matches(self.identifier, self.ty_id, self.metadata.types()) {
|
||||
return Ok(None);
|
||||
}
|
||||
self.as_type::<S::Decoded>().map(Some)
|
||||
}
|
||||
|
||||
fn as_type<E: DecodeAsType>(&self) -> Result<E, Error> {
|
||||
let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?;
|
||||
fn as_type<E: DecodeAsType>(&self) -> Result<E, ExtrinsicError> {
|
||||
let value = E::decode_as_type(
|
||||
&mut &self.bytes[..],
|
||||
self.ty_id,
|
||||
self.metadata.types()
|
||||
).map_err(|e| ExtrinsicError::CouldNotDecodeTransactionExtension {
|
||||
name: self.identifier.to_owned(),
|
||||
error: e.into()
|
||||
})?;
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::BlockError;
|
||||
use crate::blocks::extrinsic_transaction_extensions::ExtrinsicTransactionExtensions;
|
||||
use crate::{
|
||||
Metadata,
|
||||
config::{Config, HashFor, Hasher},
|
||||
error::{Error, MetadataError},
|
||||
error::ExtrinsicError,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
@@ -29,7 +28,7 @@ impl<T: Config> Extrinsics<T> {
|
||||
/// Instantiate a new [`Extrinsics`] object, given a vector containing
|
||||
/// each extrinsic hash (in the form of bytes) and some metadata that
|
||||
/// we'll use to decode them.
|
||||
pub fn decode_from(extrinsics: Vec<Vec<u8>>, metadata: Metadata) -> Result<Self, Error> {
|
||||
pub fn decode_from(extrinsics: Vec<Vec<u8>>, metadata: Metadata) -> Result<Self, ExtrinsicError> {
|
||||
let hasher = T::Hasher::new(&metadata);
|
||||
let extrinsics = extrinsics
|
||||
.into_iter()
|
||||
@@ -43,7 +42,7 @@ impl<T: Config> Extrinsics<T> {
|
||||
&metadata,
|
||||
metadata.types(),
|
||||
)
|
||||
.map_err(|error| BlockError::ExtrinsicDecodeError {
|
||||
.map_err(|error| ExtrinsicError::ExtrinsicDecodeError {
|
||||
extrinsic_index,
|
||||
error,
|
||||
})?
|
||||
@@ -51,7 +50,7 @@ impl<T: Config> Extrinsics<T> {
|
||||
|
||||
// We didn't consume all bytes, so decoding probably failed.
|
||||
if !cursor.is_empty() {
|
||||
return Err(BlockError::LeftoverBytes {
|
||||
return Err(ExtrinsicError::LeftoverBytes {
|
||||
extrinsic_index,
|
||||
num_leftover_bytes: cursor.len(),
|
||||
}
|
||||
@@ -60,7 +59,7 @@ impl<T: Config> Extrinsics<T> {
|
||||
|
||||
Ok(Arc::new((decoded_info, bytes)))
|
||||
})
|
||||
.collect::<Result<_, Error>>()?;
|
||||
.collect::<Result<_, ExtrinsicError>>()?;
|
||||
|
||||
Ok(Self {
|
||||
extrinsics,
|
||||
@@ -105,7 +104,7 @@ impl<T: Config> Extrinsics<T> {
|
||||
/// If an error occurs, all subsequent iterations return `None`.
|
||||
pub fn find<E: StaticExtrinsic>(
|
||||
&self,
|
||||
) -> impl Iterator<Item = Result<FoundExtrinsic<T, E>, Error>> {
|
||||
) -> impl Iterator<Item = Result<FoundExtrinsic<T, E>, ExtrinsicError>> {
|
||||
self.iter().filter_map(|details| {
|
||||
match details.as_extrinsic::<E>() {
|
||||
// Failed to decode extrinsic:
|
||||
@@ -119,18 +118,18 @@ impl<T: Config> Extrinsics<T> {
|
||||
|
||||
/// Iterate through the extrinsics using metadata to dynamically decode and skip
|
||||
/// them, and return the first extrinsic found which decodes to the provided `E` type.
|
||||
pub fn find_first<E: StaticExtrinsic>(&self) -> Result<Option<FoundExtrinsic<T, E>>, Error> {
|
||||
pub fn find_first<E: StaticExtrinsic>(&self) -> Result<Option<FoundExtrinsic<T, E>>, ExtrinsicError> {
|
||||
self.find::<E>().next().transpose()
|
||||
}
|
||||
|
||||
/// Iterate through the extrinsics using metadata to dynamically decode and skip
|
||||
/// them, and return the last extrinsic found which decodes to the provided `Ev` type.
|
||||
pub fn find_last<E: StaticExtrinsic>(&self) -> Result<Option<FoundExtrinsic<T, E>>, Error> {
|
||||
pub fn find_last<E: StaticExtrinsic>(&self) -> Result<Option<FoundExtrinsic<T, E>>, ExtrinsicError> {
|
||||
self.find::<E>().last().transpose()
|
||||
}
|
||||
|
||||
/// Find an extrinsics that decodes to the type provided. Returns true if it was found.
|
||||
pub fn has<E: StaticExtrinsic>(&self) -> Result<bool, Error> {
|
||||
pub fn has<E: StaticExtrinsic>(&self) -> Result<bool, ExtrinsicError> {
|
||||
Ok(self.find::<E>().next().transpose()?.is_some())
|
||||
}
|
||||
}
|
||||
@@ -268,56 +267,57 @@ where
|
||||
}
|
||||
|
||||
/// The name of the pallet from whence the extrinsic originated.
|
||||
pub fn pallet_name(&self) -> Result<&str, Error> {
|
||||
Ok(self.extrinsic_metadata()?.pallet.name())
|
||||
pub fn pallet_name(&self) -> &str {
|
||||
self.decoded_info().pallet_name()
|
||||
}
|
||||
|
||||
/// The name of the call (ie the name of the variant that it corresponds to).
|
||||
pub fn variant_name(&self) -> Result<&str, Error> {
|
||||
Ok(&self.extrinsic_metadata()?.variant.name)
|
||||
}
|
||||
|
||||
/// Fetch the metadata for this extrinsic.
|
||||
pub fn extrinsic_metadata(&self) -> Result<ExtrinsicMetadataDetails<'_>, Error> {
|
||||
let pallet = self.metadata.pallet_by_index_err(self.pallet_index())?;
|
||||
let variant = pallet
|
||||
.call_variant_by_index(self.variant_index())
|
||||
.ok_or_else(|| MetadataError::VariantIndexNotFound(self.variant_index()))?;
|
||||
|
||||
Ok(ExtrinsicMetadataDetails { pallet, variant })
|
||||
pub fn call_name(&self) -> &str {
|
||||
self.decoded_info().call_name()
|
||||
}
|
||||
|
||||
/// Decode and provide the extrinsic fields back in the form of a [`scale_value::Composite`]
|
||||
/// type which represents the named or unnamed fields that were present in the extrinsic.
|
||||
pub fn field_values(&self) -> Result<scale_value::Composite<u32>, Error> {
|
||||
pub fn field_values(&self) -> Result<scale_value::Composite<u32>, ExtrinsicError> {
|
||||
let bytes = &mut self.field_bytes();
|
||||
let extrinsic_metadata = self.extrinsic_metadata()?;
|
||||
|
||||
let mut fields = extrinsic_metadata
|
||||
.variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref()));
|
||||
let mut fields = self.decoded_info().call_data().map(|d| {
|
||||
let name = if d.name().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(d.name())
|
||||
};
|
||||
scale_decode::Field::new(*d.ty(), name)
|
||||
});
|
||||
let decoded =
|
||||
scale_value::scale::decode_as_fields(bytes, &mut fields, self.metadata.types())?;
|
||||
scale_value::scale::decode_as_fields(bytes, &mut fields, self.metadata.types())
|
||||
.map_err(|e| ExtrinsicError::CannotDecodeFields {
|
||||
extrinsic_index: self.index as usize,
|
||||
error: e.into()
|
||||
})?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
|
||||
/// Attempt to decode these [`ExtrinsicDetails`] into a type representing the extrinsic fields.
|
||||
/// Such types are exposed in the codegen as `pallet_name::calls::types::CallName` types.
|
||||
pub fn as_extrinsic<E: StaticExtrinsic>(&self) -> Result<Option<E>, Error> {
|
||||
let extrinsic_metadata = self.extrinsic_metadata()?;
|
||||
if extrinsic_metadata.pallet.name() == E::PALLET
|
||||
&& extrinsic_metadata.variant.name == E::CALL
|
||||
pub fn as_extrinsic<E: StaticExtrinsic>(&self) -> Result<Option<E>, ExtrinsicError> {
|
||||
if self.decoded_info().pallet_name() == E::PALLET
|
||||
&& self.decoded_info().call_name() == E::CALL
|
||||
{
|
||||
let mut fields = extrinsic_metadata
|
||||
.variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref()));
|
||||
let mut fields = self.decoded_info().call_data().map(|d| {
|
||||
let name = if d.name().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(d.name())
|
||||
};
|
||||
scale_decode::Field::new(*d.ty(), name)
|
||||
});
|
||||
let decoded =
|
||||
E::decode_as_fields(&mut self.field_bytes(), &mut fields, self.metadata.types())?;
|
||||
E::decode_as_fields(&mut self.field_bytes(), &mut fields, self.metadata.types())
|
||||
.map_err(|e| ExtrinsicError::CannotDecodeFields {
|
||||
extrinsic_index: self.index as usize,
|
||||
error: e.into()
|
||||
})?;
|
||||
Ok(Some(decoded))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -327,12 +327,15 @@ where
|
||||
/// Attempt to decode these [`ExtrinsicDetails`] into an outer call enum type (which includes
|
||||
/// the pallet and extrinsic enum variants as well as the extrinsic fields). A compatible
|
||||
/// type for this is exposed via static codegen as a root level `Call` type.
|
||||
pub fn as_root_extrinsic<E: DecodeAsType>(&self) -> Result<E, Error> {
|
||||
pub fn as_root_extrinsic<E: DecodeAsType>(&self) -> Result<E, ExtrinsicError> {
|
||||
let decoded = E::decode_as_type(
|
||||
&mut &self.call_bytes()[..],
|
||||
self.metadata.outer_enums().call_enum_ty(),
|
||||
self.metadata.types(),
|
||||
)?;
|
||||
).map_err(|e| ExtrinsicError::CannotDecodeIntoRootExtrinsic {
|
||||
extrinsic_index: self.index as usize,
|
||||
error: e.into()
|
||||
})?;
|
||||
|
||||
Ok(decoded)
|
||||
}
|
||||
@@ -620,7 +623,7 @@ mod tests {
|
||||
assert_eq!(extrinsic.variant_index(), 2);
|
||||
assert_eq!(
|
||||
extrinsic
|
||||
.variant_name()
|
||||
.call_name()
|
||||
.expect("Valid metadata contains variant name"),
|
||||
"TestCall"
|
||||
);
|
||||
|
||||
@@ -70,10 +70,9 @@ mod static_extrinsic;
|
||||
|
||||
use crate::Metadata;
|
||||
use crate::config::Config;
|
||||
use crate::error::Error;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub use crate::error::BlockError;
|
||||
pub use crate::error::ExtrinsicError;
|
||||
pub use extrinsic_transaction_extensions::{
|
||||
ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions,
|
||||
};
|
||||
@@ -87,6 +86,6 @@ pub use static_extrinsic::StaticExtrinsic;
|
||||
pub fn decode_from<T: Config>(
|
||||
extrinsics: Vec<Vec<u8>>,
|
||||
metadata: Metadata,
|
||||
) -> Result<Extrinsics<T>, Error> {
|
||||
) -> Result<Extrinsics<T>, ExtrinsicError> {
|
||||
Extrinsics::decode_from(extrinsics, metadata)
|
||||
}
|
||||
|
||||
@@ -42,24 +42,24 @@ pub mod address;
|
||||
|
||||
use address::Address;
|
||||
use alloc::borrow::ToOwned;
|
||||
|
||||
use crate::{Error, Metadata, error::MetadataError, metadata::DecodeWithMetadata};
|
||||
use crate::{Metadata, metadata::DecodeWithMetadata};
|
||||
use crate::error::ConstantsError;
|
||||
|
||||
/// When the provided `address` is statically generated via the `#[subxt]` macro, this validates
|
||||
/// that the shape of the constant value is the same as the shape expected by the static address.
|
||||
///
|
||||
/// When the provided `address` is dynamic (and thus does not come with any expectation of the
|
||||
/// shape of the constant value), this just returns `Ok(())`
|
||||
pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<(), Error> {
|
||||
pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<(), ConstantsError> {
|
||||
if let Some(actual_hash) = address.validation_hash() {
|
||||
let expected_hash = metadata
|
||||
.pallet_by_name_err(address.pallet_name())?
|
||||
.constant_hash(address.constant_name())
|
||||
.ok_or_else(|| {
|
||||
MetadataError::ConstantNameNotFound(address.constant_name().to_owned())
|
||||
ConstantsError::ConstantNameNotFound(address.constant_name().to_owned())
|
||||
})?;
|
||||
if actual_hash != expected_hash {
|
||||
return Err(MetadataError::IncompatibleCodegen.into());
|
||||
return Err(ConstantsError::IncompatibleCodegen);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -67,7 +67,7 @@ pub fn validate<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<()
|
||||
|
||||
/// Fetch a constant out of the metadata given a constant address. If the `address` has been
|
||||
/// statically generated, this will validate that the constant shape is as expected, too.
|
||||
pub fn get<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<Addr::Target, Error> {
|
||||
pub fn get<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<Addr::Target, ConstantsError> {
|
||||
// 1. Validate constant shape if hash given:
|
||||
validate(address, metadata)?;
|
||||
|
||||
@@ -75,7 +75,7 @@ pub fn get<Addr: Address>(address: &Addr, metadata: &Metadata) -> Result<Addr::T
|
||||
let constant = metadata
|
||||
.pallet_by_name_err(address.pallet_name())?
|
||||
.constant_by_name(address.constant_name())
|
||||
.ok_or_else(|| MetadataError::ConstantNameNotFound(address.constant_name().to_owned()))?;
|
||||
.ok_or_else(|| ConstantsError::ConstantNameNotFound(address.constant_name().to_owned()))?;
|
||||
let value = <Addr::Target as DecodeWithMetadata>::decode_with_metadata(
|
||||
&mut constant.value(),
|
||||
constant.ty(),
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
use crate::dynamic::DecodedValueThunk;
|
||||
use crate::metadata::DecodeWithMetadata;
|
||||
use derive_where::derive_where;
|
||||
use crate::utils::YesNo;
|
||||
|
||||
/// Use this with [`Address::IsDecodable`].
|
||||
pub use crate::utils::Yes;
|
||||
pub use crate::utils::{Yes, No};
|
||||
|
||||
/// This represents the address of a custom value in the metadata.
|
||||
/// Anything that implements it can be used to fetch custom values from the metadata.
|
||||
@@ -18,8 +19,8 @@ pub trait Address {
|
||||
/// The type of the custom value.
|
||||
type Target: DecodeWithMetadata;
|
||||
/// Should be set to `Yes` for Dynamic values and static values that have a valid type.
|
||||
/// Should be `()` for custom values, that have an invalid type id.
|
||||
type IsDecodable;
|
||||
/// Should be `No` for custom values, that have an invalid type id.
|
||||
type IsDecodable: YesNo;
|
||||
|
||||
/// the name (key) by which the custom value can be accessed in the metadata.
|
||||
fn name(&self) -> &str;
|
||||
@@ -68,9 +69,9 @@ impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: DecodeWithMetadata, Y> Address for StaticAddress<R, Y> {
|
||||
type Target = R;
|
||||
type IsDecodable = Y;
|
||||
impl<Target: DecodeWithMetadata, IsDecodable: YesNo> Address for StaticAddress<Target, IsDecodable> {
|
||||
type Target = Target;
|
||||
type IsDecodable = IsDecodable;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
self.name
|
||||
|
||||
+126
-160
@@ -6,53 +6,131 @@
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use subxt_metadata::StorageHasher;
|
||||
use thiserror::Error as DeriveError;
|
||||
|
||||
/// The error emitted when something goes wrong.
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Error {
|
||||
/// Codec error.
|
||||
#[error("Codec error: {0}")]
|
||||
Codec(codec::Error),
|
||||
/// Metadata error.
|
||||
// /// Codec error.
|
||||
// #[error("Codec error: {0}")]
|
||||
// Codec(codec::Error),
|
||||
#[error(transparent)]
|
||||
Metadata(#[from] MetadataError),
|
||||
/// Storage address error.
|
||||
#[error(transparent)]
|
||||
StorageAddress(#[from] StorageAddressError),
|
||||
/// Error decoding to a [`crate::dynamic::Value`].
|
||||
#[error("Error decoding into dynamic value: {0}")]
|
||||
Decode(#[from] scale_decode::Error),
|
||||
/// Error encoding from a [`crate::dynamic::Value`].
|
||||
#[error("Error encoding from dynamic value: {0}")]
|
||||
Encode(#[from] scale_encode::Error),
|
||||
/// Error constructing an extrinsic.
|
||||
#[error("Error constructing transaction: {0}")]
|
||||
StorageError(#[from] StorageError),
|
||||
// /// Error decoding to a [`crate::dynamic::Value`].
|
||||
// #[error("Error decoding into dynamic value: {0}")]
|
||||
// Decode(#[from] scale_decode::Error),
|
||||
// /// Error encoding from a [`crate::dynamic::Value`].
|
||||
// #[error("Error encoding from dynamic value: {0}")]
|
||||
// Encode(#[from] scale_encode::Error),
|
||||
#[error(transparent)]
|
||||
Extrinsic(#[from] ExtrinsicError),
|
||||
/// Block body error.
|
||||
#[error("Error working with block_body: {0}")]
|
||||
Block(#[from] BlockError),
|
||||
#[error(transparent)]
|
||||
Constants(#[from] ConstantsError),
|
||||
}
|
||||
|
||||
impl From<scale_decode::visitor::DecodeError> for Error {
|
||||
fn from(err: scale_decode::visitor::DecodeError) -> Error {
|
||||
Error::Decode(err.into())
|
||||
}
|
||||
// impl From<scale_decode::visitor::DecodeError> for Error {
|
||||
// fn from(err: scale_decode::visitor::DecodeError) -> Error {
|
||||
// Error::Decode(err.into())
|
||||
// }
|
||||
// }
|
||||
|
||||
// // TODO: when `codec::Error` implements `core::Error`
|
||||
// // remove this impl and replace it by thiserror #[from]
|
||||
// impl From<codec::Error> for Error {
|
||||
// fn from(err: codec::Error) -> Error {
|
||||
// Error::Codec(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Something went wrong trying to access details in the metadata.
|
||||
#[derive(Clone, Debug, PartialEq, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum MetadataError {
|
||||
// /// The DispatchError type isn't available in the metadata
|
||||
// #[error("The DispatchError type isn't available")]
|
||||
// DispatchErrorNotFound,
|
||||
// /// Type not found in metadata.
|
||||
// #[error("Type with ID {0} not found")]
|
||||
// TypeNotFound(u32),
|
||||
/// Pallet not found (index).
|
||||
// /// Call type not found in metadata.
|
||||
// #[error("Call type not found in pallet with index {0}")]
|
||||
// CallTypeNotFoundInPallet(u8),
|
||||
// /// Event type not found in metadata.
|
||||
// #[error("Event type not found in pallet with index {0}")]
|
||||
// EventTypeNotFoundInPallet(u8),
|
||||
// // /// Storage details not found in metadata.
|
||||
// // #[error("Storage details not found in pallet with name {0}")]
|
||||
// // StorageNotFoundInPallet(String),
|
||||
// // /// Storage entry not found.
|
||||
// // #[error("Storage entry {0} not found")]
|
||||
// // StorageEntryNotFound(String),
|
||||
#[error("Pallet with index {0} not found")]
|
||||
PalletIndexNotFound(u8),
|
||||
#[error("Pallet with name {0} not found")]
|
||||
PalletNameNotFound(String),
|
||||
#[error("Variant with index {0} not found")]
|
||||
VariantIndexNotFound(u8),
|
||||
#[error("Constant with name {0} not found")]
|
||||
ConstantNameNotFound(String),
|
||||
#[error("Call with name {0} not found")]
|
||||
CallNameNotFound(String),
|
||||
#[error("Runtime trait with name {0} not found")]
|
||||
RuntimeTraitNotFound(String),
|
||||
#[error("Runtime method with name {0} not found")]
|
||||
RuntimeMethodNotFound(String),
|
||||
#[error("View Function with query ID {} not found", hex::encode(.0))]
|
||||
ViewFunctionNotFound([u8; 32]),
|
||||
#[error("The generated code is not compatible with the node")]
|
||||
IncompatibleCodegen,
|
||||
#[error("Custom value with name {0} not found")]
|
||||
CustomValueNameNotFound(String),
|
||||
}
|
||||
|
||||
// TODO: when `codec::Error` implements `core::Error`
|
||||
// remove this impl and replace it by thiserror #[from]
|
||||
impl From<codec::Error> for Error {
|
||||
fn from(err: codec::Error) -> Error {
|
||||
Error::Codec(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Block error
|
||||
/// Something went wrong working with a constant.
|
||||
#[derive(Debug, DeriveError)]
|
||||
pub enum BlockError {
|
||||
/// Leftover bytes found after decoding the extrinsic.
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ConstantsError {
|
||||
#[error("The static constant address used is not compatible with the live chain")]
|
||||
IncompatibleCodegen,
|
||||
#[error("Constant with name {0} not found in the live chain metadata")]
|
||||
ConstantNameNotFound(String),
|
||||
}
|
||||
|
||||
/// Something went wrong trying to encode or decode a storage address.
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum StorageError {
|
||||
#[error("Cannot obtain storage information from metadata: {0}")]
|
||||
StorageInfoError(frame_decode::storage::StorageInfoError<'static>),
|
||||
#[error("Cannot decode storage value: {0}")]
|
||||
StorageValueDecodeError(frame_decode::storage::StorageValueDecodeError<u32>),
|
||||
#[error("Cannot encode storage key: {0}")]
|
||||
StorageKeyEncodeError(frame_decode::storage::StorageKeyEncodeError),
|
||||
}
|
||||
|
||||
/// An error that can be encountered when constructing a transaction.
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ExtrinsicError {
|
||||
#[error("Subxt does not support the extrinsic versions expected by the chain")]
|
||||
UnsupportedVersion,
|
||||
#[error("Cannot construct the required transaction extensions: {0}")]
|
||||
Params(#[from] ExtrinsicParamsError),
|
||||
#[error("Cannot decode transaction extension '{name}': {error}")]
|
||||
CouldNotDecodeTransactionExtension {
|
||||
/// The extension name.
|
||||
name: String,
|
||||
/// The decode error.
|
||||
error: scale_decode::Error
|
||||
},
|
||||
#[error(
|
||||
"After decoding the extrinsic at index {extrinsic_index}, {num_leftover_bytes} bytes were left, suggesting that decoding may have failed"
|
||||
)]
|
||||
@@ -62,7 +140,6 @@ pub enum BlockError {
|
||||
/// Number of bytes leftover after decoding the extrinsic.
|
||||
num_leftover_bytes: usize,
|
||||
},
|
||||
/// Something went wrong decoding the extrinsic.
|
||||
#[error("Failed to decode extrinsic at index {extrinsic_index}: {error}")]
|
||||
ExtrinsicDecodeError {
|
||||
/// Index of the extrinsic that failed to decode.
|
||||
@@ -70,141 +147,32 @@ pub enum BlockError {
|
||||
/// The decode error.
|
||||
error: ExtrinsicDecodeError,
|
||||
},
|
||||
#[error("Failed to decode the fields of an extrinsic at index {extrinsic_index}: {error}")]
|
||||
CannotDecodeFields {
|
||||
/// Index of the extrinsic whose fields we could not decode
|
||||
extrinsic_index: usize,
|
||||
/// The decode error.
|
||||
error: scale_decode::Error
|
||||
},
|
||||
#[error("Failed to decode the extrinsic at index {extrinsic_index} to a root enum: {error}")]
|
||||
CannotDecodeIntoRootExtrinsic {
|
||||
/// Index of the extrinsic that we failed to decode
|
||||
extrinsic_index: usize,
|
||||
/// The decode error.
|
||||
error: scale_decode::Error
|
||||
}
|
||||
}
|
||||
|
||||
/// An alias for [`frame_decode::extrinsics::ExtrinsicDecodeError`].
|
||||
///
|
||||
pub type ExtrinsicDecodeError = frame_decode::extrinsics::ExtrinsicDecodeError;
|
||||
|
||||
/// Something went wrong trying to access details in the metadata.
|
||||
#[derive(Clone, Debug, PartialEq, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
pub enum MetadataError {
|
||||
/// The DispatchError type isn't available in the metadata
|
||||
#[error("The DispatchError type isn't available")]
|
||||
DispatchErrorNotFound,
|
||||
/// Type not found in metadata.
|
||||
#[error("Type with ID {0} not found")]
|
||||
TypeNotFound(u32),
|
||||
/// Pallet not found (index).
|
||||
#[error("Pallet with index {0} not found")]
|
||||
PalletIndexNotFound(u8),
|
||||
/// Pallet not found (name).
|
||||
#[error("Pallet with name {0} not found")]
|
||||
PalletNameNotFound(String),
|
||||
/// Variant not found.
|
||||
#[error("Variant with index {0} not found")]
|
||||
VariantIndexNotFound(u8),
|
||||
/// Constant not found.
|
||||
#[error("Constant with name {0} not found")]
|
||||
ConstantNameNotFound(String),
|
||||
/// Call not found.
|
||||
#[error("Call with name {0} not found")]
|
||||
CallNameNotFound(String),
|
||||
/// Runtime trait not found.
|
||||
#[error("Runtime trait with name {0} not found")]
|
||||
RuntimeTraitNotFound(String),
|
||||
/// Runtime method not found.
|
||||
#[error("Runtime method with name {0} not found")]
|
||||
RuntimeMethodNotFound(String),
|
||||
/// View Function not found.
|
||||
#[error("View Function with query ID {} not found", hex::encode(.0))]
|
||||
ViewFunctionNotFound([u8; 32]),
|
||||
/// Call type not found in metadata.
|
||||
#[error("Call type not found in pallet with index {0}")]
|
||||
CallTypeNotFoundInPallet(u8),
|
||||
/// Event type not found in metadata.
|
||||
#[error("Event type not found in pallet with index {0}")]
|
||||
EventTypeNotFoundInPallet(u8),
|
||||
/// Storage details not found in metadata.
|
||||
#[error("Storage details not found in pallet with name {0}")]
|
||||
StorageNotFoundInPallet(String),
|
||||
/// Storage entry not found.
|
||||
#[error("Storage entry {0} not found")]
|
||||
StorageEntryNotFound(String),
|
||||
/// The generated interface used is not compatible with the node.
|
||||
#[error("The generated code is not compatible with the node")]
|
||||
IncompatibleCodegen,
|
||||
/// Custom value not found.
|
||||
#[error("Custom value with name {0} not found")]
|
||||
CustomValueNameNotFound(String),
|
||||
}
|
||||
|
||||
/// Something went wrong trying to encode or decode a storage address.
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
pub enum StorageAddressError {
|
||||
/// Storage lookup does not have the expected number of keys.
|
||||
#[error("Storage lookup requires {expected} keys but more keys have been provided.")]
|
||||
TooManyKeys {
|
||||
/// The number of keys provided in the storage address.
|
||||
expected: usize,
|
||||
},
|
||||
/// This storage entry in the metadata does not have the correct number of hashers to fields.
|
||||
#[error("Storage entry in metadata does not have the correct number of hashers to fields")]
|
||||
WrongNumberOfHashers {
|
||||
/// The number of hashers in the metadata for this storage entry.
|
||||
hashers: usize,
|
||||
/// The number of fields in the metadata for this storage entry.
|
||||
fields: usize,
|
||||
},
|
||||
/// We weren't given enough bytes to decode the storage address/key.
|
||||
#[error("Not enough remaining bytes to decode the storage address/key")]
|
||||
NotEnoughBytes,
|
||||
/// We have leftover bytes after decoding the storage address.
|
||||
#[error("We have leftover bytes after decoding the storage address")]
|
||||
TooManyBytes,
|
||||
/// The bytes of a storage address are not the expected address for decoding the storage keys of the address.
|
||||
#[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"
|
||||
)]
|
||||
UnexpectedAddressBytes,
|
||||
/// 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.
|
||||
#[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"
|
||||
)]
|
||||
HasherCannotReconstructKey {
|
||||
/// Type id of the key's type.
|
||||
ty_id: u32,
|
||||
/// The invalid hasher that caused this error.
|
||||
hasher: StorageHasher,
|
||||
},
|
||||
/// Cannot obtain storage information from metadata
|
||||
#[error("Cannot obtain storage information from metadata: {0}")]
|
||||
StorageInfoError(frame_decode::storage::StorageInfoError<'static>),
|
||||
/// Cannot decode storage value
|
||||
#[error("Cannot decode storage value: {0}")]
|
||||
StorageValueDecodeError(frame_decode::storage::StorageValueDecodeError<u32>),
|
||||
/// Cannot encode storage key
|
||||
#[error("Cannot encode storage key: {0}")]
|
||||
StorageKeyEncodeError(frame_decode::storage::StorageKeyEncodeError),
|
||||
}
|
||||
|
||||
/// An error that can be encountered when constructing a transaction.
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
pub enum ExtrinsicError {
|
||||
/// Transaction version not supported by Subxt.
|
||||
#[error("Subxt does not support the extrinsic versions expected by the chain")]
|
||||
UnsupportedVersion,
|
||||
/// Issue encoding transaction extensions.
|
||||
#[error("Cannot construct the required transaction extensions: {0}")]
|
||||
Params(#[from] ExtrinsicParamsError),
|
||||
}
|
||||
|
||||
impl From<ExtrinsicParamsError> for Error {
|
||||
fn from(value: ExtrinsicParamsError) -> Self {
|
||||
Error::Extrinsic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can be emitted when trying to construct an instance of [`crate::config::ExtrinsicParams`],
|
||||
/// encode data from the instance, or match on signed extensions.
|
||||
#[derive(Debug, DeriveError)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ExtrinsicParamsError {
|
||||
/// Cannot find a type id in the metadata. The context provides some additional
|
||||
/// information about the source of the error (eg the signed extension name).
|
||||
#[error("Cannot find type id '{type_id} in the metadata (context: {context})")]
|
||||
MissingTypeId {
|
||||
/// Type ID.
|
||||
@@ -212,10 +180,8 @@ pub enum ExtrinsicParamsError {
|
||||
/// Some arbitrary context to help narrow the source of the error.
|
||||
context: &'static str,
|
||||
},
|
||||
/// A signed extension in use on some chain was not provided.
|
||||
#[error("The chain expects a signed extension with the name {0}, but we did not provide one")]
|
||||
UnknownTransactionExtension(String),
|
||||
/// Some custom error.
|
||||
#[error("Error constructing extrinsic parameters: {0}")]
|
||||
Custom(Box<dyn core::error::Error + Send + Sync + 'static>),
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ pub mod address;
|
||||
|
||||
use crate::{
|
||||
Error, Metadata,
|
||||
error::{MetadataError, StorageAddressError},
|
||||
error::{MetadataError, StorageError},
|
||||
};
|
||||
use address::Address;
|
||||
use alloc::vec::Vec;
|
||||
@@ -94,7 +94,7 @@ pub fn get_address_bytes<Addr: Address, Keys: EqualOrPrefixOf<Addr::KeyParts>>(
|
||||
&**metadata,
|
||||
metadata.types(),
|
||||
)
|
||||
.map_err(|e| StorageAddressError::StorageKeyEncodeError(e).into())
|
||||
.map_err(|e| StorageError::StorageKeyEncodeError(e).into())
|
||||
}
|
||||
|
||||
/// Given a storage address and some metadata, this encodes the root of the address (ie the pallet
|
||||
@@ -120,7 +120,7 @@ pub fn decode_value<Addr: Address>(
|
||||
metadata.types(),
|
||||
Addr::Value::into_visitor(),
|
||||
)
|
||||
.map_err(|e| StorageAddressError::StorageValueDecodeError(e).into())
|
||||
.map_err(|e| StorageError::StorageValueDecodeError(e).into())
|
||||
}
|
||||
|
||||
/// Return the default value at a given storage address if one is available, or None otherwise.
|
||||
@@ -130,13 +130,13 @@ pub fn default_value<Addr: Address>(
|
||||
) -> Result<Option<Addr::Value>, Error> {
|
||||
let storage_info = metadata
|
||||
.storage_info(address.pallet_name(), address.entry_name())
|
||||
.map_err(|e| StorageAddressError::StorageInfoError(e.into_owned()))?;
|
||||
.map_err(|e| StorageError::StorageInfoError(e.into_owned()))?;
|
||||
let value = frame_decode::storage::decode_default_storage_value_with_info(
|
||||
&storage_info,
|
||||
metadata.types(),
|
||||
Addr::Value::into_visitor(),
|
||||
)
|
||||
.map_err(|e| StorageAddressError::StorageValueDecodeError(e))?;
|
||||
.map_err(|e| StorageError::StorageValueDecodeError(e))?;
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ use alloc::vec::Vec;
|
||||
use codec::{Compact, Decode, Encode};
|
||||
use derive_where::derive_where;
|
||||
|
||||
pub use yesnomaybe::{Yes, Maybe, YesMaybe};
|
||||
pub use yesnomaybe::{Yes, No, Maybe, YesMaybe, YesNo};
|
||||
pub use account_id::AccountId32;
|
||||
pub use account_id20::AccountId20;
|
||||
pub use era::Era;
|
||||
|
||||
@@ -6,6 +6,24 @@
|
||||
pub enum Yes {}
|
||||
/// A unit marker enum.
|
||||
pub enum Maybe {}
|
||||
/// A unit marker enum.
|
||||
pub enum No {}
|
||||
|
||||
/// This is implemented for [`Yes`] and [`No`] and
|
||||
/// allows us to check at runtime which of these types is present.
|
||||
pub trait YesNo {
|
||||
/// [`Yes`]
|
||||
fn is_yes() -> bool { false }
|
||||
/// [`No`]
|
||||
fn is_no() -> bool { false }
|
||||
}
|
||||
|
||||
impl YesNo for Yes {
|
||||
fn is_yes() -> bool { true }
|
||||
}
|
||||
impl YesNo for No {
|
||||
fn is_no() -> bool { true }
|
||||
}
|
||||
|
||||
/// This is implemented for [`Yes`] and [`Maybe`] and
|
||||
/// allows us to check at runtime which of these types is present.
|
||||
|
||||
@@ -21,7 +21,7 @@ pub use dispatch_error::{
|
||||
pub use crate::metadata::Metadata;
|
||||
pub use scale_decode::Error as DecodeError;
|
||||
pub use scale_encode::Error as EncodeError;
|
||||
pub use subxt_core::error::{ExtrinsicError, MetadataError, StorageAddressError};
|
||||
pub use subxt_core::error::{ExtrinsicError, MetadataError, StorageError};
|
||||
pub use subxt_metadata::TryFromError as MetadataTryFromError;
|
||||
|
||||
/// The underlying error enum, generic over the type held by the `Runtime`
|
||||
@@ -68,7 +68,7 @@ pub enum Error {
|
||||
Block(#[from] BlockError),
|
||||
/// An error encoding a storage address.
|
||||
#[error("Error encoding storage address: {0}")]
|
||||
StorageAddress(#[from] StorageAddressError),
|
||||
StorageAddress(#[from] StorageError),
|
||||
/// The bytes representing an error that we were unable to decode.
|
||||
#[error("An error occurred but it could not be decoded: {0:?}")]
|
||||
Unknown(Vec<u8>),
|
||||
@@ -87,7 +87,7 @@ impl From<CoreError> for Error {
|
||||
match value {
|
||||
CoreError::Codec(e) => Error::Codec(e),
|
||||
CoreError::Metadata(e) => Error::Metadata(e),
|
||||
CoreError::StorageAddress(e) => Error::StorageAddress(e),
|
||||
CoreError::StorageError(e) => Error::StorageAddress(e),
|
||||
CoreError::Decode(e) => Error::Decode(e),
|
||||
CoreError::Encode(e) => Error::Encode(e),
|
||||
CoreError::Extrinsic(e) => Error::Extrinsic(e),
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
backend::{BackendExt, BlockRef},
|
||||
client::{OfflineClientT, OnlineClientT},
|
||||
config::{Config, HashFor},
|
||||
error::{Error, MetadataError, StorageAddressError},
|
||||
error::{Error, MetadataError, StorageError},
|
||||
metadata::DecodeWithMetadata,
|
||||
storage::storage_value::StorageValue,
|
||||
};
|
||||
@@ -542,12 +542,12 @@ where
|
||||
}
|
||||
|
||||
/// Strips the first 32 bytes (16 for the pallet hash, 16 for the entry hash) off some storage address bytes.
|
||||
fn strip_storage_address_root_bytes(address_bytes: &mut &[u8]) -> Result<(), StorageAddressError> {
|
||||
fn strip_storage_address_root_bytes(address_bytes: &mut &[u8]) -> Result<(), StorageError> {
|
||||
if address_bytes.len() >= 32 {
|
||||
*address_bytes = &address_bytes[32..];
|
||||
Ok(())
|
||||
} else {
|
||||
Err(StorageAddressError::UnexpectedAddressBytes)
|
||||
Err(StorageError::UnexpectedAddressBytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user