From 46bc4f23125ee1a2049e34295db0d960f5398d1c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 16 Sep 2024 18:06:00 +0300 Subject: [PATCH] Update to latest frame-metadata changes Signed-off-by: Alexandru Vasile --- Cargo.lock | 12 +- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- cli/src/commands/metadata.rs | 1 + cli/src/utils.rs | 4 +- codegen/src/api/associated_types.rs | 113 +++++++ codegen/src/api/mod.rs | 12 + codegen/src/fetch_metadata.rs | 4 + metadata/Cargo.toml | 2 +- metadata/src/from_into/mod.rs | 2 + metadata/src/from_into/v15.rs | 4 + metadata/src/from_into/v16.rs | 458 ++++++++++++++++++++++++++++ metadata/src/lib.rs | 36 +++ subxt/examples/metadata_config.rs | 21 +- 14 files changed, 658 insertions(+), 15 deletions(-) create mode 100644 codegen/src/api/associated_types.rs create mode 100644 metadata/src/from_into/v16.rs diff --git a/Cargo.lock b/Cargo.lock index 56902d35cd..1fe8d12457 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1830,6 +1830,16 @@ dependencies = [ "scale-info", ] +[[package]] +name = "frame-metadata" +version = "16.0.0" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + [[package]] name = "frame-metadata" version = "16.0.0" @@ -5103,7 +5113,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a616fa51350b35326682a472ee8e6ba742fdacb18babac38ecd46b3e05ead869" dependencies = [ - "frame-metadata 16.0.0", + "frame-metadata 16.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec", "scale-info", ] diff --git a/Cargo.toml b/Cargo.toml index 9803a00183..dabba45830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,7 @@ darling = "0.20.10" derive-where = "1.2.7" either = { version = "1.13.0", default-features = false } finito = { version = "0.1.0", default-features = false } -frame-metadata = { version = "16.0.0", default-features = false } +frame-metadata = { path = "/home/lexnv/workspace/frame-metadata/frame-metadata", features = ["current", "decode", "unstable"] } futures = { version = "0.3.30", default-features = false, features = ["std"] } getrandom = { version = "0.2", default-features = false } hashbrown = "0.14.5" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d6392da894..c4bc640fec 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -34,7 +34,7 @@ serde = { workspace = true, features = ["derive"] } color-eyre = { workspace = true } serde_json = { workspace = true } hex = { workspace = true } -frame-metadata = { workspace = true } +frame-metadata = { workspace = true, features = ["current", "decode", "unstable"] } codec = { package = "parity-scale-codec", workspace = true } scale-info = { workspace = true } scale-value = { workspace = true } diff --git a/cli/src/commands/metadata.rs b/cli/src/commands/metadata.rs index 292ca1c7a5..0263416f9c 100644 --- a/cli/src/commands/metadata.rs +++ b/cli/src/commands/metadata.rs @@ -41,6 +41,7 @@ pub struct Opts { } pub async fn run(opts: Opts, output: &mut impl Write) -> color_eyre::Result<()> { + println!("opts {:?}", opts); validate_url_security(opts.file_or_url.url.as_ref(), opts.allow_insecure)?; let bytes = opts.file_or_url.fetch().await?; let mut metadata = RuntimeMetadataPrefixed::decode(&mut &bytes[..])?; diff --git a/cli/src/utils.rs b/cli/src/utils.rs index 624d5256ae..e4cce6b314 100644 --- a/cli/src/utils.rs +++ b/cli/src/utils.rs @@ -122,7 +122,9 @@ impl FileOrUrl { // Default if neither is provided; fetch from local url (None, None, version) => { let url = Url::parse("ws://localhost:9944").expect("Valid URL; qed"); - Ok(fetch_metadata_from_url(url, version.unwrap_or_default()).await?) + let version = version.unwrap_or_default(); + // println!("Fetching metadata from {url} with version {version:?}"); + Ok(fetch_metadata_from_url(url, version).await?) } } } diff --git a/codegen/src/api/associated_types.rs b/codegen/src/api/associated_types.rs new file mode 100644 index 0000000000..8e0a086ce3 --- /dev/null +++ b/codegen/src/api/associated_types.rs @@ -0,0 +1,113 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use std::any::Any; + +use super::CodegenError; +use heck::{ToSnakeCase as _, ToUpperCamelCase as _}; +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote}; +use scale_typegen::typegen::ir::ToTokensWithSettings; +use scale_typegen::{typegen::ir::type_ir::CompositeIRKind, TypeGenerator}; +use subxt_metadata::{AssociatedTypeMetadata, PalletMetadata}; + +/// The name of the system pallet. +const PALLET_SYSTEM: &str = "System"; +/// The name of the system pallet block type. +const PALLET_SYSTEM_BLOCK: &str = "Block"; + +fn handle_block_type( + type_gen: &TypeGenerator, + pallet: &PalletMetadata, + ty: &AssociatedTypeMetadata, + crate_path: &syn::Path, +) -> Option { + // Only handle the system pallet block type. + if pallet.name() != PALLET_SYSTEM || ty.name() != PALLET_SYSTEM_BLOCK { + return None; + } + + // println!("System pallet, block type: {:?}", ty); + + let resolved_ty = type_gen.resolve_type(ty.type_id()).ok()?; + // First generic param is the header of the chain. + let header = resolved_ty.type_params.get(0)?; + + // Second generic param is the unchecked extrinsics. + let extrinsics = resolved_ty.type_params.get(1)?; + let extrinsics_ty = type_gen.resolve_type(extrinsics.ty?.id).ok()?; + // Which contains the Address Type as first generic parameter. + let account_id = extrinsics_ty.type_params.get(0)?; + let resolved_account_id = type_gen.resolve_type_path(account_id.ty?.id).ok()?; + let resolved_account_id = resolved_account_id.to_token_stream(type_gen.settings()); + + let ty_path = type_gen.resolve_type_path(ty.type_id()).ok()?; + let ty = ty_path.to_token_stream(type_gen.settings()); + + Some(quote! { + pub type Address = #resolved_account_id; + // TODO: add the header type here. + // pub type Header = <#crate_path::system::Block as #crate_path::Block>::Header; + }) +} + +/// Generate associated types. +pub fn generate_associated_types( + type_gen: &TypeGenerator, + pallet: &PalletMetadata, + crate_path: &syn::Path, +) -> Result { + let associated_types = pallet.associated_types(); + + let collected = associated_types.iter().map(|ty| { + let name = format_ident!("{}", ty.name()); + let docs = type_gen.docs_from_scale_info(&ty.docs()); + + let Ok(ty_path) = type_gen.resolve_type_path(ty.type_id()) else { + // We don't have the information in the type generator to handle this type. + return quote! {}; + }; + + let maybe_block_ty = handle_block_type(type_gen, pallet, ty, crate_path); + let name_str = ty.name(); + let ty = ty_path.to_token_stream(type_gen.settings()); + + let mut maybe_impl = None; + if name_str == "Hashing" { + // Extract hasher name + let ty_path_str = ty.to_string(); + if ty_path_str.contains("BlakeTwo256") { + maybe_impl = Some(quote! { + impl #crate_path::config::Hasher for #ty { + type Output = #crate_path::utils::H256; + + fn hash(s: &[u8]) -> Self::Output { + let mut bytes = Vec::new(); + #crate_path::storage::utils::hash_bytes(s, #crate_path::storage::utils::StorageHasher::Blake2_256, &mut bytes); + let arr: [u8; 32] = bytes.try_into().expect("Invalid hashing output provided"); + arr.into() + } + } + }); + } + } + + + + quote! { + #docs + pub type #name = #ty; + + // Types extracted from the generic parameters of the system pallet block type. + #maybe_block_ty + + // Implementation for the hasher type. + #maybe_impl + } + }); + + Ok(quote! { + #( #collected )* + }) +} diff --git a/codegen/src/api/mod.rs b/codegen/src/api/mod.rs index 7a8e8eee2f..9553e43916 100644 --- a/codegen/src/api/mod.rs +++ b/codegen/src/api/mod.rs @@ -4,6 +4,7 @@ //! Generate code for submitting extrinsics and query storage of a Substrate runtime. +mod associated_types; mod calls; mod constants; mod custom_values; @@ -171,10 +172,21 @@ impl RuntimeGenerator { let errors = errors::generate_error_type_alias(&type_gen, pallet)?; + let associated_types = + associated_types::generate_associated_types(&type_gen, pallet, &crate_path)?; + Ok(quote! { pub mod #mod_name { use super::root_mod; use super::#types_mod_ident; + + pub mod associated_types { + use super::root_mod; + use super::#types_mod_ident; + + #associated_types + } + #errors #calls #event diff --git a/codegen/src/fetch_metadata.rs b/codegen/src/fetch_metadata.rs index ee7c554013..7b485f43d4 100644 --- a/codegen/src/fetch_metadata.rs +++ b/codegen/src/fetch_metadata.rs @@ -143,6 +143,8 @@ async fn fetch_metadata( Decode::decode(&mut &raw_bytes[..])? }; + // println!(" Metadata version: {supported_versions:?}"); + // Return the version the user wants if it's supported: let version = match version { MetadataVersion::Latest => *supported_versions @@ -172,6 +174,8 @@ async fn fetch_metadata( } }; + // println!(" Metadata version: {version}"); + let bytes = version.encode(); let version: String = format!("0x{}", hex::encode(&bytes)); diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 0ad5316100..bdc8edb93f 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -19,7 +19,7 @@ std = ["scale-info/std", "frame-metadata/std"] [dependencies] scale-info = { workspace = true, default-features = false } -frame-metadata = { workspace = true, default-features = false, features = ["current", "decode"] } +frame-metadata = { workspace = true, default-features = false, features = ["current", "decode", "unstable"] } codec = { package = "parity-scale-codec", workspace = true, default-features = false, features = ["derive"] } sp-crypto-hashing = { workspace = true } hashbrown = { workspace = true } diff --git a/metadata/src/from_into/mod.rs b/metadata/src/from_into/mod.rs index 13bb2f40c2..12d54c87a5 100644 --- a/metadata/src/from_into/mod.rs +++ b/metadata/src/from_into/mod.rs @@ -8,6 +8,7 @@ use alloc::string::String; mod v14; mod v15; +mod v16; /// An error emitted if something goes wrong converting [`frame_metadata`] /// types into [`crate::Metadata`]. @@ -108,6 +109,7 @@ impl TryFrom for crate::Metadata { } frame_metadata::RuntimeMetadata::V14(m) => m.try_into(), frame_metadata::RuntimeMetadata::V15(m) => m.try_into(), + frame_metadata::RuntimeMetadata::V16(m) => m.try_into(), } } } diff --git a/metadata/src/from_into/v15.rs b/metadata/src/from_into/v15.rs index 37e4336543..026d854409 100644 --- a/metadata/src/from_into/v15.rs +++ b/metadata/src/from_into/v15.rs @@ -2,6 +2,9 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +extern crate alloc; +use alloc::vec::Vec; + use super::TryFromError; use crate::utils::variant_index::VariantIndex; @@ -66,6 +69,7 @@ mod from_v15 { error_variant_index, constants: constants.collect(), docs: p.docs, + associated_types: Vec::new(), }, ); } diff --git a/metadata/src/from_into/v16.rs b/metadata/src/from_into/v16.rs new file mode 100644 index 0000000000..6455778385 --- /dev/null +++ b/metadata/src/from_into/v16.rs @@ -0,0 +1,458 @@ +// Copyright 2019-2023 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or GPL-3.0. +// see LICENSE for license details. + +use super::TryFromError; + +use crate::utils::variant_index::VariantIndex; +use crate::{ + utils::ordered_map::OrderedMap, ArcStr, ConstantMetadata, ExtrinsicMetadata, Metadata, + OuterEnumsMetadata, PalletMetadataInner, RuntimeApiMetadataInner, RuntimeApiMethodMetadata, + RuntimeApiMethodParamMetadata, SignedExtensionMetadata, StorageEntryMetadata, + StorageEntryModifier, StorageEntryType, StorageHasher, StorageMetadata, +}; +use alloc::borrow::ToOwned; +use frame_metadata::v16; +use hashbrown::HashMap; +use scale_info::form::PortableForm; + +// Converting from V16 metadata into our Subxt repr. +mod from_v16 { + use frame_metadata::v15; + + use crate::AssociatedTypeMetadata; + + use super::*; + + impl TryFrom for Metadata { + type Error = TryFromError; + fn try_from(m: v16::RuntimeMetadataV16) -> Result { + let mut pallets = OrderedMap::new(); + let mut pallets_by_index = HashMap::new(); + for (pos, p) in m.pallets.into_iter().enumerate() { + let name: ArcStr = p.name.into(); + + let storage = p.storage.map(|s| StorageMetadata { + prefix: s.prefix, + entries: s + .entries + .into_iter() + .map(|s| { + let name: ArcStr = s.name.clone().into(); + (name.clone(), from_storage_entry_metadata(name, s)) + }) + .collect(), + }); + let constants = p.constants.into_iter().map(|c| { + let name: ArcStr = c.name.clone().into(); + (name.clone(), from_constant_metadata(name, c)) + }); + + let call_variant_index = + VariantIndex::build(p.calls.as_ref().map(|c| c.ty.id), &m.types); + let error_variant_index = + VariantIndex::build(p.error.as_ref().map(|e| e.ty.id), &m.types); + let event_variant_index = + VariantIndex::build(p.event.as_ref().map(|e| e.ty.id), &m.types); + + pallets_by_index.insert(p.index, pos); + pallets.push_insert( + name.clone(), + PalletMetadataInner { + name, + index: p.index, + storage, + call_ty: p.calls.map(|c| c.ty.id), + call_variant_index, + event_ty: p.event.map(|e| e.ty.id), + event_variant_index, + error_ty: p.error.map(|e| e.ty.id), + error_variant_index, + constants: constants.collect(), + docs: p.docs, + associated_types: p + .associated_types + .into_iter() + .map(from_associated_type_metadata) + .collect(), + }, + ); + } + + let apis = m.apis.into_iter().map(|api| { + let name: ArcStr = api.name.clone().into(); + (name.clone(), from_runtime_api_metadata(name, api)) + }); + + let dispatch_error_ty = m + .types + .types + .iter() + .find(|ty| ty.ty.path.segments == ["sp_runtime", "DispatchError"]) + .map(|ty| ty.id); + + Ok(Metadata { + types: m.types, + pallets, + pallets_by_index, + extrinsic: from_extrinsic_metadata(m.extrinsic), + runtime_ty: m.ty.id, + dispatch_error_ty, + apis: apis.collect(), + outer_enums: OuterEnumsMetadata { + call_enum_ty: m.outer_enums.call_enum_ty.id, + event_enum_ty: m.outer_enums.event_enum_ty.id, + error_enum_ty: m.outer_enums.error_enum_ty.id, + }, + custom: v15::CustomMetadata { + map: Default::default(), + }, + }) + } + } + + fn from_signed_extension_metadata( + value: v16::SignedExtensionMetadata, + ) -> SignedExtensionMetadata { + SignedExtensionMetadata { + identifier: value.identifier, + extra_ty: value.ty.id, + additional_ty: value.additional_signed.id, + } + } + + fn from_extrinsic_metadata(value: v16::ExtrinsicMetadata) -> ExtrinsicMetadata { + ExtrinsicMetadata { + version: value.version, + signed_extensions: value + .signed_extensions + .into_iter() + .map(from_signed_extension_metadata) + .collect(), + address_ty: value.address_ty.id, + call_ty: value.call_ty.id, + signature_ty: value.signature_ty.id, + extra_ty: value.extra_ty.id, + } + } + + fn from_storage_hasher(value: v16::StorageHasher) -> StorageHasher { + match value { + v16::StorageHasher::Blake2_128 => StorageHasher::Blake2_128, + v16::StorageHasher::Blake2_256 => StorageHasher::Blake2_256, + v16::StorageHasher::Blake2_128Concat => StorageHasher::Blake2_128Concat, + v16::StorageHasher::Twox128 => StorageHasher::Twox128, + v16::StorageHasher::Twox256 => StorageHasher::Twox256, + v16::StorageHasher::Twox64Concat => StorageHasher::Twox64Concat, + v16::StorageHasher::Identity => StorageHasher::Identity, + } + } + + fn from_storage_entry_type(value: v16::StorageEntryType) -> StorageEntryType { + match value { + v16::StorageEntryType::Plain(ty) => StorageEntryType::Plain(ty.id), + v16::StorageEntryType::Map { + hashers, + key, + value, + } => StorageEntryType::Map { + hashers: hashers.into_iter().map(from_storage_hasher).collect(), + key_ty: key.id, + value_ty: value.id, + }, + } + } + + fn from_storage_entry_modifier(value: v16::StorageEntryModifier) -> StorageEntryModifier { + match value { + v16::StorageEntryModifier::Optional => StorageEntryModifier::Optional, + v16::StorageEntryModifier::Default => StorageEntryModifier::Default, + } + } + + fn from_associated_type_metadata( + value: v16::PalletAssociatedTypeMetadata, + ) -> AssociatedTypeMetadata { + AssociatedTypeMetadata { + name: value.name, + ty: value.ty.id, + docs: value.docs, + } + } + + fn from_storage_entry_metadata( + name: ArcStr, + s: v16::StorageEntryMetadata, + ) -> StorageEntryMetadata { + StorageEntryMetadata { + name, + modifier: from_storage_entry_modifier(s.modifier), + entry_type: from_storage_entry_type(s.ty), + default: s.default, + docs: s.docs, + } + } + + fn from_constant_metadata( + name: ArcStr, + s: v16::PalletConstantMetadata, + ) -> ConstantMetadata { + ConstantMetadata { + name, + ty: s.ty.id, + value: s.value, + docs: s.docs, + } + } + + fn from_runtime_api_metadata( + name: ArcStr, + s: v16::RuntimeApiMetadata, + ) -> RuntimeApiMetadataInner { + RuntimeApiMetadataInner { + name, + docs: s.docs, + methods: s + .methods + .into_iter() + .map(|m| { + let name: ArcStr = m.name.clone().into(); + (name.clone(), from_runtime_api_method_metadata(name, m)) + }) + .collect(), + } + } + + fn from_runtime_api_method_metadata( + name: ArcStr, + s: v16::RuntimeApiMethodMetadata, + ) -> RuntimeApiMethodMetadata { + RuntimeApiMethodMetadata { + name, + inputs: s + .inputs + .into_iter() + .map(from_runtime_api_method_param_metadata) + .collect(), + output_ty: s.output.id, + docs: s.docs, + } + } + + fn from_runtime_api_method_param_metadata( + s: v16::RuntimeApiMethodParamMetadata, + ) -> RuntimeApiMethodParamMetadata { + RuntimeApiMethodParamMetadata { + name: s.name, + ty: s.ty.id, + } + } +} + +// Converting from our metadata repr to v16 metadata. +mod into_v16 { + use crate::AssociatedTypeMetadata; + + use super::*; + + impl From for v16::RuntimeMetadataV16 { + fn from(m: Metadata) -> Self { + let pallets = m.pallets.into_values().into_iter().map(|p| { + let storage = p.storage.map(|s| v16::PalletStorageMetadata { + prefix: s.prefix, + entries: s + .entries + .into_values() + .into_iter() + .map(from_storage_entry_metadata) + .collect(), + }); + + v16::PalletMetadata { + name: (*p.name).to_owned(), + calls: p.call_ty.map(|id| v16::PalletCallMetadata { + ty: id.into(), + deprecation_info: v16::DeprecationInfo::NotDeprecated, + }), + event: p.event_ty.map(|id| v16::PalletEventMetadata { + ty: id.into(), + deprecation_info: v16::DeprecationInfo::NotDeprecated, + }), + error: p.error_ty.map(|id| v16::PalletErrorMetadata { + ty: id.into(), + deprecation_info: v16::DeprecationInfo::NotDeprecated, + }), + storage, + constants: p + .constants + .into_values() + .into_iter() + .map(from_constant_metadata) + .collect(), + index: p.index, + docs: p.docs, + associated_types: p + .associated_types + .into_iter() + .map(from_associated_type_metadata) + .collect(), + deprecation_info: v16::DeprecationStatus::NotDeprecated, + } + }); + + v16::RuntimeMetadataV16 { + types: m.types, + pallets: pallets.collect(), + ty: m.runtime_ty.into(), + extrinsic: from_extrinsic_metadata(m.extrinsic), + apis: m + .apis + .into_values() + .into_iter() + .map(from_runtime_api_metadata) + .collect(), + outer_enums: v16::OuterEnums { + call_enum_ty: m.outer_enums.call_enum_ty.into(), + event_enum_ty: m.outer_enums.event_enum_ty.into(), + error_enum_ty: m.outer_enums.error_enum_ty.into(), + }, + custom: v16::CustomMetadata { + map: Default::default(), + }, + } + } + } + + fn from_associated_type_metadata( + a: AssociatedTypeMetadata, + ) -> v16::PalletAssociatedTypeMetadata { + v16::PalletAssociatedTypeMetadata { + name: a.name, + ty: a.ty.into(), + docs: a.docs, + } + } + + fn from_runtime_api_metadata( + r: RuntimeApiMetadataInner, + ) -> v16::RuntimeApiMetadata { + v16::RuntimeApiMetadata { + name: (*r.name).to_owned(), + methods: r + .methods + .into_values() + .into_iter() + .map(from_runtime_api_method_metadata) + .collect(), + docs: r.docs, + deprecation_info: v16::DeprecationStatus::NotDeprecated, + } + } + + fn from_runtime_api_method_metadata( + m: RuntimeApiMethodMetadata, + ) -> v16::RuntimeApiMethodMetadata { + v16::RuntimeApiMethodMetadata { + name: (*m.name).to_owned(), + inputs: m + .inputs + .into_iter() + .map(from_runtime_api_method_param_metadata) + .collect(), + output: m.output_ty.into(), + docs: m.docs, + deprecation_info: v16::DeprecationStatus::NotDeprecated, + } + } + + fn from_runtime_api_method_param_metadata( + p: RuntimeApiMethodParamMetadata, + ) -> v16::RuntimeApiMethodParamMetadata { + v16::RuntimeApiMethodParamMetadata { + name: p.name, + ty: p.ty.into(), + } + } + + fn from_extrinsic_metadata(e: ExtrinsicMetadata) -> v16::ExtrinsicMetadata { + v16::ExtrinsicMetadata { + version: e.version, + signed_extensions: e + .signed_extensions + .into_iter() + .map(from_signed_extension_metadata) + .collect(), + address_ty: e.address_ty.into(), + call_ty: e.call_ty.into(), + signature_ty: e.signature_ty.into(), + extra_ty: e.extra_ty.into(), + } + } + + fn from_signed_extension_metadata( + s: SignedExtensionMetadata, + ) -> v16::SignedExtensionMetadata { + v16::SignedExtensionMetadata { + identifier: s.identifier, + ty: s.extra_ty.into(), + additional_signed: s.additional_ty.into(), + } + } + + fn from_constant_metadata(c: ConstantMetadata) -> v16::PalletConstantMetadata { + v16::PalletConstantMetadata { + name: (*c.name).to_owned(), + ty: c.ty.into(), + value: c.value, + docs: c.docs, + deprecation_info: v16::DeprecationStatus::NotDeprecated, + } + } + + fn from_storage_entry_metadata( + s: StorageEntryMetadata, + ) -> v16::StorageEntryMetadata { + v16::StorageEntryMetadata { + docs: s.docs, + default: s.default, + name: (*s.name).to_owned(), + ty: from_storage_entry_type(s.entry_type), + modifier: from_storage_entry_modifier(s.modifier), + deprecation_info: v16::DeprecationStatus::NotDeprecated, + } + } + + fn from_storage_entry_modifier(s: StorageEntryModifier) -> v16::StorageEntryModifier { + match s { + StorageEntryModifier::Default => v16::StorageEntryModifier::Default, + StorageEntryModifier::Optional => v16::StorageEntryModifier::Optional, + } + } + + fn from_storage_entry_type(s: StorageEntryType) -> v16::StorageEntryType { + match s { + StorageEntryType::Plain(ty) => v16::StorageEntryType::Plain(ty.into()), + StorageEntryType::Map { + hashers, + key_ty, + value_ty, + } => v16::StorageEntryType::Map { + hashers: hashers.into_iter().map(from_storage_hasher).collect(), + key: key_ty.into(), + value: value_ty.into(), + }, + } + } + + fn from_storage_hasher(s: StorageHasher) -> v16::StorageHasher { + match s { + StorageHasher::Blake2_128 => v16::StorageHasher::Blake2_128, + StorageHasher::Blake2_256 => v16::StorageHasher::Blake2_256, + StorageHasher::Blake2_128Concat => v16::StorageHasher::Blake2_128Concat, + StorageHasher::Twox128 => v16::StorageHasher::Twox128, + StorageHasher::Twox256 => v16::StorageHasher::Twox256, + StorageHasher::Twox64Concat => v16::StorageHasher::Twox64Concat, + StorageHasher::Identity => v16::StorageHasher::Identity, + } + } +} diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index fb86ddcbef..b273ee6535 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -230,6 +230,11 @@ impl<'a> PalletMetadata<'a> { ) } + /// Return all of the associated types. + pub fn associated_types(&self) -> &'a [AssociatedTypeMetadata] { + &self.inner.associated_types + } + /// Return all of the call variants, if a call type exists. pub fn call_variants(&self) -> Option<&'a [Variant]> { VariantIndex::get(self.inner.call_ty, self.types) @@ -318,6 +323,36 @@ struct PalletMetadataInner { constants: OrderedMap, /// Pallet documentation. docs: Vec, + /// Pallet associated types. + associated_types: Vec, +} + +/// Metadata for an associated type. +#[derive(Debug, Clone)] +pub struct AssociatedTypeMetadata { + /// Name of the associated type. + name: String, + /// Type of the associated type. + ty: u32, + /// Associated type documentation. + docs: Vec, +} + +impl AssociatedTypeMetadata { + /// Name of the associated type. + pub fn name(&self) -> &str { + &self.name + } + + /// Type id of the associated type. + pub fn type_id(&self) -> u32 { + self.ty + } + + /// Associated type documentation. + pub fn docs(&self) -> &[String] { + &self.docs + } } /// Metadata for the storage entries in a pallet. @@ -773,6 +808,7 @@ impl codec::Decode for Metadata { let metadata = match metadata.1 { frame_metadata::RuntimeMetadata::V14(md) => md.try_into(), frame_metadata::RuntimeMetadata::V15(md) => md.try_into(), + frame_metadata::RuntimeMetadata::V16(md) => md.try_into(), _ => return Err("Cannot try_into() to Metadata: unsupported metadata version".into()), }; diff --git a/subxt/examples/metadata_config.rs b/subxt/examples/metadata_config.rs index ca3b3850b2..37ff32b202 100644 --- a/subxt/examples/metadata_config.rs +++ b/subxt/examples/metadata_config.rs @@ -5,7 +5,10 @@ use subxt_core::config::{Config, DefaultExtrinsicParams}; use subxt_signer::sr25519::dev; // Generate an interface that we can use from the node's metadata. -#[subxt::subxt(runtime_metadata_insecure_url = "ws://localhost:9999")] +#[subxt::subxt( + runtime_metadata_insecure_url = "ws://localhost:9944", + unstable_metadata +)] pub mod polkadot {} // Derives aren't strictly needed, they just make developer life easier. @@ -14,10 +17,10 @@ pub enum MetadataConfig {} impl Config for MetadataConfig { // Extracted from metadata directly: - type Hash = polkadot::custom_types::Hash; - type AccountId = polkadot::custom_types::AccountId; - type AssetId = polkadot::custom_types::AssetId; - type Address = polkadot::custom_types::Address; + type Hash = polkadot::system::associated_types::Hash; + type AccountId = polkadot::system::associated_types::AccountId; + type AssetId = polkadot::assets::associated_types::AssetId; + type Address = polkadot::system::associated_types::Address; // Present in metadata but this PoC needs to add // fn specific per name of type to impl the hashing fn. @@ -25,7 +28,7 @@ impl Config for MetadataConfig { // // TODO: Eventually extend this to a DynamicHasher object instead. // Similar logic already exists for StorageHasher. - type Hasher = polkadot::custom_types::Hashing; + type Hasher = polkadot::system::associated_types::Hashing; // Present in metadata but this PoC needs to impl the header // trait to make use of this. @@ -37,13 +40,11 @@ impl Config for MetadataConfig { // generated hasher to expose the same information, this is not // as robust and codgen can be used instead. // type Header = polkadot::custom_types::Header; - type Header = - SubstrateHeader; + type Header = SubstrateHeader; // Same story, present in md but needs subxt::tx::Signer. // type Signature = polkadot::custom_types::Signature; type Signature = ::Signature; - // Not exposed in metadata, seems like heavily involved with // code functionality which cannot safely be expressed in the // metadata. @@ -53,7 +54,7 @@ impl Config for MetadataConfig { #[tokio::main] async fn main() -> Result<(), Box> { // Create a new API client, configured to talk to nodes. - let api = OnlineClient::::from_insecure_url("ws://localhost:9999").await?; + let api = OnlineClient::::from_insecure_url("ws://localhost:9944").await?; // Build a balance transfer extrinsic. let dest = dev::bob().public_key().into();