diff --git a/core/src/blocks/extrinsic_transaction_extensions.rs b/core/src/blocks/extrinsic_transaction_extensions.rs index 12e0ca4fe6..375fa6d869 100644 --- a/core/src/blocks/extrinsic_transaction_extensions.rs +++ b/core/src/blocks/extrinsic_transaction_extensions.rs @@ -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>(&self) -> Result, Error> { + pub fn find>(&self) -> Result, ExtrinsicError> { for ext in self.iter() { match ext.as_signed_extension::() { // 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, Error> { + pub fn value(&self) -> Result, 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>( &self, - ) -> Result, Error> { + ) -> Result, ExtrinsicError> { if !S::matches(self.identifier, self.ty_id, self.metadata.types()) { return Ok(None); } self.as_type::().map(Some) } - fn as_type(&self) -> Result { - let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?; + fn as_type(&self) -> Result { + 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) } } diff --git a/core/src/blocks/extrinsics.rs b/core/src/blocks/extrinsics.rs index 39673bed03..0644cb64ca 100644 --- a/core/src/blocks/extrinsics.rs +++ b/core/src/blocks/extrinsics.rs @@ -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 Extrinsics { /// 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>, metadata: Metadata) -> Result { + pub fn decode_from(extrinsics: Vec>, metadata: Metadata) -> Result { let hasher = T::Hasher::new(&metadata); let extrinsics = extrinsics .into_iter() @@ -43,7 +42,7 @@ impl Extrinsics { &metadata, metadata.types(), ) - .map_err(|error| BlockError::ExtrinsicDecodeError { + .map_err(|error| ExtrinsicError::ExtrinsicDecodeError { extrinsic_index, error, })? @@ -51,7 +50,7 @@ impl Extrinsics { // 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 Extrinsics { Ok(Arc::new((decoded_info, bytes))) }) - .collect::>()?; + .collect::>()?; Ok(Self { extrinsics, @@ -105,7 +104,7 @@ impl Extrinsics { /// If an error occurs, all subsequent iterations return `None`. pub fn find( &self, - ) -> impl Iterator, Error>> { + ) -> impl Iterator, ExtrinsicError>> { self.iter().filter_map(|details| { match details.as_extrinsic::() { // Failed to decode extrinsic: @@ -119,18 +118,18 @@ impl Extrinsics { /// 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(&self) -> Result>, Error> { + pub fn find_first(&self) -> Result>, ExtrinsicError> { self.find::().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(&self) -> Result>, Error> { + pub fn find_last(&self) -> Result>, ExtrinsicError> { self.find::().last().transpose() } /// Find an extrinsics that decodes to the type provided. Returns true if it was found. - pub fn has(&self) -> Result { + pub fn has(&self) -> Result { Ok(self.find::().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, 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, Error> { + pub fn field_values(&self) -> Result, 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(&self) -> Result, Error> { - let extrinsic_metadata = self.extrinsic_metadata()?; - if extrinsic_metadata.pallet.name() == E::PALLET - && extrinsic_metadata.variant.name == E::CALL + pub fn as_extrinsic(&self) -> Result, 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(&self) -> Result { + pub fn as_root_extrinsic(&self) -> Result { 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" ); diff --git a/core/src/blocks/mod.rs b/core/src/blocks/mod.rs index 3114bf0573..2b0589ed21 100644 --- a/core/src/blocks/mod.rs +++ b/core/src/blocks/mod.rs @@ -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( extrinsics: Vec>, metadata: Metadata, -) -> Result, Error> { +) -> Result, ExtrinsicError> { Extrinsics::decode_from(extrinsics, metadata) } diff --git a/core/src/constants/mod.rs b/core/src/constants/mod.rs index 39e0eefeba..f7f0854393 100644 --- a/core/src/constants/mod.rs +++ b/core/src/constants/mod.rs @@ -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(address: &Addr, metadata: &Metadata) -> Result<(), Error> { +pub fn validate(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(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(address: &Addr, metadata: &Metadata) -> Result { +pub fn get(address: &Addr, metadata: &Metadata) -> Result { // 1. Validate constant shape if hash given: validate(address, metadata)?; @@ -75,7 +75,7 @@ pub fn get(address: &Addr, metadata: &Metadata) -> Result::decode_with_metadata( &mut constant.value(), constant.ty(), diff --git a/core/src/custom_values/address.rs b/core/src/custom_values/address.rs index 6bbacaed68..2d3ffbbc7b 100644 --- a/core/src/custom_values/address.rs +++ b/core/src/custom_values/address.rs @@ -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 StaticAddress { } } -impl Address for StaticAddress { - type Target = R; - type IsDecodable = Y; +impl Address for StaticAddress { + type Target = Target; + type IsDecodable = IsDecodable; fn name(&self) -> &str { self.name diff --git a/core/src/error.rs b/core/src/error.rs index c4eaf51ca6..29eb14ff70 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -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 for Error { - fn from(err: scale_decode::visitor::DecodeError) -> Error { - Error::Decode(err.into()) - } +// impl From 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 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 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), + #[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), - /// 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 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), } diff --git a/core/src/storage/mod.rs b/core/src/storage/mod.rs index 5e2020390b..9af1da56a3 100644 --- a/core/src/storage/mod.rs +++ b/core/src/storage/mod.rs @@ -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>( &**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( 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( ) -> Result, 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) } diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs index 50da64197a..d441cab3c6 100644 --- a/core/src/utils/mod.rs +++ b/core/src/utils/mod.rs @@ -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; diff --git a/core/src/utils/yesnomaybe.rs b/core/src/utils/yesnomaybe.rs index af8796d8d2..d28a54f627 100644 --- a/core/src/utils/yesnomaybe.rs +++ b/core/src/utils/yesnomaybe.rs @@ -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. diff --git a/subxt/src/error/mod.rs b/subxt/src/error/mod.rs index d19bdba198..d40d75ed1f 100644 --- a/subxt/src/error/mod.rs +++ b/subxt/src/error/mod.rs @@ -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), @@ -87,7 +87,7 @@ impl From 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), diff --git a/subxt/src/storage/storage_client_at.rs b/subxt/src/storage/storage_client_at.rs index 110820f632..c2db892fff 100644 --- a/subxt/src/storage/storage_client_at.rs +++ b/subxt/src/storage/storage_client_at.rs @@ -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) } }