Begin 'fixing' errors

This commit is contained in:
James Wilson
2025-09-30 18:04:21 +01:00
parent 964c474088
commit 4606eb4679
11 changed files with 239 additions and 241 deletions
@@ -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)
}
}
+49 -46
View File
@@ -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"
);
+2 -3
View File
@@ -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)
}
+7 -7
View File
@@ -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 -6
View File
@@ -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
View File
@@ -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>),
}
+5 -5
View File
@@ -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)
}
+1 -1
View File
@@ -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;
+18
View File
@@ -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.
+3 -3
View File
@@ -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),
+3 -3
View File
@@ -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)
}
}