From 09a045fae7b00afd4b5ca97f2f813ad0157de332 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 3 Aug 2023 01:58:10 +0200 Subject: [PATCH 1/9] work in progress --- examples/wasm-example/Cargo.lock | 88 ++++++++++++++--------------- metadata/src/from_into/v15.rs | 1 + metadata/src/lib.rs | 11 ++++ subxt/src/client/offline_client.rs | 11 ++++ subxt/src/client/online_client.rs | 7 +++ subxt/src/custom_types/mod.rs | 24 ++++++++ subxt/src/lib.rs | 1 + subxt/src/metadata/metadata_type.rs | 23 ++++++++ 8 files changed, 122 insertions(+), 44 deletions(-) create mode 100644 subxt/src/custom_types/mod.rs diff --git a/examples/wasm-example/Cargo.lock b/examples/wasm-example/Cargo.lock index 63aea8e290..701700e09e 100644 --- a/examples/wasm-example/Cargo.lock +++ b/examples/wasm-example/Cargo.lock @@ -113,7 +113,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -537,7 +537,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -559,7 +559,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -762,7 +762,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1704,7 +1704,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2005,9 +2005,9 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scale-bits" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd7aca73785181cc41f0bbe017263e682b585ca660540ba569133901d013ecf" +checksum = "036575c29af9b6e4866ffb7fa055dbf623fe7a9cc159b33786de6013a6969d89" dependencies = [ "parity-scale-codec", "scale-info", @@ -2016,24 +2016,24 @@ dependencies = [ [[package]] name = "scale-decode" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0459d00b0dbd2e765009924a78ef36b2ff7ba116292d732f00eb0ed8e465d15" +checksum = "7789f5728e4e954aaa20cadcc370b99096fb8645fca3c9333ace44bb18f30095" dependencies = [ + "derive_more", "parity-scale-codec", "primitive-types", "scale-bits", "scale-decode-derive", "scale-info", "smallvec", - "thiserror", ] [[package]] name = "scale-decode-derive" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4391f0dfbb6690f035f6d2a15d6a12f88cc5395c36bcc056db07ffa2a90870ec" +checksum = "27873eb6005868f8cc72dcfe109fae664cf51223d35387bc2f28be4c28d94c47" dependencies = [ "darling 0.14.4", "proc-macro-crate", @@ -2044,24 +2044,24 @@ dependencies = [ [[package]] name = "scale-encode" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0401b7cdae8b8aa33725f3611a051358d5b32887ecaa0fda5953a775b2d4d76" +checksum = "6d70cb4b29360105483fac1ed567ff95d65224a14dd275b6303ed0a654c78de5" dependencies = [ + "derive_more", "parity-scale-codec", "primitive-types", "scale-bits", "scale-encode-derive", "scale-info", "smallvec", - "thiserror", ] [[package]] name = "scale-encode-derive" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "316e0fb10ec0fee266822bd641bab5e332a4ab80ef8c5b5ff35e5401a394f5a6" +checksum = "995491f110efdc6bea96d6a746140e32bfceb4ea47510750a5467295a4707a25" dependencies = [ "darling 0.14.4", "proc-macro-crate", @@ -2098,12 +2098,13 @@ dependencies = [ [[package]] name = "scale-value" -version = "0.10.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2096d36e94ce9bf87d8addb752423b6b19730dc88edd7cc452bb2b90573f7a7" +checksum = "6538d1cc1af9c0baf401c57da8a6d4730ef582db0d330d2efa56ec946b5b0283" dependencies = [ "base58", "blake2", + "derive_more", "either", "frame-metadata 15.1.0", "parity-scale-codec", @@ -2112,7 +2113,6 @@ dependencies = [ "scale-encode", "scale-info", "serde", - "thiserror", "yap", ] @@ -2194,9 +2194,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.175" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] @@ -2214,20 +2214,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -2490,7 +2490,7 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "subxt" -version = "0.30.0" +version = "0.31.0" dependencies = [ "base58", "blake2", @@ -2521,7 +2521,7 @@ dependencies = [ [[package]] name = "subxt-codegen" -version = "0.30.0" +version = "0.31.0" dependencies = [ "frame-metadata 16.0.0", "heck", @@ -2532,14 +2532,14 @@ dependencies = [ "quote", "scale-info", "subxt-metadata", - "syn 2.0.27", + "syn 2.0.28", "thiserror", "tokio", ] [[package]] name = "subxt-lightclient" -version = "0.30.0" +version = "0.31.0" dependencies = [ "futures", "futures-timer", @@ -2563,17 +2563,17 @@ dependencies = [ [[package]] name = "subxt-macro" -version = "0.30.0" +version = "0.31.0" dependencies = [ "darling 0.20.3", "proc-macro-error", "subxt-codegen", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] name = "subxt-metadata" -version = "0.30.0" +version = "0.31.0" dependencies = [ "frame-metadata 16.0.0", "parity-scale-codec", @@ -2595,9 +2595,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -2647,7 +2647,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2700,7 +2700,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2783,7 +2783,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2895,7 +2895,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -2929,7 +2929,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3136,9 +3136,9 @@ dependencies = [ [[package]] name = "yap" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a7eb6d82a11e4d0b8e6bda8347169aff4ccd8235d039bba7c47482d977dcf7" +checksum = "ff4524214bc4629eba08d78ceb1d6507070cc0bcbbed23af74e19e6e924a24cf" [[package]] name = "yew" @@ -3226,5 +3226,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] diff --git a/metadata/src/from_into/v15.rs b/metadata/src/from_into/v15.rs index bb3b6a83bf..f210089dce 100644 --- a/metadata/src/from_into/v15.rs +++ b/metadata/src/from_into/v15.rs @@ -93,6 +93,7 @@ mod from_v15 { event_enum_ty: m.outer_enums.event_enum_ty.id, error_enum_ty: m.outer_enums.error_enum_ty.id, }, + custom: m.custom, }) } } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 988bba1db9..e096657609 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -19,6 +19,7 @@ mod from_into; mod utils; +use frame_metadata::v15::CustomMetadata; use scale_info::{form::PortableForm, PortableRegistry, Variant}; use std::collections::HashMap; use std::sync::Arc; @@ -30,6 +31,9 @@ type ArcStr = Arc; pub use from_into::TryFromError; pub use utils::validation::MetadataHasher; +/// type alias for [frame_metadata::v15::CustomValueMetadata] +pub type CustomValueMetadata = frame_metadata::v15::CustomValueMetadata; + /// Node metadata. This can be constructed by providing some compatible [`frame_metadata`] /// which is then decoded into this. We aim to preserve all of the existing information in /// the incoming metadata while optimizing the format a little for Subxt's use cases. @@ -51,6 +55,8 @@ pub struct Metadata { dispatch_error_ty: Option, /// Details about each of the runtime API traits. apis: OrderedMap, + /// Allows users to add custom types to the metadata. A map that associates a string key to a `CustomValueMetadata`. + custom: CustomMetadata, } impl Metadata { @@ -132,6 +138,11 @@ impl Metadata { }) } + /// Returns custom user defined types + pub fn custom_metadata(&self) -> &CustomMetadata { + &self.custom + } + /// Obtain a unique hash representing this metadata or specific parts of it. pub fn hasher(&self) -> MetadataHasher { MetadataHasher::new(self) diff --git a/subxt/src/client/offline_client.rs b/subxt/src/client/offline_client.rs index e93f786f66..adbd6cdad1 100644 --- a/subxt/src/client/offline_client.rs +++ b/subxt/src/client/offline_client.rs @@ -8,6 +8,8 @@ use crate::{ tx::TxClient, Config, Metadata, }; use derivative::Derivative; +use frame_metadata::v15::CustomMetadata; +use scale_info::form::PortableForm; use std::sync::Arc; /// A trait representing a client that can perform @@ -49,6 +51,10 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { fn runtime_api(&self) -> RuntimeApiClient { RuntimeApiClient::new(self.clone()) } + + fn custom_types(&self) -> &CustomMetadata { + self.metadata().custom_metadata() + } } /// A client that is capable of performing offline-only operations. @@ -121,6 +127,11 @@ impl OfflineClient { pub fn constants(&self) -> ConstantsClient { >::constants(self) } + + /// Access custom types + fn custom_types(&self) -> &CustomMetadata { + >::custom_types(self) + } } impl OfflineClientT for OfflineClient { diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index 907dd5bc25..067ebff4f1 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -18,7 +18,9 @@ use crate::{ Config, Metadata, }; use derivative::Derivative; +use frame_metadata::v15::CustomMetadata; use futures::future; +use scale_info::form::PortableForm; use std::sync::{Arc, RwLock}; /// A trait representing a client that can perform @@ -292,6 +294,11 @@ impl OnlineClient { >::constants(self) } + /// Access custom types. + pub fn custom_types(&self) -> &CustomMetadata { + >::custom_types(self) + } + /// Work with blocks. pub fn blocks(&self) -> BlocksClient { >::blocks(self) diff --git a/subxt/src/custom_types/mod.rs b/subxt/src/custom_types/mod.rs new file mode 100644 index 0000000000..7fe4ecdab2 --- /dev/null +++ b/subxt/src/custom_types/mod.rs @@ -0,0 +1,24 @@ +use crate::client::OfflineClientT; +use crate::{Config, Metadata}; +use scale_info::form::PortableForm; +use std::borrow::Borrow; + +/// A client for accessing custom types. +#[derive(Derivative)] +#[derivative(Clone(bound = "Client: Clone"))] +pub struct CustomTypesClient { + metadata: Metadata, +} + +impl CustomTypesClient { + /// Create a new [`ConstantsClient`]. + pub fn new(metadata: Metadata) -> Self { + Self { metadata } + } +} + +impl CustomTypesClient { + pub fn get(&self, key: impl Borrow) -> Option<&CustomValueMetadata> { + self.metadata.custom_metadata().map.get(key) + } +} diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 4623d19aa3..38d8be7914 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -67,6 +67,7 @@ pub mod blocks; pub mod client; pub mod config; pub mod constants; +pub mod custom_types; pub mod dynamic; pub mod error; pub mod events; diff --git a/subxt/src/metadata/metadata_type.rs b/subxt/src/metadata/metadata_type.rs index 72520ef81c..01cbc5c066 100644 --- a/subxt/src/metadata/metadata_type.rs +++ b/subxt/src/metadata/metadata_type.rs @@ -3,6 +3,9 @@ // see LICENSE for license details. use crate::error::MetadataError; +use scale_decode::DecodeAsType; +use scale_encode::EncodeAsType; +use scale_info::form::PortableForm; use std::sync::Arc; /// A cheaply clone-able representation of the runtime metadata received from a node. @@ -71,3 +74,23 @@ impl codec::Decode for Metadata { subxt_metadata::Metadata::decode(input).map(Metadata::new) } } + +pub struct CustomValueMetadata { + inner: subxt_metadata::CustomValueMetadata, + metadata: Metadata, +} + +impl CustomValueMetadata { + pub fn encoded(&self) -> &[u8] { + &self.inner.value + } + + pub fn type_id(&self) -> u32 { + self.inner.ty.id + } + + pub fn as_type(&self) -> Result { + // use inner Arc that points to metadata to decode... + todo!() + } +} From e2af2cb1be3b21d51dbf5a70fcc72b67bbfe0e0e Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 3 Aug 2023 14:46:35 +0200 Subject: [PATCH 2/9] add custom types access --- subxt/src/client/offline_client.rs | 11 +- subxt/src/client/online_client.rs | 7 +- subxt/src/custom_types/mod.rs | 158 +++++++++++++++++++++++++--- subxt/src/lib.rs | 2 +- subxt/src/metadata/metadata_type.rs | 24 +---- 5 files changed, 155 insertions(+), 47 deletions(-) diff --git a/subxt/src/client/offline_client.rs b/subxt/src/client/offline_client.rs index adbd6cdad1..ae43209467 100644 --- a/subxt/src/client/offline_client.rs +++ b/subxt/src/client/offline_client.rs @@ -2,14 +2,14 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use crate::custom_types::CustomTypes; use crate::{ blocks::BlocksClient, constants::ConstantsClient, events::EventsClient, rpc::types::RuntimeVersion, runtime_api::RuntimeApiClient, storage::StorageClient, tx::TxClient, Config, Metadata, }; use derivative::Derivative; -use frame_metadata::v15::CustomMetadata; -use scale_info::form::PortableForm; + use std::sync::Arc; /// A trait representing a client that can perform @@ -52,8 +52,9 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { RuntimeApiClient::new(self.clone()) } - fn custom_types(&self) -> &CustomMetadata { - self.metadata().custom_metadata() + /// Work this custom types. + fn custom_types(&self) -> CustomTypes { + CustomTypes::new(self.metadata()) } } @@ -129,7 +130,7 @@ impl OfflineClient { } /// Access custom types - fn custom_types(&self) -> &CustomMetadata { + pub fn custom_types(&self) -> CustomTypes { >::custom_types(self) } } diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index 067ebff4f1..c0859eb4a1 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -3,6 +3,7 @@ // see LICENSE for license details. use super::{OfflineClient, OfflineClientT}; +use crate::custom_types::CustomTypes; use crate::{ blocks::BlocksClient, constants::ConstantsClient, @@ -18,9 +19,9 @@ use crate::{ Config, Metadata, }; use derivative::Derivative; -use frame_metadata::v15::CustomMetadata; + use futures::future; -use scale_info::form::PortableForm; + use std::sync::{Arc, RwLock}; /// A trait representing a client that can perform @@ -295,7 +296,7 @@ impl OnlineClient { } /// Access custom types. - pub fn custom_types(&self) -> &CustomMetadata { + pub fn custom_types(&self) -> CustomTypes { >::custom_types(self) } diff --git a/subxt/src/custom_types/mod.rs b/subxt/src/custom_types/mod.rs index 7fe4ecdab2..9aae8680ec 100644 --- a/subxt/src/custom_types/mod.rs +++ b/subxt/src/custom_types/mod.rs @@ -1,24 +1,152 @@ -use crate::client::OfflineClientT; -use crate::{Config, Metadata}; -use scale_info::form::PortableForm; -use std::borrow::Borrow; - -/// A client for accessing custom types. -#[derive(Derivative)] -#[derivative(Clone(bound = "Client: Clone"))] -pub struct CustomTypesClient { +// 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. + +//! Types associated with accessing custom types + +use crate::error::MetadataError; +use crate::Metadata; +use scale_decode::DecodeAsType; + +/// gives you access to all `CustomValueMetadata` entries that are available as custom types on the metadata. +pub struct CustomTypes { metadata: Metadata, } -impl CustomTypesClient { - /// Create a new [`ConstantsClient`]. +impl CustomTypes { + /// create a new CustomTypes instance, taking shared ownership of the metadata pub fn new(metadata: Metadata) -> Self { - Self { metadata } + CustomTypes { metadata } + } + + /// get a [CustomValueMetadata] by the string key it is registered under + pub fn get(&self, key: &str) -> Option { + self.metadata + .custom_metadata() + .map + .get(key) + .map(|inner| CustomValueMetadata { + inner, + custom_types: self, + }) + } +} + +/// a wrapper around [subxt_metadata::CustomValueMetadata]. Can be used to decode a custom type. +pub struct CustomValueMetadata<'a> { + inner: &'a subxt_metadata::CustomValueMetadata, + /// contains an Arc to the actual metadata, so this is pretty light-weight + custom_types: &'a CustomTypes, +} + +impl<'a> CustomValueMetadata<'a> { + /// the scale encoded value + pub fn encoded(&self) -> &[u8] { + &self.inner.value + } + + /// the type id in the TypeRegistry + pub fn type_id(&self) -> u32 { + self.inner.ty.id + } + + /// attempts to decode the scale encoded value of this custom type into the type + pub fn as_type(&self) -> Result { + let cursor = &mut self.encoded(); + let type_id = self.type_id(); + if self + .custom_types + .metadata + .types() + .resolve(type_id) + .is_none() + { + return Err(MetadataError::TypeNotFound(type_id).into()); + } + let decoded = T::decode_as_type(cursor, type_id, self.custom_types.metadata.types())?; + Ok(decoded) } } -impl CustomTypesClient { - pub fn get(&self, key: impl Borrow) -> Option<&CustomValueMetadata> { - self.metadata.custom_metadata().map.get(key) +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use crate::custom_types::CustomTypes; + use crate::Metadata; + use scale_decode::DecodeAsType; + use scale_info::form::PortableForm; + use scale_info::TypeInfo; + use sp_core::Encode; + + #[derive(Debug, Clone, PartialEq, Eq, Encode, TypeInfo, DecodeAsType)] + pub struct Person { + age: u16, + name: String, + } + + fn mock_metadata() -> Metadata { + let person_ty = scale_info::MetaType::new::(); + let unit = scale_info::MetaType::new::<()>(); + let mut types = scale_info::Registry::new(); + let person_ty_id = types.register_type(&person_ty); + let unit_id = types.register_type(&unit); + let types: scale_info::PortableRegistry = types.into(); + + let person = Person { + age: 42, + name: "Neo".into(), + }; + + let person_value_metadata: frame_metadata::v15::CustomValueMetadata = + frame_metadata::v15::CustomValueMetadata { + ty: person_ty_id, + value: person.encode(), + }; + + let frame_metadata = frame_metadata::v15::RuntimeMetadataV15 { + types, + pallets: vec![], + extrinsic: frame_metadata::v15::ExtrinsicMetadata { + version: 0, + address_ty: unit_id, + call_ty: unit_id, + signature_ty: unit_id, + extra_ty: unit_id, + signed_extensions: vec![], + }, + ty: unit_id, + apis: vec![], + outer_enums: frame_metadata::v15::OuterEnums { + call_enum_ty: unit_id, + event_enum_ty: unit_id, + error_enum_ty: unit_id, + }, + custom: frame_metadata::v15::CustomMetadata { + map: { + let mut m = BTreeMap::new(); + m.insert("Person".to_string(), person_value_metadata); + m + }, + }, + }; + + let metadata: subxt_metadata::Metadata = frame_metadata.try_into().unwrap(); + Metadata::new(metadata) + } + + #[test] + fn test_decoding() { + let custom_types = CustomTypes::new(mock_metadata()); + assert!(custom_types.get("No one").is_none()); + let person_value = custom_types.get("Person").unwrap(); + let person: Person = person_value.as_type().unwrap(); + assert_eq!( + person, + Person { + age: 42, + name: "Neo".into() + } + ) } } diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 38d8be7914..056788ab4e 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -5,7 +5,7 @@ //! Subxt is a library for interacting with Substrate based nodes. Using it looks something like this: //! //! ```rust,ignore -#![doc = include_str!("../examples/tx_basic.rs")] +#![doc = include_str ! ("../examples/tx_basic.rs")] //! ``` //! //! Take a look at [the Subxt guide](book) to learn more about how to use Subxt. diff --git a/subxt/src/metadata/metadata_type.rs b/subxt/src/metadata/metadata_type.rs index 01cbc5c066..29ae567afa 100644 --- a/subxt/src/metadata/metadata_type.rs +++ b/subxt/src/metadata/metadata_type.rs @@ -3,9 +3,7 @@ // see LICENSE for license details. use crate::error::MetadataError; -use scale_decode::DecodeAsType; -use scale_encode::EncodeAsType; -use scale_info::form::PortableForm; + use std::sync::Arc; /// A cheaply clone-able representation of the runtime metadata received from a node. @@ -74,23 +72,3 @@ impl codec::Decode for Metadata { subxt_metadata::Metadata::decode(input).map(Metadata::new) } } - -pub struct CustomValueMetadata { - inner: subxt_metadata::CustomValueMetadata, - metadata: Metadata, -} - -impl CustomValueMetadata { - pub fn encoded(&self) -> &[u8] { - &self.inner.value - } - - pub fn type_id(&self) -> u32 { - self.inner.ty.id - } - - pub fn as_type(&self) -> Result { - // use inner Arc that points to metadata to decode... - todo!() - } -} From 72ad54b2fee852b4c27f6c52ee60f4f2f1ca6098 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 8 Aug 2023 13:23:29 +0200 Subject: [PATCH 3/9] nit --- subxt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 056788ab4e..38d8be7914 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -5,7 +5,7 @@ //! Subxt is a library for interacting with Substrate based nodes. Using it looks something like this: //! //! ```rust,ignore -#![doc = include_str ! ("../examples/tx_basic.rs")] +#![doc = include_str!("../examples/tx_basic.rs")] //! ``` //! //! Take a look at [the Subxt guide](book) to learn more about how to use Subxt. From 50da61c3273f81f9859dee70369124ebe696caac Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Wed, 9 Aug 2023 14:43:04 +0200 Subject: [PATCH 4/9] custom values client --- metadata/src/from_into/v15.rs | 3 +- metadata/src/lib.rs | 44 ++++++- subxt/src/book/mod.rs | 2 +- subxt/src/client/offline_client.rs | 10 +- subxt/src/client/online_client.rs | 6 +- .../src/custom_values/custom_value_adress.rs | 21 +++ .../custom_values_client.rs} | 120 ++++++++---------- subxt/src/custom_values/mod.rs | 11 ++ subxt/src/dynamic.rs | 8 ++ subxt/src/error/mod.rs | 3 + subxt/src/lib.rs | 2 +- 11 files changed, 145 insertions(+), 85 deletions(-) create mode 100644 subxt/src/custom_values/custom_value_adress.rs rename subxt/src/{custom_types/mod.rs => custom_values/custom_values_client.rs} (50%) create mode 100644 subxt/src/custom_values/mod.rs diff --git a/metadata/src/from_into/v15.rs b/metadata/src/from_into/v15.rs index f210089dce..559b633f1e 100644 --- a/metadata/src/from_into/v15.rs +++ b/metadata/src/from_into/v15.rs @@ -17,6 +17,7 @@ use std::collections::HashMap; // Converting from V15 metadata into our Subxt repr. mod from_v15 { use super::*; + use crate::CustomMetadata; impl TryFrom for Metadata { type Error = TryFromError; @@ -93,7 +94,7 @@ mod from_v15 { event_enum_ty: m.outer_enums.event_enum_ty.id, error_enum_ty: m.outer_enums.error_enum_ty.id, }, - custom: m.custom, + custom: CustomMetadata { map: m.custom.map }, }) } } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index e096657609..f713329dd3 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -19,9 +19,8 @@ mod from_into; mod utils; -use frame_metadata::v15::CustomMetadata; use scale_info::{form::PortableForm, PortableRegistry, Variant}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; use utils::ordered_map::OrderedMap; use utils::variant_index::VariantIndex; @@ -31,9 +30,6 @@ type ArcStr = Arc; pub use from_into::TryFromError; pub use utils::validation::MetadataHasher; -/// type alias for [frame_metadata::v15::CustomValueMetadata] -pub type CustomValueMetadata = frame_metadata::v15::CustomValueMetadata; - /// Node metadata. This can be constructed by providing some compatible [`frame_metadata`] /// which is then decoded into this. We aim to preserve all of the existing information in /// the incoming metadata while optimizing the format a little for Subxt's use cases. @@ -56,7 +52,7 @@ pub struct Metadata { /// Details about each of the runtime API traits. apis: OrderedMap, /// Allows users to add custom types to the metadata. A map that associates a string key to a `CustomValueMetadata`. - custom: CustomMetadata, + custom: CustomMetadata, } impl Metadata { @@ -139,7 +135,7 @@ impl Metadata { } /// Returns custom user defined types - pub fn custom_metadata(&self) -> &CustomMetadata { + pub fn custom(&self) -> &CustomMetadata { &self.custom } @@ -642,6 +638,40 @@ pub struct RuntimeApiMethodParamMetadata { pub ty: u32, } +/// Metadata of custom types with custom values, basically the same as `frame_metadata::v15::CustomMetadata>`. +#[derive(Debug, Clone)] +pub struct CustomMetadata { + pub(crate) map: BTreeMap>, +} + +impl CustomMetadata { + /// Get a certain [CustomMetadataValue] by its name. + pub fn get(&self, name: &str) -> Option> { + self.map.get(name).map(|e| CustomMetadataValue { + type_id: e.ty.id, + data: &e.value, + }) + } +} + +/// Basically the same as `frame_metadata::v15::CustomValueMetadata>`, but borrowed. +pub struct CustomMetadataValue<'a> { + type_id: u32, + data: &'a [u8], +} + +impl<'a> CustomMetadataValue<'a> { + /// the scale encoded value + pub fn bytes(&self) -> &[u8] { + &self.data + } + + /// the type id in the TypeRegistry + pub fn type_id(&self) -> u32 { + self.type_id + } +} + // Support decoding metadata from the "wire" format directly into this. // Errors may be lost in the case that the metadata content is somehow invalid. impl codec::Decode for Metadata { diff --git a/subxt/src/book/mod.rs b/subxt/src/book/mod.rs index 95091c04c2..14e710022c 100644 --- a/subxt/src/book/mod.rs +++ b/subxt/src/book/mod.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. // Dev note; I used the following command to normalize and wrap comments: -// rustfmt +nightly --config wrap_comments=true,comment_width=100,normalize_comments=true subxt/src/book/mod.rs +// rustfmt +nightly --config wrap_comments=true,comment_width=100,normalize_comments=true subxt/src/book/custom_values // It messed up comments in code blocks though, so be prepared to go and fix those. //! # The Subxt Guide diff --git a/subxt/src/client/offline_client.rs b/subxt/src/client/offline_client.rs index ae43209467..be81cd5b7e 100644 --- a/subxt/src/client/offline_client.rs +++ b/subxt/src/client/offline_client.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::custom_types::CustomTypes; +use crate::custom_values::CustomValuesClient; use crate::{ blocks::BlocksClient, constants::ConstantsClient, events::EventsClient, rpc::types::RuntimeVersion, runtime_api::RuntimeApiClient, storage::StorageClient, @@ -53,8 +53,8 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { } /// Work this custom types. - fn custom_types(&self) -> CustomTypes { - CustomTypes::new(self.metadata()) + fn custom_values(&self) -> CustomValuesClient { + CustomValuesClient::new(self.clone()) } } @@ -130,8 +130,8 @@ impl OfflineClient { } /// Access custom types - pub fn custom_types(&self) -> CustomTypes { - >::custom_types(self) + pub fn custom_values(&self) -> CustomValuesClient { + >::custom_values(self) } } diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index c0859eb4a1..7ab7474da2 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. use super::{OfflineClient, OfflineClientT}; -use crate::custom_types::CustomTypes; +use crate::custom_values::CustomValuesClient; use crate::{ blocks::BlocksClient, constants::ConstantsClient, @@ -296,8 +296,8 @@ impl OnlineClient { } /// Access custom types. - pub fn custom_types(&self) -> CustomTypes { - >::custom_types(self) + pub fn custom_values(&self) -> CustomValuesClient { + >::custom_values(self) } /// Work with blocks. diff --git a/subxt/src/custom_values/custom_value_adress.rs b/subxt/src/custom_values/custom_value_adress.rs new file mode 100644 index 0000000000..cae7a335b8 --- /dev/null +++ b/subxt/src/custom_values/custom_value_adress.rs @@ -0,0 +1,21 @@ +use crate::dynamic::DecodedValueThunk; +use crate::metadata::DecodeWithMetadata; + +/// This represents the address of a custom value in in the metadata. +/// Anything, that implements the [CustomValueAddress] trait can be used, to fetch +/// custom values from the metadata. +pub trait CustomValueAddress { + /// The type of the custom value. + type Target: DecodeWithMetadata; + + /// the name (key) by which the custom value can be accessed in the metadata. + fn name(&self) -> &str; +} + +impl CustomValueAddress for str { + type Target = DecodedValueThunk; + + fn name(&self) -> &str { + self + } +} diff --git a/subxt/src/custom_types/mod.rs b/subxt/src/custom_values/custom_values_client.rs similarity index 50% rename from subxt/src/custom_types/mod.rs rename to subxt/src/custom_values/custom_values_client.rs index 9aae8680ec..6c5b03c647 100644 --- a/subxt/src/custom_types/mod.rs +++ b/subxt/src/custom_values/custom_values_client.rs @@ -1,70 +1,46 @@ -// 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. - -//! Types associated with accessing custom types - +use crate::client::OfflineClientT; +use crate::custom_values::custom_value_adress::CustomValueAddress; use crate::error::MetadataError; -use crate::Metadata; -use scale_decode::DecodeAsType; - -/// gives you access to all `CustomValueMetadata` entries that are available as custom types on the metadata. -pub struct CustomTypes { - metadata: Metadata, +use crate::metadata::DecodeWithMetadata; +use crate::{Config, Error}; +use derivative::Derivative; + +/// A client for accessing custom values stored in the metadata. +#[derive(Derivative)] +#[derivative(Clone(bound = "Client: Clone"))] +pub struct CustomValuesClient { + client: Client, + _marker: std::marker::PhantomData, } -impl CustomTypes { - /// create a new CustomTypes instance, taking shared ownership of the metadata - pub fn new(metadata: Metadata) -> Self { - CustomTypes { metadata } - } - - /// get a [CustomValueMetadata] by the string key it is registered under - pub fn get(&self, key: &str) -> Option { - self.metadata - .custom_metadata() - .map - .get(key) - .map(|inner| CustomValueMetadata { - inner, - custom_types: self, - }) +impl CustomValuesClient { + /// Create a new [`ConstantsClient`]. + pub fn new(client: Client) -> Self { + Self { + client, + _marker: std::marker::PhantomData, + } } } -/// a wrapper around [subxt_metadata::CustomValueMetadata]. Can be used to decode a custom type. -pub struct CustomValueMetadata<'a> { - inner: &'a subxt_metadata::CustomValueMetadata, - /// contains an Arc to the actual metadata, so this is pretty light-weight - custom_types: &'a CustomTypes, -} - -impl<'a> CustomValueMetadata<'a> { - /// the scale encoded value - pub fn encoded(&self) -> &[u8] { - &self.inner.value - } - - /// the type id in the TypeRegistry - pub fn type_id(&self) -> u32 { - self.inner.ty.id - } - - /// attempts to decode the scale encoded value of this custom type into the type - pub fn as_type(&self) -> Result { - let cursor = &mut self.encoded(); - let type_id = self.type_id(); - if self - .custom_types - .metadata - .types() - .resolve(type_id) - .is_none() - { - return Err(MetadataError::TypeNotFound(type_id).into()); - } - let decoded = T::decode_as_type(cursor, type_id, self.custom_types.metadata.types())?; - Ok(decoded) +impl> CustomValuesClient { + /// get a [CustomMetadataValue] by the string key it is registered under + pub fn at( + &self, + address: &Address, + ) -> Result { + let metadata = self.client.metadata(); + let custom_value = metadata + .custom() + .get(address.name()) + .ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().to_string()))?; + + let value = ::decode_with_metadata( + &mut custom_value.bytes(), + custom_value.type_id(), + &metadata, + )?; + Ok(value) } } @@ -72,8 +48,9 @@ impl<'a> CustomValueMetadata<'a> { mod tests { use std::collections::BTreeMap; - use crate::custom_types::CustomTypes; - use crate::Metadata; + use crate::custom_values::CustomValuesClient; + use crate::rpc::types::RuntimeVersion; + use crate::{Metadata, OfflineClient, SubstrateConfig}; use scale_decode::DecodeAsType; use scale_info::form::PortableForm; use scale_info::TypeInfo; @@ -137,10 +114,19 @@ mod tests { #[test] fn test_decoding() { - let custom_types = CustomTypes::new(mock_metadata()); - assert!(custom_types.get("No one").is_none()); - let person_value = custom_types.get("Person").unwrap(); - let person: Person = person_value.as_type().unwrap(); + let client = OfflineClient::::new( + Default::default(), + RuntimeVersion { + spec_version: 0, + transaction_version: 0, + other: Default::default(), + }, + mock_metadata(), + ); + let custom_value_client = CustomValuesClient::new(client); + assert!(custom_value_client.at("No one").is_err()); + let person_decoded_value_thunk = custom_value_client.at("Person").unwrap(); + let person: Person = person_decoded_value_thunk.as_type().unwrap(); assert_eq!( person, Person { diff --git a/subxt/src/custom_values/mod.rs b/subxt/src/custom_values/mod.rs new file mode 100644 index 0000000000..27a566e3bc --- /dev/null +++ b/subxt/src/custom_values/mod.rs @@ -0,0 +1,11 @@ +// 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. + +//! Types associated with accessing custom types + +mod custom_value_adress; +mod custom_values_client; + +pub use custom_value_adress::CustomValueAddress; +pub use custom_values_client::CustomValuesClient; diff --git a/subxt/src/dynamic.rs b/subxt/src/dynamic.rs index ec318da4c9..389f8d6ff4 100644 --- a/subxt/src/dynamic.rs +++ b/subxt/src/dynamic.rs @@ -75,4 +75,12 @@ impl DecodedValueThunk { )?; Ok(val) } + /// decode the `DecodedValueThunk` into a concrete type. + pub fn as_type(&self) -> Result { + T::decode_as_type( + &mut &self.scale_bytes[..], + self.type_id, + self.metadata.types(), + ) + } } diff --git a/subxt/src/error/mod.rs b/subxt/src/error/mod.rs index 54bd80414c..2c40e09373 100644 --- a/subxt/src/error/mod.rs +++ b/subxt/src/error/mod.rs @@ -234,4 +234,7 @@ pub enum MetadataError { /// 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), } diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 38d8be7914..95dd4bd7ee 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -67,7 +67,7 @@ pub mod blocks; pub mod client; pub mod config; pub mod constants; -pub mod custom_types; +pub mod custom_values; pub mod dynamic; pub mod error; pub mod events; From e8f21401f83f5cae7ca8a74c859420092e554201 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Wed, 9 Aug 2023 18:31:05 +0200 Subject: [PATCH 5/9] adjust light client --- metadata/src/from_into/v15.rs | 9 ++++----- metadata/src/lib.rs | 6 +++--- subxt/src/client/lightclient/mod.rs | 6 ++++++ .../{custom_value_adress.rs => custom_value_address.rs} | 0 subxt/src/custom_values/custom_values_client.rs | 8 ++------ subxt/src/custom_values/mod.rs | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) rename subxt/src/custom_values/{custom_value_adress.rs => custom_value_address.rs} (100%) diff --git a/metadata/src/from_into/v15.rs b/metadata/src/from_into/v15.rs index 559b633f1e..bec4b3ff3f 100644 --- a/metadata/src/from_into/v15.rs +++ b/metadata/src/from_into/v15.rs @@ -5,10 +5,10 @@ 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, + utils::ordered_map::OrderedMap, ArcStr, ConstantMetadata, CustomMetadata, ExtrinsicMetadata, + Metadata, OuterEnumsMetadata, PalletMetadataInner, RuntimeApiMetadataInner, + RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, SignedExtensionMetadata, + StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher, StorageMetadata, }; use frame_metadata::v15; use scale_info::form::PortableForm; @@ -17,7 +17,6 @@ use std::collections::HashMap; // Converting from V15 metadata into our Subxt repr. mod from_v15 { use super::*; - use crate::CustomMetadata; impl TryFrom for Metadata { type Error = TryFromError; diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index f713329dd3..ea0a43598d 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -641,7 +641,7 @@ pub struct RuntimeApiMethodParamMetadata { /// Metadata of custom types with custom values, basically the same as `frame_metadata::v15::CustomMetadata>`. #[derive(Debug, Clone)] pub struct CustomMetadata { - pub(crate) map: BTreeMap>, + map: BTreeMap>, } impl CustomMetadata { @@ -662,8 +662,8 @@ pub struct CustomMetadataValue<'a> { impl<'a> CustomMetadataValue<'a> { /// the scale encoded value - pub fn bytes(&self) -> &[u8] { - &self.data + pub fn bytes(&self) -> &'a [u8] { + self.data } /// the type id in the TypeRegistry diff --git a/subxt/src/client/lightclient/mod.rs b/subxt/src/client/lightclient/mod.rs index 63bb48a0b6..ef95173f35 100644 --- a/subxt/src/client/lightclient/mod.rs +++ b/subxt/src/client/lightclient/mod.rs @@ -12,6 +12,7 @@ use crate::{ client::{OfflineClientT, OnlineClientT}, config::Config, constants::ConstantsClient, + custom_values::CustomValuesClient, events::EventsClient, runtime_api::RuntimeApiClient, storage::StorageClient, @@ -100,6 +101,11 @@ impl LightClient { >::constants(self) } + /// Access custom types. + pub fn custom_values(&self) -> CustomValuesClient { + >::custom_values(self) + } + /// Work with blocks. pub fn blocks(&self) -> BlocksClient { >::blocks(self) diff --git a/subxt/src/custom_values/custom_value_adress.rs b/subxt/src/custom_values/custom_value_address.rs similarity index 100% rename from subxt/src/custom_values/custom_value_adress.rs rename to subxt/src/custom_values/custom_value_address.rs diff --git a/subxt/src/custom_values/custom_values_client.rs b/subxt/src/custom_values/custom_values_client.rs index 6c5b03c647..92659c60b2 100644 --- a/subxt/src/custom_values/custom_values_client.rs +++ b/subxt/src/custom_values/custom_values_client.rs @@ -1,5 +1,5 @@ use crate::client::OfflineClientT; -use crate::custom_values::custom_value_adress::CustomValueAddress; +use crate::custom_values::custom_value_address::CustomValueAddress; use crate::error::MetadataError; use crate::metadata::DecodeWithMetadata; use crate::{Config, Error}; @@ -100,11 +100,7 @@ mod tests { error_enum_ty: unit_id, }, custom: frame_metadata::v15::CustomMetadata { - map: { - let mut m = BTreeMap::new(); - m.insert("Person".to_string(), person_value_metadata); - m - }, + map: BTreeMap::from_iter([("Person".to_string(), person_value_metadata)]), }, }; diff --git a/subxt/src/custom_values/mod.rs b/subxt/src/custom_values/mod.rs index 27a566e3bc..16b6354014 100644 --- a/subxt/src/custom_values/mod.rs +++ b/subxt/src/custom_values/mod.rs @@ -4,8 +4,8 @@ //! Types associated with accessing custom types -mod custom_value_adress; +mod custom_value_address; mod custom_values_client; -pub use custom_value_adress::CustomValueAddress; +pub use custom_value_address::CustomValueAddress; pub use custom_values_client::CustomValuesClient; From f286b261ca8b2e7330d64d6e336ec302b385e916 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 10 Aug 2023 14:28:24 +0200 Subject: [PATCH 6/9] adjust doc comments --- subxt/src/custom_values/custom_values_client.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subxt/src/custom_values/custom_values_client.rs b/subxt/src/custom_values/custom_values_client.rs index 92659c60b2..04e3903ba5 100644 --- a/subxt/src/custom_values/custom_values_client.rs +++ b/subxt/src/custom_values/custom_values_client.rs @@ -14,7 +14,7 @@ pub struct CustomValuesClient { } impl CustomValuesClient { - /// Create a new [`ConstantsClient`]. + /// Create a new [`CustomValuesClient`]. pub fn new(client: Client) -> Self { Self { client, @@ -24,7 +24,8 @@ impl CustomValuesClient { } impl> CustomValuesClient { - /// get a [CustomMetadataValue] by the string key it is registered under + /// Access a custom value by the address it is registered under. This can be just a [str] to get back a dynamic value, + /// or a static address from the generated static interface to get a value of a static type returned. pub fn at( &self, address: &Address, From 2f83d36618d1c05a33a437702258bbcaae4dbf04 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 10 Aug 2023 15:55:24 +0200 Subject: [PATCH 7/9] adjust book for custom values in code gen --- subxt/src/book/usage/custom_values.rs | 54 +++++++++++++++++++++++++++ subxt/src/book/usage/mod.rs | 2 + 2 files changed, 56 insertions(+) create mode 100644 subxt/src/book/usage/custom_values.rs diff --git a/subxt/src/book/usage/custom_values.rs b/subxt/src/book/usage/custom_values.rs new file mode 100644 index 0000000000..d8f807d4a0 --- /dev/null +++ b/subxt/src/book/usage/custom_values.rs @@ -0,0 +1,54 @@ +// 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. + +//! # Custom Values +//! +//! Substrate-based chains can expose custom values in their metadata. +//! Each of these values: +//! +//! - can be accessed by a unique __name__. +//! - refers to a concrete __type__ stored in the metadata. +//! - contains a scale encoded __value__ of that type. +//! +//! ## Getting a custom value +//! +//! Custom values can be accessed via a [`CustomValuesClient`](subxt::custom_values::CustomValuesClient). +//! The client exposes an `at` function by which a custom value can be fetched, given an address to this custom value. +//! An address can be as simple as the aforementioned __name__ as a [str]. This will return a dynamic value, that you can manually decode into the type you want. +//! Suppose, the custom types contain a value of type `Foo` under the name `"foo"` you can access it like in this example: +//! +//! ```rust +//! use subxt::{OnlineClient, PolkadotConfig, ext::{codec::Decode, scale_decode::DecodeAsType}}; +//! +//! #[derive(Decode, DecodeAsType, Debug)] +//! struct Foo { +//! n: u8, +//! b: bool, +//! } +//! +//! let api = OnlineClient::::new().await?; +//! let custom_value_client = api.custom_values(); +//! let foo_dynamic = custom_value_client.at("foo")?; +//! let foo: Foo = foo_dynamic.as_type()?; +//! +//! ``` +//! +//! Alternatively we also provide a statically generated api for custom values: +//! +//! ```rust,no_run +//! #[subxt::subxt(runtime_metadata_path = "some_metadata.scale")] +//! pub mod interface {} +//! +//! let static_address = interface::custom().foo(); +//! +//! let api = OnlineClient::::new().await?; +//! let custom_value_client = api.custom_values(); +//! +//! // Now the `at()` function already decodes the value into the Foo type: +//! let foo = custom_value_client.at(&static_address)?; +//! ``` +//! +//! Note: Names of custom values are converted to __snake_case__ to produce a valid function name during code generation. +//! If there are multiple values where the names would be equal when converted to __snake_case__, functions might not be statically generated for some of them, because of naming conflicts. +//! Make sure names in the custom values of your metadata differ significantly. diff --git a/subxt/src/book/usage/mod.rs b/subxt/src/book/usage/mod.rs index 1029e63444..45aa5516e0 100644 --- a/subxt/src/book/usage/mod.rs +++ b/subxt/src/book/usage/mod.rs @@ -11,6 +11,7 @@ //! - [Blocks](blocks) //! - [Runtime APIs](runtime_apis) //! - [Unstable Light Client](light_client) +//! - [Custom Values](custom_values) //! //! Alternately, [go back](super). @@ -21,3 +22,4 @@ pub mod light_client; pub mod runtime_apis; pub mod storage; pub mod transactions; +pub mod custom_values; From 57be757f2cd65cb1e8255d8cb520aa1358cf5861 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 10 Aug 2023 15:57:40 +0200 Subject: [PATCH 8/9] format and check docs --- subxt/src/book/usage/custom_values.rs | 32 +++++++++++++-------------- subxt/src/book/usage/mod.rs | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/subxt/src/book/usage/custom_values.rs b/subxt/src/book/usage/custom_values.rs index d8f807d4a0..b5315757a4 100644 --- a/subxt/src/book/usage/custom_values.rs +++ b/subxt/src/book/usage/custom_values.rs @@ -6,49 +6,49 @@ //! //! Substrate-based chains can expose custom values in their metadata. //! Each of these values: -//! +//! //! - can be accessed by a unique __name__. //! - refers to a concrete __type__ stored in the metadata. //! - contains a scale encoded __value__ of that type. -//! +//! //! ## Getting a custom value -//! -//! Custom values can be accessed via a [`CustomValuesClient`](subxt::custom_values::CustomValuesClient). +//! +//! Custom values can be accessed via a [`CustomValuesClient`](crate::custom_values::CustomValuesClient). //! The client exposes an `at` function by which a custom value can be fetched, given an address to this custom value. -//! An address can be as simple as the aforementioned __name__ as a [str]. This will return a dynamic value, that you can manually decode into the type you want. +//! An address can be as simple as the aforementioned __name__ as a [str]. This will return a dynamic value, that you can manually decode into the type you want. //! Suppose, the custom types contain a value of type `Foo` under the name `"foo"` you can access it like in this example: -//! +//! //! ```rust //! use subxt::{OnlineClient, PolkadotConfig, ext::{codec::Decode, scale_decode::DecodeAsType}}; -//! +//! //! #[derive(Decode, DecodeAsType, Debug)] -//! struct Foo { +//! struct Foo { //! n: u8, //! b: bool, //! } -//! +//! //! let api = OnlineClient::::new().await?; //! let custom_value_client = api.custom_values(); //! let foo_dynamic = custom_value_client.at("foo")?; //! let foo: Foo = foo_dynamic.as_type()?; -//! +//! //! ``` -//! +//! //! Alternatively we also provide a statically generated api for custom values: -//! +//! //! ```rust,no_run //! #[subxt::subxt(runtime_metadata_path = "some_metadata.scale")] //! pub mod interface {} //! //! let static_address = interface::custom().foo(); -//! +//! //! let api = OnlineClient::::new().await?; //! let custom_value_client = api.custom_values(); -//! +//! //! // Now the `at()` function already decodes the value into the Foo type: -//! let foo = custom_value_client.at(&static_address)?; +//! let foo = custom_value_client.at(&static_address)?; //! ``` -//! +//! //! Note: Names of custom values are converted to __snake_case__ to produce a valid function name during code generation. //! If there are multiple values where the names would be equal when converted to __snake_case__, functions might not be statically generated for some of them, because of naming conflicts. //! Make sure names in the custom values of your metadata differ significantly. diff --git a/subxt/src/book/usage/mod.rs b/subxt/src/book/usage/mod.rs index 45aa5516e0..9986d3d7c0 100644 --- a/subxt/src/book/usage/mod.rs +++ b/subxt/src/book/usage/mod.rs @@ -17,9 +17,9 @@ pub mod blocks; pub mod constants; +pub mod custom_values; pub mod events; pub mod light_client; pub mod runtime_apis; pub mod storage; pub mod transactions; -pub mod custom_values; From 922fee2a68120a04bf690c1baeb2627bdc58247d Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 11 Aug 2023 14:22:19 +0200 Subject: [PATCH 9/9] use ignore in docs in book --- subxt/src/book/usage/custom_values.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subxt/src/book/usage/custom_values.rs b/subxt/src/book/usage/custom_values.rs index b5315757a4..ec3fdb6184 100644 --- a/subxt/src/book/usage/custom_values.rs +++ b/subxt/src/book/usage/custom_values.rs @@ -18,7 +18,7 @@ //! An address can be as simple as the aforementioned __name__ as a [str]. This will return a dynamic value, that you can manually decode into the type you want. //! Suppose, the custom types contain a value of type `Foo` under the name `"foo"` you can access it like in this example: //! -//! ```rust +//! ```rust,ignore //! use subxt::{OnlineClient, PolkadotConfig, ext::{codec::Decode, scale_decode::DecodeAsType}}; //! //! #[derive(Decode, DecodeAsType, Debug)] @@ -36,7 +36,7 @@ //! //! Alternatively we also provide a statically generated api for custom values: //! -//! ```rust,no_run +//! ```rust,ignore //! #[subxt::subxt(runtime_metadata_path = "some_metadata.scale")] //! pub mod interface {} //!