diff --git a/Cargo.lock b/Cargo.lock index d0b067155..bd60ddcc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ "bitvec", "derive_more", "either", - "frame-metadata 15.1.0", + "frame-metadata", "hex", "log", "parity-scale-codec", @@ -1678,18 +1678,6 @@ dependencies = [ "sp-tracing", ] -[[package]] -name = "frame-metadata" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" -dependencies = [ - "cfg-if 1.0.0", - "parity-scale-codec", - "scale-info", - "serde", -] - [[package]] name = "frame-metadata" version = "16.0.0" @@ -1711,7 +1699,7 @@ dependencies = [ "bitflags 1.3.2", "docify", "environmental", - "frame-metadata 16.0.0", + "frame-metadata", "frame-support-procedural", "impl-trait-for-tuples", "k256", @@ -5879,7 +5867,7 @@ name = "sp-metadata-ir" version = "0.1.0" source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=master#6079b6dd3aaba56ef257111fda74a57a800f16d0" dependencies = [ - "frame-metadata 16.0.0", + "frame-metadata", "parity-scale-codec", "scale-info", "sp-std", @@ -6295,7 +6283,7 @@ dependencies = [ "ac-primitives", "async-trait", "derive_more", - "frame-metadata 15.1.0", + "frame-metadata", "frame-support", "futures", "hex", diff --git a/Cargo.toml b/Cargo.toml index 3492077aa..133b475f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ members = [ async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ['derive'] } derive_more = { version = "0.99.5" } -frame-metadata = { version = "15.1", default-features = false, features = ["v14", "v15-unstable", "serde_full", "decode"] } +frame-metadata = { version = "16.0", default-features = false, features = ["current", "serde_full", "decode"] } hex = { version = "0.4.3", default-features = false, features = ["alloc"] } log = { version = "0.4.14", default-features = false } maybe-async = { version = "0.2.7" } diff --git a/ksm_metadata_v14.bin b/ksm_metadata_v14.bin index 7c214eeed..406bec8a7 100644 Binary files a/ksm_metadata_v14.bin and b/ksm_metadata_v14.bin differ diff --git a/node-api/Cargo.toml b/node-api/Cargo.toml index 0bbf99f64..09eb4b7cc 100644 --- a/node-api/Cargo.toml +++ b/node-api/Cargo.toml @@ -14,7 +14,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive", "bit-vec"], default-features = false } derive_more = { version = "0.99.17" } either = { version = "1.6.1", default-features = false } -frame-metadata = { version = "15.1", default-features = false, features = ["v14", "v15-unstable", "serde_full", "decode"] } +frame-metadata = { version = "16.0", default-features = false, features = ["current", "serde_full", "decode"] } hex = { version = "0.4.3", default-features = false } log = { version = "0.4.14", default-features = false } scale-bits = { version = "0.4.0", default-features = false, features = ["scale-info", "serde"] } diff --git a/node-api/src/error/mod.rs b/node-api/src/error/mod.rs index 52b9ad75a..2ab997eaf 100644 --- a/node-api/src/error/mod.rs +++ b/node-api/src/error/mod.rs @@ -13,7 +13,7 @@ use core::fmt::Debug; use derive_more::From; // Re-expose the errors we use from other crates here: -pub use crate::metadata::{InvalidMetadataError, MetadataError}; +pub use crate::metadata::{MetadataConversionError, MetadataError}; pub use scale_decode::Error as DecodeError; pub use scale_encode::Error as EncodeError; pub use sp_core::crypto::SecretStringError; @@ -34,7 +34,7 @@ pub enum Error { /// Secret string error. SecretString(SecretStringError), /// Invalid metadata error - InvalidMetadata(InvalidMetadataError), + InvalidMetadata(MetadataConversionError), /// Invalid metadata error Metadata(MetadataError), /// Runtime error. diff --git a/node-api/src/metadata/error.rs b/node-api/src/metadata/error.rs index 817343710..0169592d3 100644 --- a/node-api/src/metadata/error.rs +++ b/node-api/src/metadata/error.rs @@ -39,18 +39,22 @@ pub enum MetadataError { ConstantNotFound(&'static str), /// Variant not found. VariantIndexNotFound(u8), - /// Type is not in metadata. - TypeNotFound(u32), /// Api is not in metadata. RuntimeApiNotFound(String), } #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Encode, Decode)] -pub enum InvalidMetadataError { +pub enum MetadataConversionError { InvalidPrefix, InvalidVersion, /// Type is missing from type registry. MissingType(u32), /// Type was not variant/enum type. TypeDefNotVariant(u32), + /// Type is not in metadata. + TypeNotFound(u32), + /// Type Name is not in metadata. + TypeNameNotFound(String), + // Path not found. + InvalidTypePath(String), } diff --git a/node-api/src/metadata/from_v14_to_v15.rs b/node-api/src/metadata/from_v14_to_v15.rs index 65d76982f..9cad7ee24 100644 --- a/node-api/src/metadata/from_v14_to_v15.rs +++ b/node-api/src/metadata/from_v14_to_v15.rs @@ -6,10 +6,26 @@ // This file is licensed as Apache-2.0 // see LICENSE for license details. +use super::error::MetadataConversionError; +use alloc::{ + collections::BTreeMap, + format, + string::{String, ToString}, + vec, + vec::Vec, +}; use frame_metadata::{v14, v15}; +use scale_info::TypeDef; -pub fn v14_to_v15(metadata: v14::RuntimeMetadataV14) -> v15::RuntimeMetadataV15 { - v15::RuntimeMetadataV15 { +pub fn v14_to_v15( + mut metadata: v14::RuntimeMetadataV14, +) -> Result { + // Find the extrinsic types. + let extrinsic_parts = ExtrinsicPartTypeIds::new(&metadata)?; + + let outer_enums = generate_outer_enums(&mut metadata)?; + + Ok(v15::RuntimeMetadataV15 { types: metadata.types, pallets: metadata .pallets @@ -80,7 +96,6 @@ pub fn v14_to_v15(metadata: v14::RuntimeMetadataV14) -> v15::RuntimeMetadataV15 }) .collect(), extrinsic: frame_metadata::v15::ExtrinsicMetadata { - ty: metadata.extrinsic.ty, version: metadata.extrinsic.version, signed_extensions: metadata.extrinsic.signed_extensions.into_iter().map(|ext| { frame_metadata::v15::SignedExtensionMetadata { @@ -88,9 +103,350 @@ pub fn v14_to_v15(metadata: v14::RuntimeMetadataV14) -> v15::RuntimeMetadataV15 ty: ext.ty, additional_signed: ext.additional_signed, } - }).collect() + }).collect(), + address_ty: extrinsic_parts.address.into(), + call_ty: extrinsic_parts.call.into(), + signature_ty: extrinsic_parts.signature.into(), + extra_ty: extrinsic_parts.extra.into(), }, ty: metadata.ty, apis: Default::default(), - } + outer_enums, + custom: v15::CustomMetadata { + map: Default::default(), + }, + }) +} + +/// The type IDs extracted from the metadata that represent the +/// generic type parameters passed to the `UncheckedExtrinsic` from +/// the substrate-based chain. +struct ExtrinsicPartTypeIds { + address: u32, + call: u32, + signature: u32, + extra: u32, +} + +impl ExtrinsicPartTypeIds { + /// Extract the generic type parameters IDs from the extrinsic type. + fn new(metadata: &v14::RuntimeMetadataV14) -> Result { + const ADDRESS: &str = "Address"; + const CALL: &str = "Call"; + const SIGNATURE: &str = "Signature"; + const EXTRA: &str = "Extra"; + + let extrinsic_id = metadata.extrinsic.ty.id; + let Some(extrinsic_ty) = metadata.types.resolve(extrinsic_id) else { + return Err(MetadataConversionError::TypeNotFound(extrinsic_id)) + }; + + let params: BTreeMap<_, _> = extrinsic_ty + .type_params + .iter() + .map(|ty_param| { + let Some(ty) = ty_param.ty else { + return Err(MetadataConversionError::TypeNameNotFound(ty_param.name.clone())) + }; + + Ok((ty_param.name.as_str(), ty.id)) + }) + .collect::>()?; + + let Some(address) = params.get(ADDRESS) else { + return Err(MetadataConversionError::TypeNameNotFound(ADDRESS.into())) + }; + let Some(call) = params.get(CALL) else { + return Err(MetadataConversionError::TypeNameNotFound(CALL.into())) + }; + let Some(signature) = params.get(SIGNATURE) else { + return Err(MetadataConversionError::TypeNameNotFound(SIGNATURE.into())) + }; + let Some(extra) = params.get(EXTRA) else { + return Err(MetadataConversionError::TypeNameNotFound(EXTRA.into())) + }; + + Ok(ExtrinsicPartTypeIds { + address: *address, + call: *call, + signature: *signature, + extra: *extra, + }) + } +} + +fn generate_outer_enums( + metadata: &mut v14::RuntimeMetadataV14, +) -> Result, MetadataConversionError> { + let find_type = |name: &str| { + metadata.types.types.iter().find_map(|ty| { + let ident = ty.ty.path.ident()?; + + if ident != name { + return None + } + + let TypeDef::Variant(_) = &ty.ty.type_def else { return None }; + + Some((ty.id, ty.ty.path.segments.clone())) + }) + }; + + let Some((call_enum, mut call_path)) = find_type("RuntimeCall") else { + return Err(MetadataConversionError::TypeNameNotFound("RuntimeCall".into())) + }; + + let Some((event_enum, _)) = find_type("RuntimeEvent") else { + return Err(MetadataConversionError::TypeNameNotFound("RuntimeEvent".into())) + }; + + let error_enum = if let Some((error_enum, _)) = find_type("RuntimeError") { + error_enum + } else { + let Some(last) = call_path.last_mut() else { + return Err(MetadataConversionError::InvalidTypePath("RuntimeCall".into())) + }; + *last = "RuntimeError".to_string(); + generate_outer_error_enum_type(metadata, call_path) + }; + + Ok(v15::OuterEnums { + call_enum_ty: call_enum.into(), + event_enum_ty: event_enum.into(), + error_enum_ty: error_enum.into(), + }) +} + +/// Generates an outer `RuntimeError` enum type and adds it to the metadata. +/// +/// Returns the id of the generated type from the registry. +fn generate_outer_error_enum_type( + metadata: &mut v14::RuntimeMetadataV14, + path_segments: Vec, +) -> u32 { + let variants: Vec<_> = metadata + .pallets + .iter() + .filter_map(|pallet| { + let error = &pallet.error.clone()?; + + let path = format!("{}Error", pallet.name); + let ty = error.ty.id.into(); + + Some(scale_info::Variant { + name: pallet.name.clone(), + fields: vec![scale_info::Field { + name: None, + ty, + type_name: Some(path), + docs: vec![], + }], + index: pallet.index, + docs: vec![], + }) + }) + .collect(); + + let enum_type = scale_info::Type { + path: scale_info::Path { segments: path_segments }, + type_params: vec![], + type_def: scale_info::TypeDef::Variant(scale_info::TypeDefVariant { variants }), + docs: vec![], + }; + + let enum_type_id = metadata.types.types.len() as u32; + + metadata + .types + .types + .push(scale_info::PortableType { id: enum_type_id, ty: enum_type }); + + enum_type_id +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::Decode; + use frame_metadata::{ + v14::{ExtrinsicMetadata, RuntimeMetadataV14}, + RuntimeMetadata, RuntimeMetadataPrefixed, + }; + use scale_info::{meta_type, IntoPortable, TypeInfo}; + use sp_core::Bytes; + use std::{fs, marker::PhantomData}; + + fn load_v14_metadata() -> RuntimeMetadataV14 { + let encoded_metadata: Bytes = fs::read("./../ksm_metadata_v14.bin").unwrap().into(); + let runtime_metadata_prefixed: RuntimeMetadataPrefixed = + Decode::decode(&mut encoded_metadata.0.as_slice()).unwrap(); + + match runtime_metadata_prefixed.1 { + RuntimeMetadata::V14(ref metadata) => metadata.clone(), + _ => unimplemented!(), + } + } + + #[test] + fn test_extrinsic_id_generation() { + let v14 = load_v14_metadata(); + + let v15 = v14_to_v15(v14.clone()).unwrap(); + + let ext_ty = v14.types.resolve(v14.extrinsic.ty.id).unwrap(); + let addr_id = ext_ty + .type_params + .iter() + .find_map(|ty| if ty.name == "Address" { Some(ty.ty.unwrap().id) } else { None }) + .unwrap(); + let call_id = ext_ty + .type_params + .iter() + .find_map(|ty| if ty.name == "Call" { Some(ty.ty.unwrap().id) } else { None }) + .unwrap(); + let extra_id = ext_ty + .type_params + .iter() + .find_map(|ty| if ty.name == "Extra" { Some(ty.ty.unwrap().id) } else { None }) + .unwrap(); + let signature_id = ext_ty + .type_params + .iter() + .find_map(|ty| if ty.name == "Signature" { Some(ty.ty.unwrap().id) } else { None }) + .unwrap(); + + // Position in type registry shouldn't change. + assert_eq!(v15.extrinsic.address_ty.id, addr_id); + assert_eq!(v15.extrinsic.call_ty.id, call_id); + assert_eq!(v15.extrinsic.extra_ty.id, extra_id); + assert_eq!(v15.extrinsic.signature_ty.id, signature_id); + + let v15_addr = v15.types.resolve(v15.extrinsic.address_ty.id).unwrap(); + let v14_addr = v14.types.resolve(addr_id).unwrap(); + assert_eq!(v15_addr, v14_addr); + + let v15_call = v15.types.resolve(v15.extrinsic.call_ty.id).unwrap(); + let v14_call = v14.types.resolve(call_id).unwrap(); + assert_eq!(v15_call, v14_call); + + let v15_extra = v15.types.resolve(v15.extrinsic.extra_ty.id).unwrap(); + let v14_extra = v14.types.resolve(extra_id).unwrap(); + assert_eq!(v15_extra, v14_extra); + + let v15_sign = v15.types.resolve(v15.extrinsic.signature_ty.id).unwrap(); + let v14_sign = v14.types.resolve(signature_id).unwrap(); + assert_eq!(v15_sign, v14_sign); + } + + #[test] + fn test_missing_extrinsic_types() { + #[derive(TypeInfo)] + struct Runtime; + + let generate_metadata = |extrinsic_ty| { + let mut registry = scale_info::Registry::new(); + + let ty = registry.register_type(&meta_type::()); + + let extrinsic = + ExtrinsicMetadata { ty: extrinsic_ty, version: 0, signed_extensions: vec![] } + .into_portable(&mut registry); + + v14::RuntimeMetadataV14 { types: registry.into(), pallets: Vec::new(), extrinsic, ty } + }; + + let metadata = generate_metadata(meta_type::<()>()); + let err = v14_to_v15(metadata).unwrap_err(); + assert_eq!(err, MetadataConversionError::TypeNameNotFound("Address".into())); + + #[derive(TypeInfo)] + struct ExtrinsicNoCall { + _phantom: PhantomData<(Address, Signature, Extra)>, + } + let metadata = generate_metadata(meta_type::>()); + let err = v14_to_v15(metadata).unwrap_err(); + assert_eq!(err, MetadataConversionError::TypeNameNotFound("Call".into())); + + #[derive(TypeInfo)] + struct ExtrinsicNoSign { + _phantom: PhantomData<(Call, Address, Extra)>, + } + let metadata = generate_metadata(meta_type::>()); + let err = v14_to_v15(metadata).unwrap_err(); + assert_eq!(err, MetadataConversionError::TypeNameNotFound("Signature".into())); + + #[derive(TypeInfo)] + struct ExtrinsicNoExtra { + _phantom: PhantomData<(Call, Address, Signature)>, + } + let metadata = generate_metadata(meta_type::>()); + let err = v14_to_v15(metadata).unwrap_err(); + assert_eq!(err, MetadataConversionError::TypeNameNotFound("Extra".into())); + } + + #[test] + fn test_missing_outer_enum_types() { + #[derive(TypeInfo)] + struct Runtime; + + #[derive(TypeInfo)] + enum RuntimeCall {} + #[derive(TypeInfo)] + enum RuntimeEvent {} + + #[allow(unused)] + #[derive(TypeInfo)] + struct ExtrinsicType { + pub signature: Option<(Address, Signature, Extra)>, + pub function: Call, + } + + // Missing runtime call. + { + let mut registry = scale_info::Registry::new(); + let ty = registry.register_type(&meta_type::()); + registry.register_type(&meta_type::()); + + let extrinsic = ExtrinsicMetadata { + ty: meta_type::>(), + version: 0, + signed_extensions: vec![], + } + .into_portable(&mut registry); + + let metadata = v14::RuntimeMetadataV14 { + types: registry.into(), + pallets: Vec::new(), + extrinsic, + ty, + }; + + let err = v14_to_v15(metadata).unwrap_err(); + assert_eq!(err, MetadataConversionError::TypeNameNotFound("RuntimeCall".into())); + } + + // Missing runtime event. + { + let mut registry = scale_info::Registry::new(); + let ty = registry.register_type(&meta_type::()); + registry.register_type(&meta_type::()); + + let extrinsic = ExtrinsicMetadata { + ty: meta_type::>(), + version: 0, + signed_extensions: vec![], + } + .into_portable(&mut registry); + + let metadata = v14::RuntimeMetadataV14 { + types: registry.into(), + pallets: Vec::new(), + extrinsic, + ty, + }; + + let err = v14_to_v15(metadata).unwrap_err(); + assert_eq!(err, MetadataConversionError::TypeNameNotFound("RuntimeEvent".into())); + } + } } diff --git a/node-api/src/metadata/metadata_types.rs b/node-api/src/metadata/metadata_types.rs index 0d4cf4ceb..e1457a636 100644 --- a/node-api/src/metadata/metadata_types.rs +++ b/node-api/src/metadata/metadata_types.rs @@ -9,7 +9,7 @@ //! Handle substrate chain metadata. use crate::{ - metadata::{v14_to_v15, variant_index::VariantIndex, InvalidMetadataError, MetadataError}, + metadata::{v14_to_v15, variant_index::VariantIndex, MetadataConversionError, MetadataError}, storage::GetStorageTypes, }; use alloc::{ @@ -329,17 +329,17 @@ struct RuntimeApiMetadataInner { // Based on https://github.com/paritytech/subxt/blob/8413c4d2dd625335b9200dc2289670accdf3391a/metadata/src/from_into/v15.rs impl TryFrom for Metadata { - type Error = InvalidMetadataError; + type Error = MetadataConversionError; fn try_from(m: RuntimeMetadataPrefixed) -> Result { if m.0 != META_RESERVED { - return Err(InvalidMetadataError::InvalidPrefix) + return Err(MetadataConversionError::InvalidPrefix) } let m = match m.1 { - RuntimeMetadata::V14(meta) => v14_to_v15(meta), + RuntimeMetadata::V14(meta) => v14_to_v15(meta)?, RuntimeMetadata::V15(meta) => meta, - _ => return Err(InvalidMetadataError::InvalidVersion), + _ => return Err(MetadataConversionError::InvalidVersion), }; let mut pallets = BTreeMap::new(); diff --git a/node-api/src/metadata/variant_index.rs b/node-api/src/metadata/variant_index.rs index 0c2d809a1..fc861ea5d 100644 --- a/node-api/src/metadata/variant_index.rs +++ b/node-api/src/metadata/variant_index.rs @@ -23,9 +23,7 @@ pub struct VariantIndex { impl VariantIndex { /// Build indexes from the optional variant ID. pub fn build(variant_id: Option, types: &PortableRegistry) -> Self { - let Some(variants) = Self::get(variant_id, types) else { - return Self::empty() - }; + let Some(variants) = Self::get(variant_id, types) else { return Self::empty() }; let mut by_name = BTreeMap::new(); let mut by_index = BTreeMap::new(); @@ -47,12 +45,8 @@ impl VariantIndex { variant_id: Option, types: &PortableRegistry, ) -> Option<&[Variant]> { - let Some(variant_id) = variant_id else { - return None - }; - let TypeDef::Variant(v) = &types.resolve(variant_id)?.type_def else { - return None - }; + let variant_id = variant_id?; + let TypeDef::Variant(v) = &types.resolve(variant_id)?.type_def else { return None }; Some(&v.variants) } diff --git a/node-api/src/scale_value/encode.rs b/node-api/src/scale_value/encode.rs index 456f86187..2439dffa1 100644 --- a/node-api/src/scale_value/encode.rs +++ b/node-api/src/scale_value/encode.rs @@ -205,9 +205,7 @@ fn encode_composite( // skip into the target type past any newtype wrapper like things: fn find_single_entry_with_same_repr(type_id: u32, types: &PortableRegistry) -> u32 { - let Some(ty) = types.resolve(type_id) else { - return type_id - }; + let Some(ty) = types.resolve(type_id) else { return type_id }; match &ty.type_def { TypeDef::Tuple(tuple) if tuple.fields.len() == 1 => find_single_entry_with_same_repr(tuple.fields[0].id, types), diff --git a/node-api/src/test_utils.rs b/node-api/src/test_utils.rs index c93d70ea1..40173373a 100644 --- a/node-api/src/test_utils.rs +++ b/node-api/src/test_utils.rs @@ -16,8 +16,9 @@ use frame_metadata::{ PalletMetadata as PalletMetadataV14, RuntimeMetadataV14, }, v15::{ - ExtrinsicMetadata as ExtrinsicMetadataV15, PalletEventMetadata as PalletEventMetadataV15, - PalletMetadata as PalletMetadataV15, RuntimeMetadataV15, + CustomMetadata, ExtrinsicMetadata as ExtrinsicMetadataV15, OuterEnums, + PalletEventMetadata as PalletEventMetadataV15, PalletMetadata as PalletMetadataV15, + RuntimeMetadataV15, }, RuntimeMetadataPrefixed, }; @@ -62,25 +63,7 @@ pub fn metadata_with_version( version: SupportedMetadataVersions, ) -> Metadata { let runtime_metadata: RuntimeMetadataPrefixed = match version { - SupportedMetadataVersions::V14 => { - let pallets = vec![PalletMetadataV14 { - name: "Test", - storage: None, - calls: None, - event: Some(PalletEventMetadataV14 { ty: meta_type::() }), - constants: vec![], - error: None, - index: 0, - }]; - - let extrinsic = ExtrinsicMetadataV14 { - ty: meta_type::<()>(), - version: 0, - signed_extensions: vec![], - }; - let v14 = RuntimeMetadataV14::new(pallets, extrinsic, meta_type::<()>()); - v14.into() - }, + SupportedMetadataVersions::V14 => create_dummy_runtime_v14::().into(), SupportedMetadataVersions::V15 => { let pallets = vec![PalletMetadataV15 { name: "Test", @@ -94,11 +77,27 @@ pub fn metadata_with_version( }]; let extrinsic = ExtrinsicMetadataV15 { - ty: meta_type::<()>(), version: 0, + address_ty: meta_type::<()>(), + call_ty: meta_type::<()>(), + signature_ty: meta_type::<()>(), + extra_ty: meta_type::<()>(), signed_extensions: vec![], }; - let v15 = RuntimeMetadataV15::new(pallets, extrinsic, meta_type::<()>(), vec![]); + let outer_enums = OuterEnums { + call_enum_ty: meta_type::<()>(), + event_enum_ty: meta_type::<()>(), + error_enum_ty: meta_type::<()>(), + }; + let custom = CustomMetadata { map: Default::default() }; + let v15 = RuntimeMetadataV15::new( + pallets, + extrinsic, + meta_type::<()>(), + vec![], + outer_enums, + custom, + ); v15.into() }, }; @@ -128,3 +127,89 @@ pub fn events_raw(metadata: Metadata, event_bytes: Vec, num_events: u32) -> all_event_bytes.extend(event_bytes); Events::new(metadata, H256::default(), all_event_bytes) } + +fn create_dummy_runtime_v14() -> RuntimeMetadataV14 { + let pallets = vec![PalletMetadataV14 { + name: "Test", + storage: None, + calls: None, + event: Some(PalletEventMetadataV14 { ty: meta_type::() }), + constants: vec![], + error: None, + index: 0, + }]; + + let extrinsic = + ExtrinsicMetadataV14 { ty: meta_type::<()>(), version: 0, signed_extensions: vec![] }; + + let mut v14 = RuntimeMetadataV14::new(pallets, extrinsic, meta_type::<()>()); + + // Register types that are needed for v14 -> v15 conversion. + let extrinsic_type = scale_info::Type { + path: scale_info::Path { + segments: vec![ + "primitives".to_string(), + "runtime".to_string(), + "generic".to_string(), + "UncheckedExtrinsic".to_string(), + ], + }, + type_params: vec![ + scale_info::TypeParameter:: { + name: "Address".to_string(), + ty: Some(0.into()), + }, + scale_info::TypeParameter:: { + name: "Call".to_string(), + ty: Some(0.into()), + }, + scale_info::TypeParameter:: { + name: "Signature".to_string(), + ty: Some(0.into()), + }, + scale_info::TypeParameter:: { + name: "Extra".to_string(), + ty: Some(0.into()), + }, + ], + type_def: scale_info::TypeDef::Composite(scale_info::TypeDefComposite { fields: vec![] }), + docs: vec![], + }; + let new_type_id = v14.types.types.len() as u32; + v14.types + .types + .push(scale_info::PortableType { id: new_type_id, ty: extrinsic_type }); + v14.extrinsic.ty = new_type_id.into(); + + let runtime_call_type = scale_info::Type { + path: scale_info::Path { segments: vec!["RuntimeError".to_string()] }, + type_params: vec![], + type_def: scale_info::TypeDef::Variant(scale_info::TypeDefVariant { variants: vec![] }), + docs: vec![], + }; + v14.types + .types + .push(scale_info::PortableType { id: v14.types.types.len() as u32, ty: runtime_call_type }); + + let runtime_call_type = scale_info::Type { + path: scale_info::Path { segments: vec!["RuntimeCall".to_string()] }, + type_params: vec![], + type_def: scale_info::TypeDef::Variant(scale_info::TypeDefVariant { variants: vec![] }), + docs: vec![], + }; + v14.types + .types + .push(scale_info::PortableType { id: v14.types.types.len() as u32, ty: runtime_call_type }); + + let runtime_call_type = scale_info::Type { + path: scale_info::Path { segments: vec!["RuntimeEvent".to_string()] }, + type_params: vec![], + type_def: scale_info::TypeDef::Variant(scale_info::TypeDefVariant { variants: vec![] }), + docs: vec![], + }; + v14.types + .types + .push(scale_info::PortableType { id: v14.types.types.len() as u32, ty: runtime_call_type }); + + v14 +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index be5341847..b1a0b0058 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2023-05-22" +channel = "nightly-2023-08-22" targets = ["wasm32-unknown-unknown"] profile = "default" # include rustfmt, clippy diff --git a/src/api/api_client.rs b/src/api/api_client.rs index ece2510dd..ec90d6008 100644 --- a/src/api/api_client.rs +++ b/src/api/api_client.rs @@ -310,7 +310,7 @@ mod tests { AssetRuntimeConfig, DefaultRuntimeConfig, GenericAdditionalParams, GenericExtrinsicParams, PlainTip, }; - use frame_metadata::{ExtrinsicMetadata, RuntimeMetadata}; + use frame_metadata::{v14::ExtrinsicMetadata, RuntimeMetadata}; use scale_info::form::PortableForm; use sp_core::H256; use std::{collections::HashMap, fs}; diff --git a/src/api/error.rs b/src/api/error.rs index 7a9ed250a..589374042 100644 --- a/src/api/error.rs +++ b/src/api/error.rs @@ -18,7 +18,7 @@ use crate::{api::UnexpectedTxStatus, rpc::Error as RpcClientError}; use ac_node_api::{ error::DispatchError, - metadata::{InvalidMetadataError, MetadataError}, + metadata::{MetadataConversionError, MetadataError}, }; use alloc::boxed::Box; @@ -35,7 +35,7 @@ pub enum Error { /// Metadata Error. Metadata(MetadataError), /// Invalid Metadata Error. - InvalidMetadata(InvalidMetadataError), + InvalidMetadata(MetadataConversionError), /// Node Api Error. NodeApi(ac_node_api::error::Error), /// Encode / Decode Error. diff --git a/src/rpc/tungstenite_client/client.rs b/src/rpc/tungstenite_client/client.rs index efb4ea68c..983d31743 100644 --- a/src/rpc/tungstenite_client/client.rs +++ b/src/rpc/tungstenite_client/client.rs @@ -88,7 +88,7 @@ impl TungsteniteRpcClient { debug!("Connected to the server. Response HTTP code: {}", response.status()); // Send request to server. - socket.write_message(Message::Text(json_req))?; + socket.send(Message::Text(json_req))?; let msg = read_until_text_message(&mut socket)?; @@ -132,7 +132,7 @@ fn subscribe_to_server( debug!("Connected to the server. Response HTTP code: {}", response.status()); // Subscribe to server - socket.write_message(Message::Text(json_req))?; + socket.send(Message::Text(json_req))?; loop { let msg = read_until_text_message(&mut socket)?; @@ -180,7 +180,7 @@ fn attempt_connection_until(url: &Url, max_attempts: u8) -> Result<(MySocket, Re fn read_until_text_message(socket: &mut MySocket) -> Result { loop { - match socket.read_message()? { + match socket.read()? { Message::Text(s) => { debug!("receive text: {:?}", s); break Ok(s) diff --git a/testing/examples/dump_metadata.rs b/testing/examples/dump_metadata.rs new file mode 100644 index 000000000..ec8b61ff4 --- /dev/null +++ b/testing/examples/dump_metadata.rs @@ -0,0 +1,17 @@ +use sp_core::Bytes; +use std::{fs::File, io::prelude::*}; +use substrate_api_client::{ + ac_compose_macros::rpc_params, + rpc::{JsonrpseeClient, Request}, +}; + +// Simple file to dump new metdata as a file. +// Run with: cargo run -p ac-testing --example dump_metadata + +#[tokio::main] +async fn main() { + let client = JsonrpseeClient::new("wss://kusama-rpc.polkadot.io:443").unwrap(); + let metadata_bytes: Bytes = client.request("state_getMetadata", rpc_params![]).unwrap(); + let mut file = File::create("new_ksm_metadata.bin").unwrap(); + file.write_all(&metadata_bytes.0).unwrap(); +}