diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ce94eb..cd1d17b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ +## 0.13.0 (2025-11-14) + +- Separate the iterating over entries from the core `frame-decode` `*Info` traits; One only needs to implement `*Info` traits to work with `frame-decode`; the other traits are convenience traits. +- Make `Entry` type generic so that it can potentially be used in more places, expose it, and expose concrete versions from each module. +- Expose Kusama RC and AH types (though keep these hidden until the types are more complete). +- Remove `helpers::list_storage_entries_any`: it was a bit of an anomaly to have this and not a version for any other thing. Better to keep this upstream for now. + ## 0.12.1 (2025-11-12) - Add `map_ids()` functions to `RuntimeApiInfo`, `StorageInfo` and `ViewFunctionInfo` to make translating the `TypeId` parameter simpler. diff --git a/Cargo.lock b/Cargo.lock index e15bda5..b46a89f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,7 +161,7 @@ checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "frame-decode" -version = "0.12.1" +version = "0.13.0" dependencies = [ "frame-metadata", "hex", diff --git a/Cargo.toml b/Cargo.toml index 7b6972c..f292e5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frame-decode" -version = "0.12.1" +version = "0.13.0" edition = "2024" description = "Decode extrinsics and storage from Substrate based chains" license = "Apache-2.0" diff --git a/src/lib.rs b/src/lib.rs index 64bb23e..6a03a72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,9 +52,10 @@ pub mod storage { //! from modern or historic runtimes. //! - See [`encode_storage_key_prefix`] to encode storage prefixes, and [`encode_storage_key`] to encode //! storage keys. - //! - See [`StorageTypeInfo`] for the underlying trait which extracts the relevant information. + //! - See [`StorageTypeInfo`] for the underlying trait which provides storage entry information. + //! - See [`StorageEntryInfo`] for a underlying trait which provides information about the available + //! storage entries. - pub use crate::methods::Entry; pub use crate::methods::storage_decoder::{ StorageKey, StorageKeyDecodeError, StorageKeyPart, StorageKeyPartValue, StorageKeyValueDecodeError, StorageValueDecodeError, @@ -68,7 +69,8 @@ pub mod storage { encode_storage_key_with_info, encode_storage_key_with_info_to, }; pub use crate::methods::storage_type_info::{ - StorageHasher, StorageInfo, StorageInfoError, StorageKeyInfo, StorageTypeInfo, + StorageEntry, StorageEntryInfo, StorageHasher, StorageInfo, StorageInfoError, + StorageKeyInfo, StorageTypeInfo, }; pub use crate::utils::{ DecodableValues, EncodableValues, IntoDecodableValues, IntoEncodableValues, @@ -81,13 +83,14 @@ pub mod constants { //! - See [`decode_constant`] and [`decode_constant_with_info`] to decode constants //! - See [`ConstantTypeInfo`] for the underlying trait which extracts constant //! information from metadata. + //! - See [`ConstantEntryInfo`] for a underlying trait which provides information about the available + //! constants. - pub use crate::methods::Entry; pub use crate::methods::constant_decoder::{ ConstantDecodeError, decode_constant, decode_constant_with_info, }; pub use crate::methods::constant_type_info::{ - ConstantInfo, ConstantInfoError, ConstantTypeInfo, + ConstantEntry, ConstantEntryInfo, ConstantInfo, ConstantInfoError, ConstantTypeInfo, }; } @@ -98,8 +101,9 @@ pub mod runtime_apis { //! the name and inputs to make a Runtime API call. //! - See [`decode_runtime_api_response`] to decode Runtime API responses. //! - See [`RuntimeApiTypeInfo`] for the underlying trait which extracts the relevant information. + //! - See [`RuntimeApiEntryInfo`] for a underlying trait which provides information about the available + //! Runtime APIs. - pub use crate::methods::Entry; pub use crate::methods::runtime_api_decoder::{ RuntimeApiDecodeError, decode_runtime_api_response, decode_runtime_api_response_with_info, }; @@ -108,7 +112,8 @@ pub mod runtime_apis { encode_runtime_api_inputs_with_info_to, encode_runtime_api_name, }; pub use crate::methods::runtime_api_type_info::{ - RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput, RuntimeApiTypeInfo, + RuntimeApiEntry, RuntimeApiEntryInfo, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput, + RuntimeApiTypeInfo, }; pub use crate::utils::{EncodableValues, IntoEncodableValues}; } @@ -120,8 +125,9 @@ pub mod view_functions { //! and the encoded input data required to call a given View Function. //! - See [`decode_view_function_response`] to decode View Function responses. //! - See [`ViewFunctionTypeInfo`] for the underlying trait which extracts the relevant information. + //! - See [`ViewFunctionEntryInfo`] for a underlying trait which provides information about the available + //! View Functions. - pub use crate::methods::Entry; pub use crate::methods::view_function_decoder::{ ViewFunctionDecodeError, decode_view_function_response, decode_view_function_response_with_info, @@ -131,7 +137,8 @@ pub mod view_functions { encode_view_function_inputs_to, encode_view_function_inputs_with_info_to, }; pub use crate::methods::view_function_type_info::{ - ViewFunctionInfo, ViewFunctionInfoError, ViewFunctionInput, ViewFunctionTypeInfo, + ViewFunctionEntry, ViewFunctionEntryInfo, ViewFunctionInfo, ViewFunctionInfoError, + ViewFunctionInput, ViewFunctionTypeInfo, }; pub use crate::utils::{EncodableValues, IntoEncodableValues}; } @@ -142,12 +149,15 @@ pub mod custom_values { //! - See [`decode_custom_value`] and [`decode_custom_value_with_info`] to decode custom values //! - See [`CustomValueTypeInfo`] for the underlying trait which extracts custom value //! information from metadata. + //! - See [`CustomValueEntryInfo`] for a underlying trait which provides information about the available + //! custom values. pub use crate::methods::custom_value_decoder::{ CustomValueDecodeError, decode_custom_value, decode_custom_value_with_info, }; pub use crate::methods::custom_value_type_info::{ - CustomValue, CustomValueInfo, CustomValueInfoError, CustomValueTypeInfo, + CustomValue, CustomValueEntryInfo, CustomValueInfo, CustomValueInfoError, + CustomValueTypeInfo, }; } @@ -162,8 +172,30 @@ pub mod legacy_types { pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry { // This is a convenience function to load the Polkadot relay chain types. // It is used in the examples in this crate. - let bytes = include_bytes!("../types/polkadot_types.yaml"); - serde_yaml::from_slice(bytes).expect("Polkadot types are valid YAML") + let bytes = include_bytes!("../types/polkadot_relay_types.yaml"); + serde_yaml::from_slice(bytes).expect("Polkadot RC types are valid YAML") + } + } + + // Hidden until the types are ready. + #[doc(hidden)] + pub mod kusama { + //! Legacy types for Kusama chains. + + /// Legacy types for the Kusama Relay Chain. + pub fn relay_chain() -> scale_info_legacy::ChainTypeRegistry { + // This is a convenience function to load the Polkadot relay chain types. + // It is used in the examples in this crate. + let bytes = include_bytes!("../types/kusama_relay_types.yaml"); + serde_yaml::from_slice(bytes).expect("Kusama RC types are valid YAML") + } + + /// Legacy types for the Kusama Asset Hub. + pub fn asset_hub() -> scale_info_legacy::ChainTypeRegistry { + // This is a convenience function to load the Polkadot relay chain types. + // It is used in the examples in this crate. + let bytes = include_bytes!("../types/kusama_assethub_types.yaml"); + serde_yaml::from_slice(bytes).expect("Kusama AssetHub types are valid YAML") } } } @@ -177,9 +209,11 @@ pub mod helpers { //! will use a tracing visitor (if the `error-tracing` feature is enabled) to provide more //! information in the event that decoding fails. + pub use crate::methods::Entry; + pub use crate::utils::{ DecodableValues, DecodeErrorTrace, EncodableValues, IntoDecodableValues, - IntoEncodableValues, decode_with_error_tracing, list_storage_entries_any, + IntoEncodableValues, decode_with_error_tracing, }; #[cfg(feature = "legacy")] pub use crate::utils::{type_registry_from_metadata, type_registry_from_metadata_any}; @@ -205,6 +239,8 @@ mod test { #[test] fn test_deserializing_legacy_types() { let _ = crate::legacy_types::polkadot::relay_chain(); + let _ = crate::legacy_types::kusama::relay_chain(); + let _ = crate::legacy_types::kusama::asset_hub(); } macro_rules! impls_trait { diff --git a/src/methods/constant_type_info.rs b/src/methods/constant_type_info.rs index be0ed1d..a3421c0 100644 --- a/src/methods/constant_type_info.rs +++ b/src/methods/constant_type_info.rs @@ -28,14 +28,25 @@ pub trait ConstantTypeInfo { pallet_name: &str, constant_name: &str, ) -> Result, ConstantInfoError<'_>>; - /// Iterate over all of the available Constants. - fn constants(&self) -> impl Iterator>; +} + +/// This can be implemented for anything capable of providing information about the available Constants +pub trait ConstantEntryInfo { + /// Iterate over all of the available Constants, returning [`Entry`] as we go. + fn constant_entries(&self) -> impl Iterator>; + /// Iterate over all of the available Constants, returning a pair of `(pallet_name, constant_name)` as we go. + fn constant_tuples(&self) -> impl Iterator, Cow<'_, str>)> { + Entry::tuples_of(self.constant_entries()) + } /// Iterate over all of the available constants in a given pallet. fn constants_in_pallet(&self, pallet: &str) -> impl Iterator> { - Entry::entries_in(self.constants(), pallet) + Entry::entries_in(self.constant_entries(), pallet) } } +/// An entry denoting a pallet or a constant name. +pub type ConstantEntry<'a> = Entry, Cow<'a, str>>; + /// An error returned trying to access Constant information. #[non_exhaustive] #[allow(missing_docs)] @@ -82,6 +93,7 @@ impl<'info> ConstantInfoError<'info> { } /// Information about a Constant. +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstantInfo<'info, TypeId: Clone> { /// The bytes representing this constant. /// @@ -98,7 +110,6 @@ macro_rules! impl_constant_type_info_for_v14_to_v16 { use $path as path; impl ConstantTypeInfo for path::$name { type TypeId = u32; - fn constant_info( &self, pallet_name: &str, @@ -128,17 +139,17 @@ macro_rules! impl_constant_type_info_for_v14_to_v16 { type_id: constant.ty.id, }) } - - fn constants(&self) -> impl Iterator> { + } + impl ConstantEntryInfo for path::$name { + fn constant_entries(&self) -> impl Iterator> { self.pallets.iter().flat_map(|p| { - core::iter::once(Entry::In(Cow::Borrowed(&p.name))).chain( + core::iter::once(Entry::In(Cow::Borrowed(&*p.name))).chain( p.constants .iter() - .map(|c| Entry::Name(Cow::Borrowed(&c.name))), + .map(|c| Entry::Name(Cow::Borrowed(&*c.name))), ) }) } - fn constants_in_pallet( &self, pallet_name: &str, @@ -175,7 +186,6 @@ mod legacy { use $path as path; impl ConstantTypeInfo for path::$name { type TypeId = LookupName; - fn constant_info( &self, pallet_name: &str, @@ -209,21 +219,21 @@ mod legacy { type_id, }) } - - fn constants(&self) -> impl Iterator> { + } + impl ConstantEntryInfo for path::$name { + fn constant_entries(&self) -> impl Iterator> { as_decoded(&self.modules).iter().flat_map(|module| { let pallet_name = as_decoded(&module.name); let constants = as_decoded(&module.constants); - core::iter::once(Entry::In(Cow::Borrowed(pallet_name))).chain( + core::iter::once(Entry::In(Cow::Borrowed(&**pallet_name))).chain( constants.iter().map(|c| { let constant_name = as_decoded(&c.name); - Entry::Name(Cow::Borrowed(constant_name)) + Entry::Name(Cow::Borrowed(&**constant_name)) }), ) }) } - fn constants_in_pallet( &self, pallet_name: &str, diff --git a/src/methods/custom_value_type_info.rs b/src/methods/custom_value_type_info.rs index 6f96b5d..5611867 100644 --- a/src/methods/custom_value_type_info.rs +++ b/src/methods/custom_value_type_info.rs @@ -25,7 +25,11 @@ pub trait CustomValueTypeInfo { &self, name: &str, ) -> Result, CustomValueInfoError>; - /// Iterate over all of the available Custom Values. +} + +/// This can be implemented for anything capable of providing information about the available Custom Values +pub trait CustomValueEntryInfo { + /// Iterate over all of the available Custom Values, returning [`CustomValue`] as we go. fn custom_values(&self) -> impl Iterator>; } @@ -39,6 +43,7 @@ pub struct CustomValueInfoError { } /// Information about a Custom Value. +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CustomValueInfo<'info, TypeId: Clone> { /// The bytes representing this custom value. /// @@ -52,7 +57,7 @@ pub struct CustomValueInfo<'info, TypeId: Clone> { } /// The identifier for a single Custom Value. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CustomValue<'info> { /// The name of this Custom Value. pub name: Cow<'info, str>, @@ -64,7 +69,6 @@ macro_rules! impl_custom_value_type_info_for_v15_to_v16 { use $path as path; impl CustomValueTypeInfo for path::$name { type TypeId = u32; - fn custom_value_info( &self, name: &str, @@ -82,7 +86,8 @@ macro_rules! impl_custom_value_type_info_for_v15_to_v16 { type_id: custom_value.ty.id, }) } - + } + impl CustomValueEntryInfo for path::$name { fn custom_values(&self) -> impl Iterator> { self.custom.map.iter().map(|(name, _)| CustomValue { name: Cow::Borrowed(name), diff --git a/src/methods/extrinsic_type_info.rs b/src/methods/extrinsic_type_info.rs index 9494495..b24f869 100644 --- a/src/methods/extrinsic_type_info.rs +++ b/src/methods/extrinsic_type_info.rs @@ -215,7 +215,7 @@ impl ExtrinsicInfoError<'_> { } /// An argument with a name and type ID. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtrinsicInfoArg<'info, TypeId> { /// Argument name. pub name: Cow<'info, str>, @@ -224,7 +224,7 @@ pub struct ExtrinsicInfoArg<'info, TypeId> { } /// Extrinsic call data information. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtrinsicCallInfo<'info, TypeId> { /// Name of the pallet. pub pallet_name: Cow<'info, str>, @@ -235,7 +235,7 @@ pub struct ExtrinsicCallInfo<'info, TypeId> { } /// Extrinsic signature information. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtrinsicSignatureInfo { /// Type ID of the address. pub address_id: TypeId, @@ -244,7 +244,7 @@ pub struct ExtrinsicSignatureInfo { } /// Extrinsic extension information. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtrinsicExtensionInfo<'info, TypeId> { /// Names and type IDs of the transaction extensions. pub extension_ids: Vec>, diff --git a/src/methods/mod.rs b/src/methods/mod.rs index ef30c4e..f5f9d24 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -29,8 +29,6 @@ pub mod view_function_decoder; pub mod view_function_encoder; pub mod view_function_type_info; -use alloc::borrow::Cow; - /// This represents either an entry name, or the name of the thing that the entry is /// in (for instance the name of a pallet or of a Runtime API trait). /// @@ -41,30 +39,36 @@ use alloc::borrow::Cow; /// /// A container name will not be handed back more than once. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Entry<'info> { +pub enum Entry { /// The name of the thing that the following entries are in/under. - In(Cow<'info, str>), + In(In), /// The name of the entry in/under the last given [`Entry::In`]. - Name(Cow<'info, str>), + Name(Name), } -impl<'info> Entry<'info> { - /// Take ownership of the entry, converting any lifetimes to `'static`. - pub fn into_owned(self) -> Entry<'static> { +impl Entry { + /// Map the values in the entry, assuming they are the same. + pub fn map R>(self, f: F) -> Entry { match self { - Entry::In(name) => Entry::In(Cow::Owned(name.into_owned())), - Entry::Name(name) => Entry::Name(Cow::Owned(name.into_owned())), + Entry::In(t) => Entry::In(f(t)), + Entry::Name(t) => Entry::Name(f(t)), } } +} +impl Entry { /// Iterate over all of the entries in a specific container (ie all of the entries /// which follow a specific [`Entry::In`]). - pub fn entries_in<'a>( - entries: impl Iterator>, - container: &str, - ) -> impl Iterator> { + pub fn entries_in( + entries: impl Iterator>, + container: impl PartialEq, + ) -> impl Iterator + where + In: PartialEq, + Name: PartialEq, + { entries - .skip_while(|c| c != &Entry::In(Cow::Borrowed(container))) + .skip_while(move |c| !matches!(c, Entry::In(c) if &container == c)) .skip(1) .take_while(|c| matches!(c, Entry::Name(_))) .filter_map(|c| match c { @@ -72,6 +76,27 @@ impl<'info> Entry<'info> { Entry::Name(name) => Some(name), }) } + + /// Iterate over all of the entries, returning tuples of `(entry_in, entry_name)`. + /// This can be easier to work with in some cases. + pub fn tuples_of( + entries: impl Iterator>, + ) -> impl Iterator + where + In: Clone, + { + let mut entry_in = None; + entries.filter_map(move |entry| match entry { + Entry::In(e_in) => { + entry_in = Some(e_in); + None + } + Entry::Name(e_name) => { + let e_in = entry_in.as_ref().unwrap().clone(); + Some((e_in, e_name)) + } + }) + } } #[cfg(test)] @@ -80,16 +105,16 @@ mod test { #[test] fn test_entries_in() { - fn entries() -> impl Iterator> { + fn entries() -> impl Iterator> { [ - Entry::In("Baz".into()), - Entry::In("Foo".into()), - Entry::Name("foo_a".into()), - Entry::Name("foo_b".into()), - Entry::Name("foo_c".into()), - Entry::In("Bar".into()), - Entry::Name("bar_a".into()), - Entry::In("Wibble".into()), + Entry::In("Baz"), + Entry::In("Foo"), + Entry::Name("foo_a"), + Entry::Name("foo_b"), + Entry::Name("foo_c"), + Entry::In("Bar"), + Entry::Name("bar_a"), + Entry::In("Wibble"), ] .into_iter() } @@ -98,7 +123,7 @@ mod test { assert!(Entry::entries_in(entries(), "Wibble").next().is_none()); let foos: Vec = Entry::entries_in(entries(), "Foo") - .map(|s| s.into_owned()) + .map(|s| s.to_owned()) .collect(); assert_eq!( foos, @@ -106,7 +131,7 @@ mod test { ); let bars: Vec = Entry::entries_in(entries(), "Bar") - .map(|s| s.into_owned()) + .map(|s| s.to_owned()) .collect(); assert_eq!(bars, Vec::from_iter(["bar_a".to_owned(),])); } diff --git a/src/methods/runtime_api_type_info.rs b/src/methods/runtime_api_type_info.rs index d88a3da..d50104a 100644 --- a/src/methods/runtime_api_type_info.rs +++ b/src/methods/runtime_api_type_info.rs @@ -31,14 +31,25 @@ pub trait RuntimeApiTypeInfo { trait_name: &str, method_name: &str, ) -> Result, RuntimeApiInfoError<'_>>; - /// Iterate over all of the available Runtime APIs. - fn runtime_apis(&self) -> impl Iterator>; - /// Iterate over all of the available Runtime APIs in a given trait. - fn runtime_apis_in_trait(&self, trait_name: &str) -> impl Iterator> { - Entry::entries_in(self.runtime_apis(), trait_name) +} + +/// This can be implemented for anything capable of providing information about the available Runtime Apis +pub trait RuntimeApiEntryInfo { + /// Iterate over all of the available Runtime Apis, returning [`Entry`] as we go. + fn runtime_api_entries(&self) -> impl Iterator>; + /// Iterate over all of the available Runtime Apis, returning a pair of `(trait_name, method_name)` as we go. + fn runtime_api_tuples(&self) -> impl Iterator, Cow<'_, str>)> { + Entry::tuples_of(self.runtime_api_entries()) + } + /// Iterate over all of the available Runtime Apis in a given trait. + fn runtime_apis_in_trait(&self, pallet: &str) -> impl Iterator> { + Entry::entries_in(self.runtime_api_entries(), pallet) } } +/// An entry denoting a Runtime API trait or method. +pub type RuntimeApiEntry<'a> = Entry, Cow<'a, str>>; + /// An error returned trying to access Runtime API type information. #[non_exhaustive] #[allow(missing_docs)] @@ -72,7 +83,7 @@ impl<'info> RuntimeApiInfoError<'info> { } /// Information about a Runtime API. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct RuntimeApiInfo<'info, TypeId: Clone> { /// Inputs to the runtime API. pub inputs: Cow<'info, [RuntimeApiInput<'info, TypeId>]>, @@ -133,7 +144,7 @@ impl<'info, TypeId: Clone + 'static> RuntimeApiInfo<'info, TypeId> { } /// Information about a specific input value to a Runtime API. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct RuntimeApiInput<'info, TypeId> { /// Name of the input. pub name: Cow<'info, str>, @@ -157,7 +168,6 @@ macro_rules! impl_runtime_api_info_for_v15_to_v16 { use $path as path; impl RuntimeApiTypeInfo for path::$name { type TypeId = u32; - fn runtime_api_info( &self, trait_name: &str, @@ -192,17 +202,17 @@ macro_rules! impl_runtime_api_info_for_v15_to_v16 { output_id: method.output.id, }) } - - fn runtime_apis(&self) -> impl Iterator> { + } + impl RuntimeApiEntryInfo for path::$name { + fn runtime_api_entries(&self) -> impl Iterator> { self.apis.iter().flat_map(|api| { - core::iter::once(Entry::In(Cow::Borrowed(&api.name))).chain( + core::iter::once(Entry::In(Cow::Borrowed(&*api.name))).chain( api.methods .iter() - .map(|m| Entry::Name(Cow::Borrowed(&m.name))), + .map(|m| Entry::Name(Cow::Borrowed(&*m.name))), ) }) } - fn runtime_apis_in_trait( &self, trait_name: &str, @@ -262,14 +272,14 @@ mod legacy { output_id: api.output.clone(), }) } - - fn runtime_apis(&self) -> impl Iterator> { + } + impl RuntimeApiEntryInfo for TypeRegistry { + fn runtime_api_entries(&self) -> impl Iterator> { self.runtime_apis().map(|api| match api { RuntimeApiName::Trait(name) => Entry::In(Cow::Borrowed(name)), RuntimeApiName::Method(name) => Entry::Name(Cow::Borrowed(name)), }) } - fn runtime_apis_in_trait(&self, trait_name: &str) -> impl Iterator> { TypeRegistry::runtime_apis_in_trait(self, trait_name).map(Cow::Borrowed) } @@ -304,8 +314,9 @@ mod legacy { output_id: api.output.clone(), }) } - - fn runtime_apis(&self) -> impl Iterator> { + } + impl<'a> RuntimeApiEntryInfo for TypeRegistrySet<'a> { + fn runtime_api_entries(&self) -> impl Iterator> { self.runtime_apis().map(|api| match api { RuntimeApiName::Trait(name) => Entry::In(Cow::Borrowed(name)), RuntimeApiName::Method(name) => Entry::Name(Cow::Borrowed(name)), diff --git a/src/methods/storage_type_info.rs b/src/methods/storage_type_info.rs index bbf462b..09520f9 100644 --- a/src/methods/storage_type_info.rs +++ b/src/methods/storage_type_info.rs @@ -32,15 +32,25 @@ pub trait StorageTypeInfo { pallet_name: &str, storage_entry: &str, ) -> Result, StorageInfoError<'_>>; +} - /// Iterate over all of the available storage entries. - fn storage_entries(&self) -> impl Iterator>; - /// Iterate over all of the available storage entries in a given pallet. - fn storage_entries_in_pallet(&self, pallet_name: &str) -> impl Iterator> { - Entry::entries_in(self.storage_entries(), pallet_name) +/// This can be implemented for anything capable of providing information about the available Storage Entries +pub trait StorageEntryInfo { + /// Iterate over all of the available Storage Entries, returning [`Entry`] as we go. + fn storage_entries(&self) -> impl Iterator>; + /// Iterate over all of the available Storage Entries, returning a pair of `(pallet_name, constant_name)` as we go. + fn storage_tuples(&self) -> impl Iterator, Cow<'_, str>)> { + Entry::tuples_of(self.storage_entries()) + } + /// Iterate over all of the available Storage Entries in a given pallet. + fn storage_in_pallet(&self, pallet: &str) -> impl Iterator> { + Entry::entries_in(self.storage_entries(), pallet) } } +/// An entry denoting a pallet or a constant name. +pub type StorageEntry<'a> = Entry, Cow<'a, str>>; + /// An error returned trying to access storage type information. #[non_exhaustive] #[allow(missing_docs)] @@ -121,7 +131,7 @@ impl StorageInfoError<'_> { } /// Information about a storage entry. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct StorageInfo<'info, TypeId: Clone> { /// No entries if a plain storage entry, or N entries for N maps. pub keys: Cow<'info, [StorageKeyInfo]>, @@ -166,7 +176,7 @@ impl<'info, TypeId: Clone + 'static> StorageInfo<'info, TypeId> { } /// Information about a single key within a storage entry. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct StorageKeyInfo { /// How is this key hashed? pub hasher: StorageHasher, @@ -343,7 +353,9 @@ macro_rules! impl_storage_type_info_for_v14_to_v16 { storage_entry_type_to_storage_info(&pallet.name, &storage, &self.types) } - fn storage_entries(&self) -> impl Iterator> { + } + impl StorageEntryInfo for path::$name { + fn storage_entries(&self) -> impl Iterator> { self.pallets.iter().flat_map(|p| { // Not strictly necessary, but we may as well filter out // returning palelt names that have no entries in them. @@ -352,16 +364,16 @@ macro_rules! impl_storage_type_info_for_v14_to_v16 { }; Either::Right( - core::iter::once(Entry::In(Cow::Borrowed(&p.name))).chain( + core::iter::once(Entry::In(Cow::Borrowed(&*p.name))).chain( storage .entries .iter() - .map(|e| Entry::Name(Cow::Borrowed(&e.name))), + .map(|e| Entry::Name(Cow::Borrowed(&*e.name))), ), ) }) } - fn storage_entries_in_pallet( + fn storage_in_pallet( &self, pallet_name: &str, ) -> impl Iterator> { @@ -528,7 +540,9 @@ mod legacy { } } } - fn storage_entries(&self) -> impl Iterator> { + } + impl StorageEntryInfo for path::$name { + fn storage_entries(&self) -> impl Iterator> { use crate::utils::as_decoded; as_decoded(&self.modules).iter().flat_map(|module| { let Some(storage) = &module.storage else { @@ -538,15 +552,17 @@ mod legacy { let storage = as_decoded(storage); let entries = as_decoded(&storage.entries); - Either::Right(core::iter::once(Entry::In(Cow::Borrowed(pallet))).chain( - entries.iter().map(|e| { - let entry = as_decoded(&e.name); - Entry::Name(Cow::Borrowed(entry.as_ref())) - }), - )) + Either::Right( + core::iter::once(Entry::In(Cow::Borrowed(pallet.as_ref()))).chain( + entries.iter().map(|e| { + let entry = as_decoded(&e.name); + Entry::Name(Cow::Borrowed(entry.as_ref())) + }), + ), + ) }) } - fn storage_entries_in_pallet( + fn storage_in_pallet( &self, pallet_name: &str, ) -> impl Iterator> { @@ -737,8 +753,9 @@ mod legacy { } } } - - fn storage_entries(&self) -> impl Iterator> { + } + impl StorageEntryInfo for frame_metadata::v13::RuntimeMetadataV13 { + fn storage_entries(&self) -> impl Iterator> { use crate::utils::as_decoded; as_decoded(&self.modules).iter().flat_map(|module| { let Some(storage) = &module.storage else { @@ -748,19 +765,18 @@ mod legacy { let storage = as_decoded(storage); let entries = as_decoded(&storage.entries); - Either::Right(core::iter::once(Entry::In(Cow::Borrowed(pallet))).chain( - entries.iter().map(|e| { - let entry = as_decoded(&e.name); - Entry::Name(Cow::Borrowed(entry.as_ref())) - }), - )) + Either::Right( + core::iter::once(Entry::In(Cow::Borrowed(pallet.as_ref()))).chain( + entries.iter().map(|e| { + let entry = as_decoded(&e.name); + Entry::Name(Cow::Borrowed(entry.as_ref())) + }), + ), + ) }) } - fn storage_entries_in_pallet( - &self, - pallet_name: &str, - ) -> impl Iterator> { + fn storage_in_pallet(&self, pallet_name: &str) -> impl Iterator> { let module = as_decoded(&self.modules) .iter() .find(|p| as_decoded(&p.name).as_ref() as &str == pallet_name); diff --git a/src/methods/view_function_type_info.rs b/src/methods/view_function_type_info.rs index f33e7b3..4c91a90 100644 --- a/src/methods/view_function_type_info.rs +++ b/src/methods/view_function_type_info.rs @@ -31,14 +31,25 @@ pub trait ViewFunctionTypeInfo { pallet_name: &str, function_name: &str, ) -> Result, ViewFunctionInfoError<'_>>; - /// Iterate over all of the available View Functions. - fn view_functions(&self) -> impl Iterator>; +} + +/// This can be implemented for anything capable of providing information about the available View Functions +pub trait ViewFunctionEntryInfo { + /// Iterate over all of the available View Functions, returning [`Entry`] as we go. + fn view_function_entries(&self) -> impl Iterator>; + /// Iterate over all of the available View Functions, returning a pair of `(pallet_name, view_function_name)` as we go. + fn view_function_tuples(&self) -> impl Iterator, Cow<'_, str>)> { + Entry::tuples_of(self.view_function_entries()) + } /// Iterate over all of the available View Functions in a given pallet. fn view_functions_in_pallet(&self, pallet: &str) -> impl Iterator> { - Entry::entries_in(self.view_functions(), pallet) + Entry::entries_in(self.view_function_entries(), pallet) } } +/// An entry denoting a pallet or a View Function name. +pub type ViewFunctionEntry<'a> = Entry, Cow<'a, str>>; + /// An error returned trying to access View Function type information. #[non_exhaustive] #[allow(missing_docs)] @@ -72,7 +83,7 @@ impl<'info> ViewFunctionInfoError<'info> { } /// Information about a View Function. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ViewFunctionInfo<'info, TypeId: Clone> { /// The query Id to use to call the view function. pub query_id: [u8; 32], @@ -137,7 +148,7 @@ impl<'info, TypeId: Clone> ViewFunctionInfo<'info, TypeId> { } /// Information about a specific input value to a View Function. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ViewFunctionInput<'info, TypeId> { /// Name of the input. pub name: Cow<'info, str>, @@ -195,14 +206,16 @@ impl ViewFunctionTypeInfo for frame_metadata::v16::RuntimeMetadataV16 { output_id: view_fn.output.id, }) } +} - fn view_functions(&self) -> impl Iterator> { +impl ViewFunctionEntryInfo for frame_metadata::v16::RuntimeMetadataV16 { + fn view_function_entries(&self) -> impl Iterator> { self.pallets.iter().flat_map(|pallet| { - core::iter::once(Entry::In(Cow::Borrowed(&pallet.name))).chain( + core::iter::once(Entry::In(Cow::Borrowed(pallet.name.as_ref()))).chain( pallet .view_functions .iter() - .map(|vf| Entry::Name(Cow::Borrowed(&vf.name))), + .map(|vf| Entry::Name(Cow::Borrowed(vf.name.as_ref()))), ) }) } diff --git a/src/utils.rs b/src/utils.rs index 99425f7..8a734bc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,12 +17,10 @@ mod decodable_values; mod decode_with_error_tracing; mod either; mod encodable_values; -mod list_storage_entries_any; mod type_registry_from_metadata; pub use decodable_values::{DecodableValues, IntoDecodableValues}; pub use encodable_values::{EncodableValues, IntoEncodableValues}; -pub use list_storage_entries_any::list_storage_entries_any; pub use decode_with_error_tracing::{DecodeErrorTrace, decode_with_error_tracing}; pub use either::Either; diff --git a/src/utils/list_storage_entries_any.rs b/src/utils/list_storage_entries_any.rs deleted file mode 100644 index b5d3a72..0000000 --- a/src/utils/list_storage_entries_any.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2022-2025 Parity Technologies (UK) Ltd. (admin@parity.io) -// This file is a part of the frame-decode crate. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::methods::storage_type_info::StorageTypeInfo; -use alloc::boxed::Box; -use frame_metadata::RuntimeMetadata; - -pub use crate::methods::Entry; - -/// Returns an iterator listing the available storage entries in some metadata. -/// -/// This basically calls [`StorageTypeInfo::storage_entries()`] for each metadata version, -/// returning an empty iterator where applicable (ie when passing legacy metadata and the -/// `legacy` features flag is not enabled). -pub fn list_storage_entries_any(metadata: &RuntimeMetadata) -> impl Iterator> { - match metadata { - RuntimeMetadata::V0(_deprecated_metadata) - | RuntimeMetadata::V1(_deprecated_metadata) - | RuntimeMetadata::V2(_deprecated_metadata) - | RuntimeMetadata::V3(_deprecated_metadata) - | RuntimeMetadata::V4(_deprecated_metadata) - | RuntimeMetadata::V5(_deprecated_metadata) - | RuntimeMetadata::V6(_deprecated_metadata) - | RuntimeMetadata::V7(_deprecated_metadata) => { - Box::new(core::iter::empty()) as Box>> - } - #[cfg(feature = "legacy")] - RuntimeMetadata::V8(m) => Box::new(m.storage_entries()), - #[cfg(not(feature = "legacy"))] - RuntimeMetadata::V8(_opaque) => Box::new(core::iter::empty()), - #[cfg(feature = "legacy")] - RuntimeMetadata::V9(m) => Box::new(m.storage_entries()), - #[cfg(not(feature = "legacy"))] - RuntimeMetadata::V9(_opaque) => Box::new(core::iter::empty()), - #[cfg(feature = "legacy")] - RuntimeMetadata::V10(m) => Box::new(m.storage_entries()), - #[cfg(not(feature = "legacy"))] - RuntimeMetadata::V10(_opaque) => Box::new(core::iter::empty()), - #[cfg(feature = "legacy")] - RuntimeMetadata::V11(m) => Box::new(m.storage_entries()), - #[cfg(not(feature = "legacy"))] - RuntimeMetadata::V11(_opaque) => Box::new(core::iter::empty()), - #[cfg(feature = "legacy")] - RuntimeMetadata::V12(m) => Box::new(m.storage_entries()), - #[cfg(not(feature = "legacy"))] - RuntimeMetadata::V12(_opaque) => Box::new(core::iter::empty()), - #[cfg(feature = "legacy")] - RuntimeMetadata::V13(m) => Box::new(m.storage_entries()), - #[cfg(not(feature = "legacy"))] - RuntimeMetadata::V13(_opaque) => Box::new(core::iter::empty()), - RuntimeMetadata::V14(m) => Box::new(m.storage_entries()), - RuntimeMetadata::V15(m) => Box::new(m.storage_entries()), - RuntimeMetadata::V16(m) => Box::new(m.storage_entries()), - } -} diff --git a/types/kusama_relay_types.yaml b/types/kusama_relay_types.yaml new file mode 100644 index 0000000..1887b14 --- /dev/null +++ b/types/kusama_relay_types.yaml @@ -0,0 +1,3 @@ +# Placeholder until real types are added. +global: + types: \ No newline at end of file diff --git a/types/polkadot_types.yaml b/types/polkadot_relay_types.yaml similarity index 100% rename from types/polkadot_types.yaml rename to types/polkadot_relay_types.yaml