From fd3fa992730b1ea4e92357506ca0376d0835ee42 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 8 Feb 2021 17:20:33 +0000 Subject: [PATCH 01/18] Global registration of type segmenters for event decoding --- .rustfmt.toml | 2 +- Cargo.toml | 1 + examples/transfer_subscribe.rs | 6 +- src/events.rs | 273 ++++++++++++++++++++------------- src/frame/balances.rs | 5 +- src/lib.rs | 23 ++- 6 files changed, 200 insertions(+), 110 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index da09889f0c..60f5650170 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -19,7 +19,7 @@ fn_single_line = false where_single_line = false imports_indent = "Block" imports_layout = "Vertical" # changed -merge_imports = true # changed +imports_granularity = "Crate" # changed reorder_imports = true reorder_modules = true reorder_impl_items = false diff --git a/Cargo.toml b/Cargo.toml index 7738eb9b74..5862f67c7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ serde = { version = "1.0.119", features = ["derive"] } serde_json = "1.0.61" url = "2.2.0" codec = { package = "parity-scale-codec", version = "1.3.6", default-features = false, features = ["derive", "full"] } +dyn-clone = "1.0.4" frame-metadata = "12.0.1" frame-support = "2.0.1" diff --git a/examples/transfer_subscribe.rs b/examples/transfer_subscribe.rs index 706d3fdc6f..82cccd6f1a 100644 --- a/examples/transfer_subscribe.rs +++ b/examples/transfer_subscribe.rs @@ -24,6 +24,7 @@ use substrate_subxt::{ sp_core::Decode, ClientBuilder, DefaultNodeRuntime, + EventBytesSegmenter, EventSubscription, EventsDecoder, PairSigner, @@ -38,7 +39,10 @@ async fn main() -> Result<(), Box> { let client = ClientBuilder::::new().build().await?; let sub = client.subscribe_events().await?; - let mut decoder = EventsDecoder::::new(client.metadata().clone()); + let mut decoder = EventsDecoder::::new( + client.metadata().clone(), + EventBytesSegmenter::new(), + ); decoder.with_balances(); let mut sub = EventSubscription::::new(sub, decoder); sub.filter_event::>(); diff --git a/src/events.rs b/src/events.rs index 3e6371ded0..2d2e80e0d9 100644 --- a/src/events.rs +++ b/src/events.rs @@ -22,6 +22,7 @@ use codec::{ Input, Output, }; +use dyn_clone::DynClone; use frame_support::dispatch::DispatchInfo; use sp_runtime::{ DispatchError, @@ -72,16 +73,18 @@ impl std::fmt::Debug for RawEvent { } } -trait TypeSegmenter: Send { +trait TypeSegmenter: DynClone + Send + Sync { /// Consumes an object from an input stream, and output the serialized bytes. fn segment(&self, input: &mut &[u8], output: &mut Vec) -> Result<(), Error>; } -#[derive(Default)] +// derive object safe Clone impl for `Box` +dyn_clone::clone_trait_object!(TypeSegmenter); + struct TypeMarker(PhantomData); impl TypeSegmenter for TypeMarker where - T: Codec + Send, + T: Codec + Send + Sync, { fn segment(&self, input: &mut &[u8], output: &mut Vec) -> Result<(), Error> { T::decode(input).map_err(Error::from)?.encode_to(output); @@ -89,17 +92,114 @@ where } } +impl Clone for TypeMarker { + fn clone(&self) -> Self { + Self(Default::default()) + } +} + +impl Default for TypeMarker { + fn default() -> Self { + Self(Default::default()) + } +} + /// Events decoder. +#[derive(Debug)] pub struct EventsDecoder { metadata: Metadata, + event_segmenter: EventBytesSegmenter, + marker: PhantomData T>, +} + +impl EventsDecoder { + /// Creates a new `EventsDecoder`. + pub fn new(metadata: Metadata, event_segmenter: EventBytesSegmenter) -> Self { + Self { + metadata, + event_segmenter, + marker: PhantomData, + } + } + + /// Register a type. + pub fn register_type_size(&mut self, name: &str) + where + U: Codec + Send + Sync + 'static, + { + self.event_segmenter.register_type_size::(name) + } + + /// Decode events. + pub fn decode_events(&self, input: &mut &[u8]) -> Result, Error> { + let compact_len = >::decode(input)?; + let len = compact_len.0 as usize; + + let mut r = Vec::new(); + for _ in 0..len { + // decode EventRecord + let phase = Phase::decode(input)?; + let module_variant = input.read_byte()?; + + let module = self.metadata.module_with_events(module_variant)?; + let event_variant = input.read_byte()?; + let event_metadata = module.event(event_variant)?; + + log::debug!( + "received event '{}::{}' ({:?})", + module.name(), + event_metadata.name, + event_metadata.arguments() + ); + + let mut event_data = Vec::::new(); + let mut event_errors = Vec::::new(); + let result = self.event_segmenter.decode_raw_bytes( + &self.metadata, + &event_metadata.arguments(), + input, + &mut event_data, + &mut event_errors, + ); + let raw = match result { + Ok(()) => { + log::debug!("raw bytes: {}", hex::encode(&event_data),); + + let event = RawEvent { + module: module.name().to_string(), + variant: event_metadata.name.clone(), + data: event_data, + }; + + // topics come after the event data in EventRecord + let _topics = Vec::::decode(input)?; + Raw::Event(event) + } + Err(err) => return Err(err), + }; + + if event_errors.len() == 0 { + r.push((phase.clone(), raw)); + } + + for err in event_errors { + r.push((phase.clone(), Raw::Error(err))); + } + } + Ok(r) + } +} + +/// Consumes the raw bytes for an Event from a SCALE encoded sequence of Events +#[derive(Default)] +pub struct EventBytesSegmenter { type_segmenters: HashMap>, marker: PhantomData T>, } -impl fmt::Debug for EventsDecoder { +impl fmt::Debug for EventBytesSegmenter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EventsDecoder") - .field("metadata", &self.metadata) + f.debug_struct("EventBytesSegmenter") .field( "type_segmenters", &self.type_segmenters.keys().cloned().collect::(), @@ -108,58 +208,64 @@ impl fmt::Debug for EventsDecoder { } } -impl EventsDecoder { - /// Creates a new `EventsDecoder`. - pub fn new(metadata: Metadata) -> Self { - let mut decoder = Self { - metadata, - type_segmenters: HashMap::new(), +impl Clone for EventBytesSegmenter { + fn clone(&self) -> Self { + Self { + type_segmenters: self.type_segmenters.clone(), + marker: Default::default(), + } + } +} + +impl EventBytesSegmenter { + /// Create a new [`EventBytesSegmenter`], initializing some default types. + pub fn new() -> Self { + let mut segmenter = Self { + type_segmenters: Default::default(), marker: PhantomData, }; // register default event arg type sizes for dynamic decoding of events - decoder.register_type_size::<()>("PhantomData"); - decoder.register_type_size::("DispatchInfo"); - decoder.register_type_size::("bool"); - decoder.register_type_size::("ReferendumIndex"); - decoder.register_type_size::<[u8; 16]>("Kind"); - decoder.register_type_size::<[u8; 32]>("AuthorityId"); - decoder.register_type_size::("u8"); - decoder.register_type_size::("u32"); - decoder.register_type_size::("u64"); - decoder.register_type_size::("u128"); - decoder.register_type_size::("AccountIndex"); - decoder.register_type_size::("SessionIndex"); - decoder.register_type_size::("PropIndex"); - decoder.register_type_size::("ProposalIndex"); - decoder.register_type_size::("AuthorityIndex"); - decoder.register_type_size::("AuthorityWeight"); - decoder.register_type_size::("MemberCount"); - decoder.register_type_size::("AccountId"); - decoder.register_type_size::("BlockNumber"); - decoder.register_type_size::("Hash"); - decoder.register_type_size::("VoteThreshold"); + segmenter.register_type_size::<()>("PhantomData"); + segmenter.register_type_size::("DispatchInfo"); + segmenter.register_type_size::("bool"); + segmenter.register_type_size::("ReferendumIndex"); + segmenter.register_type_size::<[u8; 16]>("Kind"); + segmenter.register_type_size::<[u8; 32]>("AuthorityId"); + segmenter.register_type_size::("u8"); + segmenter.register_type_size::("u32"); + segmenter.register_type_size::("u64"); + segmenter.register_type_size::("u128"); + segmenter.register_type_size::("AccountIndex"); + segmenter.register_type_size::("SessionIndex"); + segmenter.register_type_size::("PropIndex"); + segmenter.register_type_size::("ProposalIndex"); + segmenter.register_type_size::("AuthorityIndex"); + segmenter.register_type_size::("AuthorityWeight"); + segmenter.register_type_size::("MemberCount"); + segmenter.register_type_size::("AccountId"); + segmenter.register_type_size::("BlockNumber"); + segmenter.register_type_size::("Hash"); + segmenter.register_type_size::("VoteThreshold"); // Additional types - decoder.register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); - decoder + segmenter.register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); + segmenter } /// Register a type. - pub fn register_type_size(&mut self, name: &str) -> usize + pub fn register_type_size(&mut self, name: &str) where - U: Default + Codec + Send + 'static, + U: Codec + Send + Sync + 'static, { - let size = U::default().encode().len(); // A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized // type to the output stream (&mut Vec). self.type_segmenters .insert(name.to_string(), Box::new(TypeMarker::::default())); - size } /// Check missing type sizes. - pub fn check_missing_type_sizes(&self) { + pub fn check_missing_type_sizes(&self, metadata: &Metadata) { let mut missing = HashSet::new(); - for module in self.metadata.modules_with_events() { + for module in metadata.modules_with_events() { for event in module.events() { for arg in event.arguments() { for primitive in arg.primitives() { @@ -186,6 +292,7 @@ impl EventsDecoder { fn decode_raw_bytes( &self, + metadata: &Metadata, args: &[EventArg], input: &mut &[u8], output: &mut W, @@ -197,7 +304,13 @@ impl EventsDecoder { let len = >::decode(input)?; len.encode_to(output); for _ in 0..len.0 { - self.decode_raw_bytes(&[*arg.clone()], input, output, errors)? + self.decode_raw_bytes( + metadata, + &[*arg.clone()], + input, + output, + errors, + )? } } EventArg::Option(arg) => { @@ -205,7 +318,13 @@ impl EventsDecoder { 0 => output.push_byte(0), 1 => { output.push_byte(1); - self.decode_raw_bytes(&[*arg.clone()], input, output, errors)? + self.decode_raw_bytes( + metadata, + &[*arg.clone()], + input, + output, + errors, + )? } _ => { return Err(Error::Other( @@ -215,7 +334,7 @@ impl EventsDecoder { } } EventArg::Tuple(args) => { - self.decode_raw_bytes(args, input, output, errors)? + self.decode_raw_bytes(metadata, args, input, output, errors)? } EventArg::Primitive(name) => { let result = match name.as_str() { @@ -235,71 +354,13 @@ impl EventsDecoder { if let Err(error) = result { // since the input may contain any number of args we propagate // runtime errors to the caller for handling - errors.push(RuntimeError::from_dispatch(&self.metadata, error)?); + errors.push(RuntimeError::from_dispatch(&metadata, error)?); } } } } Ok(()) } - - /// Decode events. - pub fn decode_events(&self, input: &mut &[u8]) -> Result, Error> { - let compact_len = >::decode(input)?; - let len = compact_len.0 as usize; - - let mut r = Vec::new(); - for _ in 0..len { - // decode EventRecord - let phase = Phase::decode(input)?; - let module_variant = input.read_byte()?; - - let module = self.metadata.module_with_events(module_variant)?; - let event_variant = input.read_byte()?; - let event_metadata = module.event(event_variant)?; - - log::debug!( - "received event '{}::{}' ({:?})", - module.name(), - event_metadata.name, - event_metadata.arguments() - ); - - let mut event_data = Vec::::new(); - let mut event_errors = Vec::::new(); - let result = self.decode_raw_bytes( - &event_metadata.arguments(), - input, - &mut event_data, - &mut event_errors, - ); - let raw = match result { - Ok(()) => { - log::debug!("raw bytes: {}", hex::encode(&event_data),); - - let event = RawEvent { - module: module.name().to_string(), - variant: event_metadata.name.clone(), - data: event_data, - }; - - // topics come after the event data in EventRecord - let _topics = Vec::::decode(input)?; - Raw::Event(event) - } - Err(err) => return Err(err), - }; - - if event_errors.len() == 0 { - r.push((phase.clone(), raw)); - } - - for err in event_errors { - r.push((phase.clone(), Raw::Error(err))); - } - } - Ok(r) - } } /// Raw event or error event @@ -331,15 +392,16 @@ mod tests { #[test] fn test_decode_option() { - let decoder = EventsDecoder::::new(Metadata::default()); + let segmenter = EventBytesSegmenter::::new(); let value = Some(0u8); let input = value.encode(); let mut output = Vec::::new(); let mut errors = Vec::::new(); - decoder + segmenter .decode_raw_bytes( + &Metadata::default(), &[EventArg::Option(Box::new(EventArg::Primitive( "u8".to_string(), )))], @@ -419,6 +481,7 @@ mod tests { }), )) .unwrap(), + EventBytesSegmenter::new(), ); // [(ApplyExtrinsic(0), Event(RawEvent { module: "System", variant: "ExtrinsicSuccess", data: "482d7c09000000000200" })), (ApplyExtrinsic(1), Error(Module(ModuleError { module: "System", error: "NonDefaultComposite" }))), (ApplyExtrinsic(2), Error(Module(ModuleError { module: "System", error: "NonDefaultComposite" })))] diff --git a/src/frame/balances.rs b/src/frame/balances.rs index 4d9a331bf8..321b4061e2 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -170,6 +170,7 @@ mod tests { test_client, TestRuntime, }, + EventBytesSegmenter, }; use sp_core::{ sr25519::Pair, @@ -297,7 +298,9 @@ mod tests { let bob = AccountKeyring::Bob.to_account_id(); let (client, _) = test_client().await; let sub = client.subscribe_events().await.unwrap(); - let mut decoder = EventsDecoder::::new(client.metadata().clone()); + let event_segmenter = EventBytesSegmenter::new(); + let mut decoder = + EventsDecoder::::new(client.metadata().clone(), event_segmenter); decoder.with_balances(); let mut sub = EventSubscription::::new(sub, decoder); sub.filter_event::>(); diff --git a/src/lib.rs b/src/lib.rs index e2a7ccf4e9..caa31f099c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,10 @@ pub use substrate_subxt_client as client; pub use sp_core; pub use sp_runtime; -use codec::Decode; +use codec::{ + Codec, + Decode, +}; use futures::future; use jsonrpsee::client::Subscription; use sp_core::{ @@ -76,6 +79,7 @@ mod subscription; pub use crate::{ error::Error, events::{ + EventBytesSegmenter, EventsDecoder, RawEvent, }, @@ -119,6 +123,7 @@ pub struct ClientBuilder { url: Option, client: Option, page_size: Option, + event_segmenter: EventBytesSegmenter, } impl ClientBuilder { @@ -129,6 +134,7 @@ impl ClientBuilder { url: None, client: None, page_size: None, + event_segmenter: EventBytesSegmenter::new(), } } @@ -150,6 +156,15 @@ impl ClientBuilder { self } + /// Register a custom type segmenter, for consuming types in events where the size cannot + /// be inferred from the metadata. + pub fn register_type_size(mut self, name: &str) + where + U: Codec + Send + Sync + 'static, + { + self.event_segmenter.register_type_size::(name) + } + /// Creates a new Client. pub async fn build(self) -> Result, Error> { let client = if let Some(client) = self.client { @@ -174,6 +189,7 @@ impl ClientBuilder { rpc, genesis_hash: genesis_hash?, metadata: metadata?, + event_segmenter: self.event_segmenter, properties: properties.unwrap_or_else(|_| Default::default()), runtime_version: runtime_version?, _marker: PhantomData, @@ -187,6 +203,7 @@ pub struct Client { rpc: Rpc, genesis_hash: T::Hash, metadata: Metadata, + event_segmenter: EventBytesSegmenter, properties: SystemProperties, runtime_version: RuntimeVersion, _marker: PhantomData<(fn() -> T::Signature, T::Extra)>, @@ -199,6 +216,7 @@ impl Clone for Client { rpc: self.rpc.clone(), genesis_hash: self.genesis_hash, metadata: self.metadata.clone(), + event_segmenter: self.event_segmenter.clone(), properties: self.properties.clone(), runtime_version: self.runtime_version.clone(), _marker: PhantomData, @@ -469,7 +487,8 @@ impl Client { /// Returns an events decoder for a call. pub fn events_decoder>(&self) -> EventsDecoder { let metadata = self.metadata().clone(); - let mut decoder = EventsDecoder::new(metadata); + let segmenter = self.event_segmenter.clone(); + let mut decoder = EventsDecoder::new(metadata, segmenter); C::events_decoder(&mut decoder); decoder } From ea5a9ded7da7b6d910ea44e7c7cc6ab89dfe386b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 08:13:28 +0000 Subject: [PATCH 02/18] Perform type sizes check when building client --- src/error.rs | 7 +++++++ src/events.rs | 11 +++++------ src/lib.rs | 31 ++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index 195a2d22da..56262aa29e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -57,6 +57,13 @@ pub enum Error { /// Metadata error. #[error("Metadata error: {0}")] Metadata(#[from] MetadataError), + /// Unregistered type sizes. + #[error( + "The following types do not have a type size registered: \ + {0:?} \ + Use `ClientBuilder::register_type_size` to register missing type sizes." + )] + MissingTypeSizes(Vec), /// Type size unavailable. #[error("Type size unavailable while decoding event: {0:?}")] TypeSizeUnavailable(String), diff --git a/src/events.rs b/src/events.rs index 2d2e80e0d9..59b7a84feb 100644 --- a/src/events.rs +++ b/src/events.rs @@ -263,7 +263,7 @@ impl EventBytesSegmenter { } /// Check missing type sizes. - pub fn check_missing_type_sizes(&self, metadata: &Metadata) { + pub fn check_missing_type_sizes(&self, metadata: &Metadata) -> Result<(), HashSet> { let mut missing = HashSet::new(); for module in metadata.modules_with_events() { for event in module.events() { @@ -281,12 +281,11 @@ impl EventBytesSegmenter { } } } + if !missing.is_empty() { - log::warn!( - "The following primitive types do not have registered sizes: {:?} \ - If any of these events are received, an error will occur since we cannot decode them", - missing - ); + Err(missing) + } else { + Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index caa31f099c..e8a474b883 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,6 +124,7 @@ pub struct ClientBuilder { client: Option, page_size: Option, event_segmenter: EventBytesSegmenter, + skip_type_sizes_check: bool, } impl ClientBuilder { @@ -135,6 +136,7 @@ impl ClientBuilder { client: None, page_size: None, event_segmenter: EventBytesSegmenter::new(), + skip_type_sizes_check: false, } } @@ -165,6 +167,14 @@ impl ClientBuilder { self.event_segmenter.register_type_size::(name) } + /// Disable the check for missing type sizes on `build`. + /// + /// *WARNING* can lead to runtime errors if receiving events with unknown types. + pub fn skip_type_sizes_check(mut self) -> Self { + self.skip_type_sizes_check = false; + self + } + /// Creates a new Client. pub async fn build(self) -> Result, Error> { let client = if let Some(client) = self.client { @@ -185,10 +195,28 @@ impl ClientBuilder { rpc.system_properties(), ) .await; + let metadata = metadata?; + + if let Err(missing) = self.event_segmenter.check_missing_type_sizes(&metadata) { + if self.skip_type_sizes_check { + log::warn!( + "The following types do not have registered type segmenters: {:?} \ + If any events containing these types are received, this can cause a \ + `TypeSizeUnavailable` error and prevent decoding the actual event \ + being listened for.\ + \ + Use `ClientBuilder::register_type_size` to register missing type sizes.", + missing + ); + } else { + return Err(Error::MissingTypeSizes(missing.into_iter().collect())) + } + } + Ok(Client { rpc, genesis_hash: genesis_hash?, - metadata: metadata?, + metadata, event_segmenter: self.event_segmenter, properties: properties.unwrap_or_else(|_| Default::default()), runtime_version: runtime_version?, @@ -591,6 +619,7 @@ impl codec::Encode for Encoded { #[cfg(test)] mod tests { use super::*; + use crate::balances::*; use sp_core::storage::{ well_known_keys, StorageKey, From 8ac2e59d8530c9b4a69c5a53546675166ab0fdca Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 16:01:48 +0000 Subject: [PATCH 03/18] Introduce EventTypeRegistry for global runtime type sizes --- examples/transfer_subscribe.rs | 25 +--- proc-macro/src/call.rs | 14 -- proc-macro/src/module.rs | 16 +-- proc-macro/tests/balances.rs | 2 +- src/events.rs | 226 +++++++++++++++------------------ src/frame/balances.rs | 39 ++---- src/frame/contracts.rs | 4 +- src/frame/mod.rs | 3 - src/frame/session.rs | 4 +- src/frame/staking.rs | 2 +- src/frame/sudo.rs | 2 +- src/lib.rs | 39 +++--- src/rpc.rs | 6 +- src/runtimes.rs | 107 +++++++++++++--- src/subscription.rs | 8 +- 15 files changed, 249 insertions(+), 248 deletions(-) diff --git a/examples/transfer_subscribe.rs b/examples/transfer_subscribe.rs index 82cccd6f1a..d3d7b62e45 100644 --- a/examples/transfer_subscribe.rs +++ b/examples/transfer_subscribe.rs @@ -15,20 +15,11 @@ // along with substrate-subxt. If not, see . use sp_keyring::AccountKeyring; -use substrate_subxt::{ - balances::{ - BalancesEventsDecoder, - TransferCallExt, - TransferEvent, - }, - sp_core::Decode, - ClientBuilder, - DefaultNodeRuntime, - EventBytesSegmenter, - EventSubscription, - EventsDecoder, - PairSigner, -}; +use substrate_subxt::{balances::{ + BalancesEventTypeRegistry, + TransferCallExt, + TransferEvent, +}, sp_core::Decode, ClientBuilder, DefaultNodeRuntime, EventSubscription, PairSigner}; #[async_std::main] async fn main() -> Result<(), Box> { @@ -39,11 +30,7 @@ async fn main() -> Result<(), Box> { let client = ClientBuilder::::new().build().await?; let sub = client.subscribe_events().await?; - let mut decoder = EventsDecoder::::new( - client.metadata().clone(), - EventBytesSegmenter::new(), - ); - decoder.with_balances(); + let decoder = client.events_decoder(); let mut sub = EventSubscription::::new(sub, decoder); sub.filter_event::>(); client.transfer(&signer, &dest, 10_000).await?; diff --git a/proc-macro/src/call.rs b/proc-macro/src/call.rs index cedf993fe0..de44baa8c0 100644 --- a/proc-macro/src/call.rs +++ b/proc-macro/src/call.rs @@ -32,10 +32,6 @@ pub fn call(s: Structure) -> TokenStream { let generics = &s.ast().generics; let params = utils::type_params(generics); let module = utils::module_name(generics); - let with_module = format_ident!( - "with_{}", - utils::path_to_ident(module).to_string().to_snake_case() - ); let call_name = utils::ident_to_name(ident, "Call").to_snake_case(); let bindings = utils::bindings(&s); let fields = utils::fields(&bindings); @@ -51,11 +47,6 @@ pub fn call(s: Structure) -> TokenStream { impl#generics #subxt::Call for #ident<#(#params),*> { const MODULE: &'static str = MODULE; const FUNCTION: &'static str = #call_name; - fn events_decoder( - decoder: &mut #subxt::EventsDecoder, - ) { - decoder.#with_module(); - } } /// Call extension trait. @@ -118,11 +109,6 @@ mod tests { impl<'a, T: Balances> substrate_subxt::Call for TransferCall<'a, T> { const MODULE: &'static str = MODULE; const FUNCTION: &'static str = "transfer"; - fn events_decoder( - decoder: &mut substrate_subxt::EventsDecoder, - ) { - decoder.with_balances(); - } } /// Call extension trait. diff --git a/proc-macro/src/module.rs b/proc-macro/src/module.rs index 533563204e..95f43d5328 100644 --- a/proc-macro/src/module.rs +++ b/proc-macro/src/module.rs @@ -62,8 +62,8 @@ fn ignore(attrs: &[syn::Attribute]) -> bool { false } -fn events_decoder_trait_name(module: &syn::Ident) -> syn::Ident { - format_ident!("{}EventsDecoder", module.to_string()) +fn event_type_registry_trait_name(module: &syn::Ident) -> syn::Ident { + format_ident!("{}EventTypeRegistry", module.to_string()) } fn with_module_ident(module: &syn::Ident) -> syn::Ident { @@ -128,7 +128,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream { let subxt = utils::use_crate("substrate-subxt"); let module = &input.ident; let module_name = module.to_string(); - let module_events_decoder = events_decoder_trait_name(module); + let module_events_type_registry = event_type_registry_trait_name(module); let with_module = with_module_ident(module); let bounds = input.supertraits.iter().filter_map(|bound| { @@ -169,13 +169,13 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream { const MODULE: &str = #module_name; /// `EventsDecoder` extension trait. - pub trait #module_events_decoder { + pub trait #module_events_type_registry { /// Registers this modules types. fn #with_module(&mut self); } - impl #module_events_decoder for - #subxt::EventsDecoder + impl #module_events_type_registry for + #subxt::EventTypeRegistry { fn #with_module(&mut self) { #(#bounds)* @@ -222,12 +222,12 @@ mod tests { const MODULE: &str = "Balances"; /// `EventsDecoder` extension trait. - pub trait BalancesEventsDecoder { + pub trait BalancesEventTypeRegistry { /// Registers this modules types. fn with_balances(&mut self); } - impl BalancesEventsDecoder for + impl BalancesEventTypeRegistry for substrate_subxt::EventsDecoder { fn with_balances(&mut self) { diff --git a/proc-macro/tests/balances.rs b/proc-macro/tests/balances.rs index 0f167e9803..29017337f6 100644 --- a/proc-macro/tests/balances.rs +++ b/proc-macro/tests/balances.rs @@ -32,7 +32,7 @@ use substrate_subxt::{ }, system::{ System, - SystemEventsDecoder, + SystemEventTypeRegistry, }, ClientBuilder, KusamaRuntime, diff --git a/src/events.rs b/src/events.rs index 59b7a84feb..4902a11cfe 100644 --- a/src/events.rs +++ b/src/events.rs @@ -23,7 +23,6 @@ use codec::{ Output, }; use dyn_clone::DynClone; -use frame_support::dispatch::DispatchInfo; use sp_runtime::{ DispatchError, DispatchResult, @@ -73,7 +72,7 @@ impl std::fmt::Debug for RawEvent { } } -trait TypeSegmenter: DynClone + Send + Sync { +pub trait TypeSegmenter: DynClone + Send + Sync { /// Consumes an object from an input stream, and output the serialized bytes. fn segment(&self, input: &mut &[u8], output: &mut Vec) -> Result<(), Error>; } @@ -108,28 +107,27 @@ impl Default for TypeMarker { #[derive(Debug)] pub struct EventsDecoder { metadata: Metadata, - event_segmenter: EventBytesSegmenter, - marker: PhantomData T>, + event_type_registry: EventTypeRegistry, +} + +impl Clone for EventsDecoder { + fn clone(&self) -> Self { + Self { + metadata: self.metadata.clone(), + event_type_registry: self.event_type_registry.clone(), + } + } } impl EventsDecoder { /// Creates a new `EventsDecoder`. - pub fn new(metadata: Metadata, event_segmenter: EventBytesSegmenter) -> Self { + pub fn new(metadata: Metadata, event_type_registry: EventTypeRegistry) -> Self { Self { metadata, - event_segmenter, - marker: PhantomData, + event_type_registry, } } - /// Register a type. - pub fn register_type_size(&mut self, name: &str) - where - U: Codec + Send + Sync + 'static, - { - self.event_segmenter.register_type_size::(name) - } - /// Decode events. pub fn decode_events(&self, input: &mut &[u8]) -> Result, Error> { let compact_len = >::decode(input)?; @@ -154,8 +152,7 @@ impl EventsDecoder { let mut event_data = Vec::::new(); let mut event_errors = Vec::::new(); - let result = self.event_segmenter.decode_raw_bytes( - &self.metadata, + let result = self.decode_raw_bytes( &event_metadata.arguments(), input, &mut event_data, @@ -188,110 +185,9 @@ impl EventsDecoder { } Ok(r) } -} - -/// Consumes the raw bytes for an Event from a SCALE encoded sequence of Events -#[derive(Default)] -pub struct EventBytesSegmenter { - type_segmenters: HashMap>, - marker: PhantomData T>, -} - -impl fmt::Debug for EventBytesSegmenter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EventBytesSegmenter") - .field( - "type_segmenters", - &self.type_segmenters.keys().cloned().collect::(), - ) - .finish() - } -} - -impl Clone for EventBytesSegmenter { - fn clone(&self) -> Self { - Self { - type_segmenters: self.type_segmenters.clone(), - marker: Default::default(), - } - } -} - -impl EventBytesSegmenter { - /// Create a new [`EventBytesSegmenter`], initializing some default types. - pub fn new() -> Self { - let mut segmenter = Self { - type_segmenters: Default::default(), - marker: PhantomData, - }; - // register default event arg type sizes for dynamic decoding of events - segmenter.register_type_size::<()>("PhantomData"); - segmenter.register_type_size::("DispatchInfo"); - segmenter.register_type_size::("bool"); - segmenter.register_type_size::("ReferendumIndex"); - segmenter.register_type_size::<[u8; 16]>("Kind"); - segmenter.register_type_size::<[u8; 32]>("AuthorityId"); - segmenter.register_type_size::("u8"); - segmenter.register_type_size::("u32"); - segmenter.register_type_size::("u64"); - segmenter.register_type_size::("u128"); - segmenter.register_type_size::("AccountIndex"); - segmenter.register_type_size::("SessionIndex"); - segmenter.register_type_size::("PropIndex"); - segmenter.register_type_size::("ProposalIndex"); - segmenter.register_type_size::("AuthorityIndex"); - segmenter.register_type_size::("AuthorityWeight"); - segmenter.register_type_size::("MemberCount"); - segmenter.register_type_size::("AccountId"); - segmenter.register_type_size::("BlockNumber"); - segmenter.register_type_size::("Hash"); - segmenter.register_type_size::("VoteThreshold"); - // Additional types - segmenter.register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); - segmenter - } - - /// Register a type. - pub fn register_type_size(&mut self, name: &str) - where - U: Codec + Send + Sync + 'static, - { - // A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized - // type to the output stream (&mut Vec). - self.type_segmenters - .insert(name.to_string(), Box::new(TypeMarker::::default())); - } - - /// Check missing type sizes. - pub fn check_missing_type_sizes(&self, metadata: &Metadata) -> Result<(), HashSet> { - let mut missing = HashSet::new(); - for module in metadata.modules_with_events() { - for event in module.events() { - for arg in event.arguments() { - for primitive in arg.primitives() { - if !self.type_segmenters.contains_key(&primitive) { - missing.insert(format!( - "{}::{}::{}", - module.name(), - event.name, - primitive - )); - } - } - } - } - } - - if !missing.is_empty() { - Err(missing) - } else { - Ok(()) - } - } fn decode_raw_bytes( &self, - metadata: &Metadata, args: &[EventArg], input: &mut &[u8], output: &mut W, @@ -304,7 +200,6 @@ impl EventBytesSegmenter { len.encode_to(output); for _ in 0..len.0 { self.decode_raw_bytes( - metadata, &[*arg.clone()], input, output, @@ -318,7 +213,6 @@ impl EventBytesSegmenter { 1 => { output.push_byte(1); self.decode_raw_bytes( - metadata, &[*arg.clone()], input, output, @@ -333,14 +227,14 @@ impl EventBytesSegmenter { } } EventArg::Tuple(args) => { - self.decode_raw_bytes(metadata, args, input, output, errors)? + self.decode_raw_bytes(args, input, output, errors)? } EventArg::Primitive(name) => { let result = match name.as_str() { "DispatchResult" => DispatchResult::decode(input)?, "DispatchError" => Err(DispatchError::decode(input)?), _ => { - if let Some(seg) = self.type_segmenters.get(name) { + if let Some(seg) = self.event_type_registry.resolve(name) { let mut buf = Vec::::new(); seg.segment(input, &mut buf)?; output.write(&buf); @@ -353,7 +247,7 @@ impl EventBytesSegmenter { if let Err(error) = result { // since the input may contain any number of args we propagate // runtime errors to the caller for handling - errors.push(RuntimeError::from_dispatch(&metadata, error)?); + errors.push(RuntimeError::from_dispatch(&self.metadata, error)?); } } } @@ -362,6 +256,85 @@ impl EventBytesSegmenter { } } +/// Registry for event types which cannot be directly inferred from the metadata. +#[derive(Default)] +pub struct EventTypeRegistry { + segmenters: HashMap>, + marker: PhantomData T>, +} + +impl Clone for EventTypeRegistry { + fn clone(&self) -> Self { + Self { + segmenters: self.segmenters.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for EventTypeRegistry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EventTypeRegistry") + .field("segmenters", + &self.segmenters.keys().cloned().collect::(), + ) + .finish() + } +} + +impl EventTypeRegistry { + /// Create a new [`EventTypeRegistry`]. + pub fn new() -> Self { + Self { + segmenters: HashMap::new(), + marker: PhantomData, + } + } + + /// Register a type. + pub fn register_type_size(&mut self, name: &str) + where + U: Codec + Send + Sync + 'static, + { + // A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized + // type to the output stream (&mut Vec). + self.segmenters + .insert(name.to_string(), Box::new(TypeMarker::::default())); + } + + /// Check missing type sizes. + pub fn check_missing_type_sizes(&self, metadata: &Metadata) -> Result<(), HashSet> { + let mut missing = HashSet::new(); + for module in metadata.modules_with_events() { + for event in module.events() { + for arg in event.arguments() { + for primitive in arg.primitives() { + if !self.segmenters.contains_key(&primitive) { + missing.insert(format!( + "{}::{}::{}", + module.name(), + event.name, + primitive + )); + } + } + } + } + } + + if !missing.is_empty() { + Err(missing) + } else { + Ok(()) + } + } + + /// Resolve a segmenter for a type by its name. + pub fn resolve(&self, name: &str) -> Option<&Box> { + self.segmenters.get(name) + } +} + /// Raw event or error event #[derive(Debug)] pub enum Raw { @@ -391,16 +364,15 @@ mod tests { #[test] fn test_decode_option() { - let segmenter = EventBytesSegmenter::::new(); + let decoder = EventsDecoder::::new(Metadata::default(), EventTypeRegistry::new()); let value = Some(0u8); let input = value.encode(); let mut output = Vec::::new(); let mut errors = Vec::::new(); - segmenter + decoder .decode_raw_bytes( - &Metadata::default(), &[EventArg::Option(Box::new(EventArg::Primitive( "u8".to_string(), )))], @@ -480,7 +452,7 @@ mod tests { }), )) .unwrap(), - EventBytesSegmenter::new(), + EventTypeRegistry::new(), ); // [(ApplyExtrinsic(0), Event(RawEvent { module: "System", variant: "ExtrinsicSuccess", data: "482d7c09000000000200" })), (ApplyExtrinsic(1), Error(Module(ModuleError { module: "System", error: "NonDefaultComposite" }))), (ApplyExtrinsic(2), Error(Module(ModuleError { module: "System", error: "NonDefaultComposite" })))] diff --git a/src/frame/balances.rs b/src/frame/balances.rs index 321b4061e2..5a3cd18720 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -18,7 +18,7 @@ use crate::frame::system::{ System, - SystemEventsDecoder, + SystemEventTypeRegistry, }; use codec::{ Decode, @@ -153,25 +153,17 @@ pub struct TransferEvent { #[cfg(test)] mod tests { use super::*; - use crate::{ - error::{ - Error, - ModuleError, - RuntimeError, - }, - events::EventsDecoder, - extrinsic::{ - PairSigner, - Signer, - }, - subscription::EventSubscription, - system::AccountStoreExt, - tests::{ - test_client, - TestRuntime, - }, - EventBytesSegmenter, - }; + use crate::{error::{ + Error, + ModuleError, + RuntimeError, + }, extrinsic::{ + PairSigner, + Signer, + }, subscription::EventSubscription, system::AccountStoreExt, tests::{ + test_client, + TestRuntime, + }}; use sp_core::{ sr25519::Pair, Pair as _, @@ -298,11 +290,8 @@ mod tests { let bob = AccountKeyring::Bob.to_account_id(); let (client, _) = test_client().await; let sub = client.subscribe_events().await.unwrap(); - let event_segmenter = EventBytesSegmenter::new(); - let mut decoder = - EventsDecoder::::new(client.metadata().clone(), event_segmenter); - decoder.with_balances(); - let mut sub = EventSubscription::::new(sub, decoder); + let decoder = client.events_decoder(); + let mut sub = EventSubscription::::new(sub, &decoder); sub.filter_event::>(); client.transfer(&alice, &bob, 10_000).await.unwrap(); let raw = sub.next().await.unwrap().unwrap(); diff --git a/src/frame/contracts.rs b/src/frame/contracts.rs index 0b3a1d72ed..aa6199fa79 100644 --- a/src/frame/contracts.rs +++ b/src/frame/contracts.rs @@ -19,11 +19,11 @@ use crate::frame::{ balances::{ Balances, - BalancesEventsDecoder, + BalancesEventTypeRegistry, }, system::{ System, - SystemEventsDecoder, + SystemEventTypeRegistry, }, }; use codec::{ diff --git a/src/frame/mod.rs b/src/frame/mod.rs index 4a06b510d7..85332124e1 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -17,7 +17,6 @@ //! Implements support for built-in runtime modules. use crate::{ - events::EventsDecoder, metadata::{ Metadata, MetadataError, @@ -63,8 +62,6 @@ pub trait Call: Encode { const MODULE: &'static str; /// Function name. const FUNCTION: &'static str; - /// Load event decoder. - fn events_decoder(_decoder: &mut EventsDecoder) {} } /// Event trait. diff --git a/src/frame/session.rs b/src/frame/session.rs index 3a17c0bb68..e9b32bd0f4 100644 --- a/src/frame/session.rs +++ b/src/frame/session.rs @@ -18,11 +18,11 @@ use crate::frame::{ balances::{ Balances, - BalancesEventsDecoder as _, + BalancesEventTypeRegistry as _, }, system::{ System, - SystemEventsDecoder as _, + SystemEventTypeRegistry as _, }, }; use codec::Encode; diff --git a/src/frame/staking.rs b/src/frame/staking.rs index 7d96392144..f783f00183 100644 --- a/src/frame/staking.rs +++ b/src/frame/staking.rs @@ -18,7 +18,7 @@ use super::balances::{ Balances, - BalancesEventsDecoder as _, + BalancesEventTypeRegistry as _, }; use codec::{ Decode, diff --git a/src/frame/sudo.rs b/src/frame/sudo.rs index 47214b7b85..21206480c2 100644 --- a/src/frame/sudo.rs +++ b/src/frame/sudo.rs @@ -19,7 +19,7 @@ use crate::{ frame::system::{ System, - SystemEventsDecoder, + SystemEventTypeRegistry, }, Encoded, }; diff --git a/src/lib.rs b/src/lib.rs index e8a474b883..55eb1023d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,8 +79,8 @@ mod subscription; pub use crate::{ error::Error, events::{ - EventBytesSegmenter, EventsDecoder, + EventTypeRegistry, RawEvent, }, extrinsic::{ @@ -119,11 +119,10 @@ use crate::{ /// ClientBuilder for constructing a Client. #[derive(Default)] pub struct ClientBuilder { - _marker: std::marker::PhantomData, url: Option, client: Option, page_size: Option, - event_segmenter: EventBytesSegmenter, + event_type_registry: EventTypeRegistry, skip_type_sizes_check: bool, } @@ -131,11 +130,10 @@ impl ClientBuilder { /// Creates a new ClientBuilder. pub fn new() -> Self { Self { - _marker: std::marker::PhantomData, url: None, client: None, page_size: None, - event_segmenter: EventBytesSegmenter::new(), + event_type_registry: EventTypeRegistry::new(), skip_type_sizes_check: false, } } @@ -164,7 +162,7 @@ impl ClientBuilder { where U: Codec + Send + Sync + 'static, { - self.event_segmenter.register_type_size::(name) + self.event_type_registry.register_type_size::(name) } /// Disable the check for missing type sizes on `build`. @@ -176,7 +174,7 @@ impl ClientBuilder { } /// Creates a new Client. - pub async fn build(self) -> Result, Error> { + pub async fn build<'a>(self) -> Result, Error> { let client = if let Some(client) = self.client { client } else { @@ -197,7 +195,7 @@ impl ClientBuilder { .await; let metadata = metadata?; - if let Err(missing) = self.event_segmenter.check_missing_type_sizes(&metadata) { + if let Err(missing) = self.event_type_registry.check_missing_type_sizes(&metadata) { if self.skip_type_sizes_check { log::warn!( "The following types do not have registered type segmenters: {:?} \ @@ -213,11 +211,13 @@ impl ClientBuilder { } } + let events_decoder = EventsDecoder::new(metadata.clone(), self.event_type_registry); + Ok(Client { rpc, genesis_hash: genesis_hash?, metadata, - event_segmenter: self.event_segmenter, + events_decoder, properties: properties.unwrap_or_else(|_| Default::default()), runtime_version: runtime_version?, _marker: PhantomData, @@ -231,7 +231,7 @@ pub struct Client { rpc: Rpc, genesis_hash: T::Hash, metadata: Metadata, - event_segmenter: EventBytesSegmenter, + events_decoder: EventsDecoder, properties: SystemProperties, runtime_version: RuntimeVersion, _marker: PhantomData<(fn() -> T::Signature, T::Extra)>, @@ -244,7 +244,7 @@ impl Clone for Client { rpc: self.rpc.clone(), genesis_hash: self.genesis_hash, metadata: self.metadata.clone(), - event_segmenter: self.event_segmenter.clone(), + events_decoder: self.events_decoder.clone(), properties: self.properties.clone(), runtime_version: self.runtime_version.clone(), _marker: PhantomData, @@ -512,13 +512,9 @@ impl Client { Ok(signed) } - /// Returns an events decoder for a call. - pub fn events_decoder>(&self) -> EventsDecoder { - let metadata = self.metadata().clone(); - let segmenter = self.event_segmenter.clone(); - let mut decoder = EventsDecoder::new(metadata, segmenter); - C::events_decoder(&mut decoder); - decoder + /// Returns the events decoder. + pub fn events_decoder(&self) -> &EventsDecoder { + &self.events_decoder } /// Create and submit an extrinsic and return corresponding Hash if successful @@ -533,10 +529,9 @@ impl Client { pub async fn submit_and_watch_extrinsic( &self, extrinsic: UncheckedExtrinsic, - decoder: EventsDecoder, ) -> Result, Error> { self.rpc - .submit_and_watch_extrinsic(extrinsic, decoder) + .submit_and_watch_extrinsic(extrinsic, &self.events_decoder) .await } @@ -565,8 +560,7 @@ impl Client { Send + Sync, { let extrinsic = self.create_signed(call, signer).await?; - let decoder = self.events_decoder::(); - self.submit_and_watch_extrinsic(extrinsic, decoder).await + self.submit_and_watch_extrinsic(extrinsic).await } /// Insert a key into the keystore. @@ -619,7 +613,6 @@ impl codec::Encode for Encoded { #[cfg(test)] mod tests { use super::*; - use crate::balances::*; use sp_core::storage::{ well_known_keys, StorageKey, diff --git a/src/rpc.rs b/src/rpc.rs index c6607a0bf0..06f0c72c5d 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -423,10 +423,10 @@ impl Rpc { } /// Create and submit an extrinsic and return corresponding Event if successful - pub async fn submit_and_watch_extrinsic( + pub async fn submit_and_watch_extrinsic<'a, E: Encode + 'static>( &self, extrinsic: E, - decoder: EventsDecoder, + decoder: &'a EventsDecoder, ) -> Result, Error> { let ext_hash = T::Hashing::hash_of(&extrinsic); log::info!("Submitting Extrinsic `{:?}`", ext_hash); @@ -465,7 +465,7 @@ impl Rpc { ext_hash, )) })?; - let mut sub = EventSubscription::new(events_sub, decoder); + let mut sub = EventSubscription::new(events_sub, &decoder); sub.filter_extrinsic(block_hash, ext_index); let mut events = vec![]; while let Some(event) = sub.next().await { diff --git a/src/runtimes.rs b/src/runtimes.rs index 483cec2ccd..48bdc88090 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -138,23 +138,36 @@ impl_opaque_keys! { } } -use crate::{ - extrinsic::{ - DefaultExtra, - SignedExtra, +use crate::{extrinsic::{ + DefaultExtra, + SignedExtra, +}, frame::{ + balances::{ + AccountData, + Balances, + BalancesEventTypeRegistry, }, - frame::{ - balances::{ - AccountData, - Balances, - }, - contracts::Contracts, - session::Session, - staking::Staking, - sudo::Sudo, - system::System, + contracts::{ + Contracts, + ContractsEventTypeRegistry, }, -}; + session::{ + Session, + SessionEventTypeRegistry, + }, + staking::{ + Staking, + StakingEventTypeRegistry, + }, + sudo::{ + Sudo, + SudoEventTypeRegistry, + }, + system::{ + System, + SystemEventTypeRegistry, + }, +}, EventTypeRegistry}; /// Runtime trait. pub trait Runtime: System + Sized + Send + Sync + 'static { @@ -162,6 +175,9 @@ pub trait Runtime: System + Sized + Send + Sync + 'static { type Signature: Verify + Encode + Send + Sync + 'static; /// Transaction extras. type Extra: SignedExtra + Send + Sync + 'static; + + /// Register type sizes for this runtime + fn register_type_sizes(event_type_registry: &mut EventTypeRegistry); } /// Concrete type definitions compatible with those in the default substrate `node_runtime` @@ -178,6 +194,15 @@ impl Staking for DefaultNodeRuntime {} impl Runtime for DefaultNodeRuntime { type Signature = MultiSignature; type Extra = DefaultExtra; + + fn register_type_sizes(event_type_registry: &mut EventTypeRegistry) { + event_type_registry.with_system(); + event_type_registry.with_balances(); + event_type_registry.with_session(); + event_type_registry.with_contracts(); + event_type_registry.with_sudo(); + register_default_type_sizes(event_type_registry); + } } impl System for DefaultNodeRuntime { @@ -217,6 +242,14 @@ pub struct NodeTemplateRuntime; impl Runtime for NodeTemplateRuntime { type Signature = MultiSignature; type Extra = DefaultExtra; + + fn register_type_sizes(event_type_registry: &mut EventTypeRegistry) { + event_type_registry.with_system(); + event_type_registry.with_balances(); + event_type_registry.with_session(); + event_type_registry.with_sudo(); + register_default_type_sizes(event_type_registry); + } } impl System for NodeTemplateRuntime { @@ -253,6 +286,14 @@ pub struct ContractsTemplateRuntime; impl Runtime for ContractsTemplateRuntime { type Signature = ::Signature; type Extra = DefaultExtra; + + fn register_type_sizes(event_type_registry: &mut EventTypeRegistry) { + event_type_registry.with_system(); + event_type_registry.with_balances(); + event_type_registry.with_contracts(); + event_type_registry.with_sudo(); + register_default_type_sizes(event_type_registry); + } } impl System for ContractsTemplateRuntime { @@ -287,6 +328,14 @@ pub struct KusamaRuntime; impl Runtime for KusamaRuntime { type Signature = MultiSignature; type Extra = DefaultExtra; + + fn register_type_sizes(event_type_registry: &mut EventTypeRegistry) { + event_type_registry.with_system(); + event_type_registry.with_balances(); + event_type_registry.with_session(); + event_type_registry.with_staking(); + register_default_type_sizes(event_type_registry); + } } impl System for KusamaRuntime { @@ -311,3 +360,31 @@ impl Staking for KusamaRuntime {} impl Balances for KusamaRuntime { type Balance = u128; } + +/// Register default common runtime type sizes +fn register_default_type_sizes(event_type_registry: &mut EventTypeRegistry) { + // register default event arg type sizes for dynamic decoding of events + event_type_registry.register_type_size::<()>("PhantomData"); + event_type_registry.register_type_size::("DispatchInfo"); + event_type_registry.register_type_size::("bool"); + event_type_registry.register_type_size::("ReferendumIndex"); + event_type_registry.register_type_size::<[u8; 16]>("Kind"); + event_type_registry.register_type_size::<[u8; 32]>("AuthorityId"); + event_type_registry.register_type_size::("u8"); + event_type_registry.register_type_size::("u32"); + event_type_registry.register_type_size::("u64"); + event_type_registry.register_type_size::("u128"); + event_type_registry.register_type_size::("AccountIndex"); + event_type_registry.register_type_size::("SessionIndex"); + event_type_registry.register_type_size::("PropIndex"); + event_type_registry.register_type_size::("ProposalIndex"); + event_type_registry.register_type_size::("AuthorityIndex"); + event_type_registry.register_type_size::("AuthorityWeight"); + event_type_registry.register_type_size::("MemberCount"); + event_type_registry.register_type_size::("AccountId"); + event_type_registry.register_type_size::("BlockNumber"); + event_type_registry.register_type_size::("Hash"); + event_type_registry.register_type_size::("VoteThreshold"); + // Additional types + event_type_registry.register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); +} diff --git a/src/subscription.rs b/src/subscription.rs index 6f352edeb8..f7e210d556 100644 --- a/src/subscription.rs +++ b/src/subscription.rs @@ -34,9 +34,9 @@ use crate::{ /// Event subscription simplifies filtering a storage change set stream for /// events of interest. -pub struct EventSubscription { +pub struct EventSubscription<'a, T: Runtime> { subscription: Subscription>, - decoder: EventsDecoder, + decoder: &'a EventsDecoder, block: Option, extrinsic: Option, event: Option<(&'static str, &'static str)>, @@ -44,11 +44,11 @@ pub struct EventSubscription { finished: bool, } -impl EventSubscription { +impl<'a, T: Runtime> EventSubscription<'a, T> { /// Creates a new event subscription. pub fn new( subscription: Subscription>, - decoder: EventsDecoder, + decoder: &'a EventsDecoder, ) -> Self { Self { subscription, From 1f2022d95f651ce8fe371da928cfcd19f8f96451 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 16:02:44 +0000 Subject: [PATCH 04/18] Fmt --- examples/transfer_subscribe.rs | 17 ++++++--- src/events.rs | 27 ++++++------- src/frame/balances.rs | 28 ++++++++------ src/frame/mod.rs | 8 ++-- src/lib.rs | 8 ++-- src/runtimes.rs | 70 +++++++++++++++++++--------------- 6 files changed, 88 insertions(+), 70 deletions(-) diff --git a/examples/transfer_subscribe.rs b/examples/transfer_subscribe.rs index d3d7b62e45..dae98fbc72 100644 --- a/examples/transfer_subscribe.rs +++ b/examples/transfer_subscribe.rs @@ -15,11 +15,18 @@ // along with substrate-subxt. If not, see . use sp_keyring::AccountKeyring; -use substrate_subxt::{balances::{ - BalancesEventTypeRegistry, - TransferCallExt, - TransferEvent, -}, sp_core::Decode, ClientBuilder, DefaultNodeRuntime, EventSubscription, PairSigner}; +use substrate_subxt::{ + balances::{ + BalancesEventTypeRegistry, + TransferCallExt, + TransferEvent, + }, + sp_core::Decode, + ClientBuilder, + DefaultNodeRuntime, + EventSubscription, + PairSigner, +}; #[async_std::main] async fn main() -> Result<(), Box> { diff --git a/src/events.rs b/src/events.rs index 4902a11cfe..5329d84604 100644 --- a/src/events.rs +++ b/src/events.rs @@ -199,12 +199,7 @@ impl EventsDecoder { let len = >::decode(input)?; len.encode_to(output); for _ in 0..len.0 { - self.decode_raw_bytes( - &[*arg.clone()], - input, - output, - errors, - )? + self.decode_raw_bytes(&[*arg.clone()], input, output, errors)? } } EventArg::Option(arg) => { @@ -212,12 +207,7 @@ impl EventsDecoder { 0 => output.push_byte(0), 1 => { output.push_byte(1); - self.decode_raw_bytes( - &[*arg.clone()], - input, - output, - errors, - )? + self.decode_raw_bytes(&[*arg.clone()], input, output, errors)? } _ => { return Err(Error::Other( @@ -275,7 +265,8 @@ impl Clone for EventTypeRegistry { impl fmt::Debug for EventTypeRegistry { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EventTypeRegistry") - .field("segmenters", + .field( + "segmenters", &self.segmenters.keys().cloned().collect::(), ) .finish() @@ -303,7 +294,10 @@ impl EventTypeRegistry { } /// Check missing type sizes. - pub fn check_missing_type_sizes(&self, metadata: &Metadata) -> Result<(), HashSet> { + pub fn check_missing_type_sizes( + &self, + metadata: &Metadata, + ) -> Result<(), HashSet> { let mut missing = HashSet::new(); for module in metadata.modules_with_events() { for event in module.events() { @@ -364,7 +358,10 @@ mod tests { #[test] fn test_decode_option() { - let decoder = EventsDecoder::::new(Metadata::default(), EventTypeRegistry::new()); + let decoder = EventsDecoder::::new( + Metadata::default(), + EventTypeRegistry::new(), + ); let value = Some(0u8); let input = value.encode(); diff --git a/src/frame/balances.rs b/src/frame/balances.rs index 5a3cd18720..631d85dce2 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -153,17 +153,23 @@ pub struct TransferEvent { #[cfg(test)] mod tests { use super::*; - use crate::{error::{ - Error, - ModuleError, - RuntimeError, - }, extrinsic::{ - PairSigner, - Signer, - }, subscription::EventSubscription, system::AccountStoreExt, tests::{ - test_client, - TestRuntime, - }}; + use crate::{ + error::{ + Error, + ModuleError, + RuntimeError, + }, + extrinsic::{ + PairSigner, + Signer, + }, + subscription::EventSubscription, + system::AccountStoreExt, + tests::{ + test_client, + TestRuntime, + }, + }; use sp_core::{ sr25519::Pair, Pair as _, diff --git a/src/frame/mod.rs b/src/frame/mod.rs index 85332124e1..32b4c3eec3 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -16,11 +16,9 @@ //! Implements support for built-in runtime modules. -use crate::{ - metadata::{ - Metadata, - MetadataError, - }, +use crate::metadata::{ + Metadata, + MetadataError, }; use codec::{ Decode, diff --git a/src/lib.rs b/src/lib.rs index 55eb1023d7..254304947f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,8 +79,8 @@ mod subscription; pub use crate::{ error::Error, events::{ - EventsDecoder, EventTypeRegistry, + EventsDecoder, RawEvent, }, extrinsic::{ @@ -195,7 +195,8 @@ impl ClientBuilder { .await; let metadata = metadata?; - if let Err(missing) = self.event_type_registry.check_missing_type_sizes(&metadata) { + if let Err(missing) = self.event_type_registry.check_missing_type_sizes(&metadata) + { if self.skip_type_sizes_check { log::warn!( "The following types do not have registered type segmenters: {:?} \ @@ -211,7 +212,8 @@ impl ClientBuilder { } } - let events_decoder = EventsDecoder::new(metadata.clone(), self.event_type_registry); + let events_decoder = + EventsDecoder::new(metadata.clone(), self.event_type_registry); Ok(Client { rpc, diff --git a/src/runtimes.rs b/src/runtimes.rs index 48bdc88090..b737503a7d 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -138,36 +138,40 @@ impl_opaque_keys! { } } -use crate::{extrinsic::{ - DefaultExtra, - SignedExtra, -}, frame::{ - balances::{ - AccountData, - Balances, - BalancesEventTypeRegistry, +use crate::{ + extrinsic::{ + DefaultExtra, + SignedExtra, }, - contracts::{ - Contracts, - ContractsEventTypeRegistry, + frame::{ + balances::{ + AccountData, + Balances, + BalancesEventTypeRegistry, + }, + contracts::{ + Contracts, + ContractsEventTypeRegistry, + }, + session::{ + Session, + SessionEventTypeRegistry, + }, + staking::{ + Staking, + StakingEventTypeRegistry, + }, + sudo::{ + Sudo, + SudoEventTypeRegistry, + }, + system::{ + System, + SystemEventTypeRegistry, + }, }, - session::{ - Session, - SessionEventTypeRegistry, - }, - staking::{ - Staking, - StakingEventTypeRegistry, - }, - sudo::{ - Sudo, - SudoEventTypeRegistry, - }, - system::{ - System, - SystemEventTypeRegistry, - }, -}, EventTypeRegistry}; + EventTypeRegistry, +}; /// Runtime trait. pub trait Runtime: System + Sized + Send + Sync + 'static { @@ -362,10 +366,13 @@ impl Balances for KusamaRuntime { } /// Register default common runtime type sizes -fn register_default_type_sizes(event_type_registry: &mut EventTypeRegistry) { +fn register_default_type_sizes( + event_type_registry: &mut EventTypeRegistry, +) { // register default event arg type sizes for dynamic decoding of events event_type_registry.register_type_size::<()>("PhantomData"); - event_type_registry.register_type_size::("DispatchInfo"); + event_type_registry + .register_type_size::("DispatchInfo"); event_type_registry.register_type_size::("bool"); event_type_registry.register_type_size::("ReferendumIndex"); event_type_registry.register_type_size::<[u8; 16]>("Kind"); @@ -386,5 +393,6 @@ fn register_default_type_sizes(event_type_registry: &mut EventTypeRe event_type_registry.register_type_size::("Hash"); event_type_registry.register_type_size::("VoteThreshold"); // Additional types - event_type_registry.register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); + event_type_registry + .register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); } From 709574786a9de68b3dd424e614a617ad11955c9d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 16:30:24 +0000 Subject: [PATCH 05/18] Register runtime type sizes on creation of EventTypeRegistry --- examples/transfer_subscribe.rs | 1 - proc-macro/src/module.rs | 2 +- src/events.rs | 29 +++++++++++++---------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/examples/transfer_subscribe.rs b/examples/transfer_subscribe.rs index dae98fbc72..80099e507d 100644 --- a/examples/transfer_subscribe.rs +++ b/examples/transfer_subscribe.rs @@ -17,7 +17,6 @@ use sp_keyring::AccountKeyring; use substrate_subxt::{ balances::{ - BalancesEventTypeRegistry, TransferCallExt, TransferEvent, }, diff --git a/proc-macro/src/module.rs b/proc-macro/src/module.rs index 95f43d5328..c1228cd630 100644 --- a/proc-macro/src/module.rs +++ b/proc-macro/src/module.rs @@ -174,7 +174,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream { fn #with_module(&mut self); } - impl #module_events_type_registry for + impl #module_events_type_registry for #subxt::EventTypeRegistry { fn #with_module(&mut self) { diff --git a/src/events.rs b/src/events.rs index 5329d84604..23166b13a1 100644 --- a/src/events.rs +++ b/src/events.rs @@ -39,18 +39,13 @@ use std::{ }, }; -use crate::{ - error::{ - Error, - RuntimeError, - }, - metadata::{ - EventArg, - Metadata, - }, - Phase, - System, -}; +use crate::{error::{ + Error, + RuntimeError, +}, metadata::{ + EventArg, + Metadata, +}, Phase, System, Runtime}; /// Raw bytes for an Event pub struct RawEvent { @@ -119,7 +114,7 @@ impl Clone for EventsDecoder { } } -impl EventsDecoder { +impl EventsDecoder { /// Creates a new `EventsDecoder`. pub fn new(metadata: Metadata, event_type_registry: EventTypeRegistry) -> Self { Self { @@ -273,13 +268,15 @@ impl fmt::Debug for EventTypeRegistry { } } -impl EventTypeRegistry { +impl EventTypeRegistry { /// Create a new [`EventTypeRegistry`]. pub fn new() -> Self { - Self { + let mut registry = Self { segmenters: HashMap::new(), marker: PhantomData, - } + }; + T::register_type_sizes(&mut registry); + registry } /// Register a type. From 79edd3d7111ed275f18d24172c119071ef1991e2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 16:42:26 +0000 Subject: [PATCH 06/18] Register more default dispatch types --- src/runtimes.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtimes.rs b/src/runtimes.rs index b737503a7d..55bdc1ede5 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -373,6 +373,10 @@ fn register_default_type_sizes( event_type_registry.register_type_size::<()>("PhantomData"); event_type_registry .register_type_size::("DispatchInfo"); + event_type_registry + .register_type_size::("DispatchResult"); + event_type_registry + .register_type_size::("DispatchError"); event_type_registry.register_type_size::("bool"); event_type_registry.register_type_size::("ReferendumIndex"); event_type_registry.register_type_size::<[u8; 16]>("Kind"); From 648542706f0f6d6c9571d9df7d985f2eb0acb2cd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 17:02:46 +0000 Subject: [PATCH 07/18] Add missing type sizes --- src/runtimes.rs | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index 55bdc1ede5..716e5e17d9 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -369,34 +369,49 @@ impl Balances for KusamaRuntime { fn register_default_type_sizes( event_type_registry: &mut EventTypeRegistry, ) { - // register default event arg type sizes for dynamic decoding of events + // primitives + event_type_registry.register_type_size::("bool"); + event_type_registry.register_type_size::("u8"); + event_type_registry.register_type_size::("u32"); + event_type_registry.register_type_size::("u64"); + event_type_registry.register_type_size::("u128"); + event_type_registry.register_type_size::<()>("PhantomData"); + + // runtime associated types + event_type_registry.register_type_size::("AccountId"); + event_type_registry.register_type_size::("BlockNumber"); + event_type_registry.register_type_size::("Hash"); + + // frame_support types event_type_registry .register_type_size::("DispatchInfo"); event_type_registry .register_type_size::("DispatchResult"); event_type_registry .register_type_size::("DispatchError"); - event_type_registry.register_type_size::("bool"); + event_type_registry + .register_type_size::("Status"); + + // aliases etc. + type AuthorityId = [u8; 32]; + type AuthorityWeight = u64; + event_type_registry.register_type_size::("ReferendumIndex"); event_type_registry.register_type_size::<[u8; 16]>("Kind"); - event_type_registry.register_type_size::<[u8; 32]>("AuthorityId"); - event_type_registry.register_type_size::("u8"); - event_type_registry.register_type_size::("u32"); - event_type_registry.register_type_size::("u64"); - event_type_registry.register_type_size::("u128"); + event_type_registry.register_type_size::("AuthorityId"); + event_type_registry.register_type_size::("AccountIndex"); event_type_registry.register_type_size::("SessionIndex"); event_type_registry.register_type_size::("PropIndex"); event_type_registry.register_type_size::("ProposalIndex"); event_type_registry.register_type_size::("AuthorityIndex"); - event_type_registry.register_type_size::("AuthorityWeight"); + event_type_registry.register_type_size::("AuthorityWeight"); event_type_registry.register_type_size::("MemberCount"); - event_type_registry.register_type_size::("AccountId"); - event_type_registry.register_type_size::("BlockNumber"); - event_type_registry.register_type_size::("Hash"); + event_type_registry.register_type_size::("VoteThreshold"); - // Additional types event_type_registry .register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); + event_type_registry + .register_type_size::>("AuthorityList"); } From c38312c6e309d178ec8d99d3f882090ec3c773d2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 17:04:28 +0000 Subject: [PATCH 08/18] fmt --- src/events.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/events.rs b/src/events.rs index 23166b13a1..5601770315 100644 --- a/src/events.rs +++ b/src/events.rs @@ -39,13 +39,19 @@ use std::{ }, }; -use crate::{error::{ - Error, - RuntimeError, -}, metadata::{ - EventArg, - Metadata, -}, Phase, System, Runtime}; +use crate::{ + error::{ + Error, + RuntimeError, + }, + metadata::{ + EventArg, + Metadata, + }, + Phase, + Runtime, + System, +}; /// Raw bytes for an Event pub struct RawEvent { From a9e7c7d9180d610352b46f58e7a9dbbdd35a2d59 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 17:11:19 +0000 Subject: [PATCH 09/18] Fix up register_type_size builder method --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 254304947f..d8c4904b80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,11 +158,12 @@ impl ClientBuilder { /// Register a custom type segmenter, for consuming types in events where the size cannot /// be inferred from the metadata. - pub fn register_type_size(mut self, name: &str) + pub fn register_type_size(mut self, name: &str) -> Self where U: Codec + Send + Sync + 'static, { - self.event_type_registry.register_type_size::(name) + self.event_type_registry.register_type_size::(name); + self } /// Disable the check for missing type sizes on `build`. From 32bedb5020840a8202a07abdc6aa12acd02a12d1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 17:15:32 +0000 Subject: [PATCH 10/18] Update doc comments --- proc-macro/src/lib.rs | 8 ++++---- proc-macro/src/module.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/proc-macro/src/lib.rs b/proc-macro/src/lib.rs index 2ca3e4531b..7649c8d4f1 100644 --- a/proc-macro/src/lib.rs +++ b/proc-macro/src/lib.rs @@ -62,14 +62,14 @@ use synstructure::{ /// /// const MODULE: &str = "Herd"; /// -/// // `EventsDecoder` extension trait. -/// pub trait HerdEventsDecoder { +/// // `EventTypeRegistry` extension trait. +/// pub trait HerdEventTypeRegistry { /// // Registers this modules types. /// fn with_herd(&mut self); /// } /// -/// impl HerdEventsDecoder for -/// substrate_subxt::EventsDecoder +/// impl EventTypeRegistry for +/// substrate_subxt::EventTypeRegistry /// { /// fn with_herd(&mut self) { /// self.with_husbandry(); diff --git a/proc-macro/src/module.rs b/proc-macro/src/module.rs index c1228cd630..2e64440efe 100644 --- a/proc-macro/src/module.rs +++ b/proc-macro/src/module.rs @@ -168,7 +168,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream { const MODULE: &str = #module_name; - /// `EventsDecoder` extension trait. + /// `EventTypeRegistry` extension trait. pub trait #module_events_type_registry { /// Registers this modules types. fn #with_module(&mut self); @@ -221,7 +221,7 @@ mod tests { const MODULE: &str = "Balances"; - /// `EventsDecoder` extension trait. + /// `EventTypeRegistry` extension trait. pub trait BalancesEventTypeRegistry { /// Registers this modules types. fn with_balances(&mut self); From 7e1c1378da5b1dcfb9d239123ff853f58e6b7fd9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 10 Feb 2021 17:26:06 +0000 Subject: [PATCH 11/18] Make register_default_type_sizes public --- src/runtimes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtimes.rs b/src/runtimes.rs index 716e5e17d9..5a62864782 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -366,7 +366,7 @@ impl Balances for KusamaRuntime { } /// Register default common runtime type sizes -fn register_default_type_sizes( +pub fn register_default_type_sizes( event_type_registry: &mut EventTypeRegistry, ) { // primitives From 9b31d98f92f6ef31e9e5ddeda13e67a8a1d72011 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 11 Feb 2021 11:34:36 +0000 Subject: [PATCH 12/18] Don't allow duplicate registered types --- src/events.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/events.rs b/src/events.rs index 5601770315..eb3b53db48 100644 --- a/src/events.rs +++ b/src/events.rs @@ -29,7 +29,7 @@ use sp_runtime::{ }; use std::{ collections::{ - HashMap, + hash_map::{Entry, HashMap}, HashSet, }, fmt, @@ -290,10 +290,12 @@ impl EventTypeRegistry { where U: Codec + Send + Sync + 'static, { - // A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized + // A segmenter decodes a type from an input stream (&mut &[u8]) and returns te serialized // type to the output stream (&mut Vec). - self.segmenters - .insert(name.to_string(), Box::new(TypeMarker::::default())); + match self.segmenters.entry(name.to_string()) { + Entry::Occupied(_) => panic!("Already a type registered with key {}", name), + Entry::Vacant(entry) => entry.insert(Box::new(TypeMarker::::default())) + }; } /// Check missing type sizes. From c77d9e685e0120f241443b8035d9eef06bc1f455 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 11 Feb 2021 11:35:05 +0000 Subject: [PATCH 13/18] Remove call to supertraits type registration, done manually in Runtime --- proc-macro/src/lib.rs | 1 - proc-macro/src/module.rs | 26 ++++++-------------------- src/runtimes.rs | 11 ++++++----- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/proc-macro/src/lib.rs b/proc-macro/src/lib.rs index 7649c8d4f1..51778bb15f 100644 --- a/proc-macro/src/lib.rs +++ b/proc-macro/src/lib.rs @@ -72,7 +72,6 @@ use synstructure::{ /// substrate_subxt::EventTypeRegistry /// { /// fn with_herd(&mut self) { -/// self.with_husbandry(); /// self.register_type_size::("Hooves"); /// self.register_type_size::("Wool"); /// } diff --git a/proc-macro/src/module.rs b/proc-macro/src/module.rs index 2e64440efe..2b17fba46d 100644 --- a/proc-macro/src/module.rs +++ b/proc-macro/src/module.rs @@ -131,17 +131,6 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream { let module_events_type_registry = event_type_registry_trait_name(module); let with_module = with_module_ident(module); - let bounds = input.supertraits.iter().filter_map(|bound| { - if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound { - let module = utils::path_to_ident(path); - let with_module = with_module_ident(module); - Some(quote! { - self.#with_module(); - }) - } else { - None - } - }); let associated_types = input.items.iter().filter_map(|item| { if let syn::TraitItem::Type(ty) = item { if ignore(&ty.attrs) { @@ -178,7 +167,6 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream { #subxt::EventTypeRegistry { fn #with_module(&mut self) { - #(#bounds)* #(#associated_types)* #(#types)* } @@ -227,11 +215,10 @@ mod tests { fn with_balances(&mut self); } - impl BalancesEventTypeRegistry for - substrate_subxt::EventsDecoder + impl BalancesEventTypeRegistry for + substrate_subxt::EventTypeRegistry { fn with_balances(&mut self) { - self.with_system(); self.register_type_size::("Balance"); } } @@ -262,17 +249,16 @@ mod tests { const MODULE: &str = "Herd"; - /// `EventsDecoder` extension trait. - pub trait HerdEventsDecoder { + /// `EventTypeRegistry` extension trait. + pub trait HerdEventTypeRegistry { /// Registers this modules types. fn with_herd(&mut self); } - impl HerdEventsDecoder for - substrate_subxt::EventsDecoder + impl HerdEventTypeRegistry for + substrate_subxt::EventTypeRegistry { fn with_herd(&mut self) { - self.with_husbandry(); self.register_type_size::("Hoves"); self.register_type_size::("Wool"); } diff --git a/src/runtimes.rs b/src/runtimes.rs index 5a62864782..48a8a95258 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -200,12 +200,13 @@ impl Runtime for DefaultNodeRuntime { type Extra = DefaultExtra; fn register_type_sizes(event_type_registry: &mut EventTypeRegistry) { + println!("REGISTERING"); event_type_registry.with_system(); - event_type_registry.with_balances(); - event_type_registry.with_session(); - event_type_registry.with_contracts(); - event_type_registry.with_sudo(); - register_default_type_sizes(event_type_registry); + // event_type_registry.with_balances(); + // event_type_registry.with_session(); + // event_type_registry.with_contracts(); + // event_type_registry.with_sudo(); + // register_default_type_sizes(event_type_registry); } } From 4e1f6182f562c61876b14f59d1837f9a7b2a2d25 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 11 Feb 2021 12:00:59 +0000 Subject: [PATCH 14/18] Fix tests and warnings --- proc-macro/tests/balances.rs | 5 +---- src/frame/balances.rs | 5 +---- src/frame/contracts.rs | 10 ++-------- src/frame/session.rs | 10 ++-------- src/frame/staking.rs | 5 +---- src/frame/sudo.rs | 5 +---- src/runtimes.rs | 17 +++++------------ 7 files changed, 13 insertions(+), 44 deletions(-) diff --git a/proc-macro/tests/balances.rs b/proc-macro/tests/balances.rs index 29017337f6..6c669569f0 100644 --- a/proc-macro/tests/balances.rs +++ b/proc-macro/tests/balances.rs @@ -30,10 +30,7 @@ use substrate_subxt::{ MaybeSerialize, Member, }, - system::{ - System, - SystemEventTypeRegistry, - }, + system::System, ClientBuilder, KusamaRuntime, PairSigner, diff --git a/src/frame/balances.rs b/src/frame/balances.rs index 631d85dce2..b10e811a44 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -16,10 +16,7 @@ //! Implements support for the pallet_balances module. -use crate::frame::system::{ - System, - SystemEventTypeRegistry, -}; +use crate::frame::system::System; use codec::{ Decode, Encode, diff --git a/src/frame/contracts.rs b/src/frame/contracts.rs index aa6199fa79..4c5d189bde 100644 --- a/src/frame/contracts.rs +++ b/src/frame/contracts.rs @@ -17,14 +17,8 @@ //! Implements support for the pallet_contracts module. use crate::frame::{ - balances::{ - Balances, - BalancesEventTypeRegistry, - }, - system::{ - System, - SystemEventTypeRegistry, - }, + balances::Balances, + system::System, }; use codec::{ Decode, diff --git a/src/frame/session.rs b/src/frame/session.rs index e9b32bd0f4..015df27380 100644 --- a/src/frame/session.rs +++ b/src/frame/session.rs @@ -16,14 +16,8 @@ //! Session support use crate::frame::{ - balances::{ - Balances, - BalancesEventTypeRegistry as _, - }, - system::{ - System, - SystemEventTypeRegistry as _, - }, + balances::Balances, + system::System, }; use codec::Encode; use frame_support::Parameter; diff --git a/src/frame/staking.rs b/src/frame/staking.rs index f783f00183..b5c1cda3b0 100644 --- a/src/frame/staking.rs +++ b/src/frame/staking.rs @@ -16,10 +16,7 @@ //! Implements support for the pallet_staking module. -use super::balances::{ - Balances, - BalancesEventTypeRegistry as _, -}; +use super::balances::Balances; use codec::{ Decode, Encode, diff --git a/src/frame/sudo.rs b/src/frame/sudo.rs index 21206480c2..23e30243ae 100644 --- a/src/frame/sudo.rs +++ b/src/frame/sudo.rs @@ -17,10 +17,7 @@ //! Implements support for the frame_sudo module. use crate::{ - frame::system::{ - System, - SystemEventTypeRegistry, - }, + frame::system::System, Encoded, }; use codec::Encode; diff --git a/src/runtimes.rs b/src/runtimes.rs index 48a8a95258..546228c65f 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -200,13 +200,12 @@ impl Runtime for DefaultNodeRuntime { type Extra = DefaultExtra; fn register_type_sizes(event_type_registry: &mut EventTypeRegistry) { - println!("REGISTERING"); event_type_registry.with_system(); - // event_type_registry.with_balances(); - // event_type_registry.with_session(); - // event_type_registry.with_contracts(); - // event_type_registry.with_sudo(); - // register_default_type_sizes(event_type_registry); + event_type_registry.with_balances(); + event_type_registry.with_session(); + event_type_registry.with_contracts(); + event_type_registry.with_sudo(); + register_default_type_sizes(event_type_registry); } } @@ -379,11 +378,6 @@ pub fn register_default_type_sizes( event_type_registry.register_type_size::<()>("PhantomData"); - // runtime associated types - event_type_registry.register_type_size::("AccountId"); - event_type_registry.register_type_size::("BlockNumber"); - event_type_registry.register_type_size::("Hash"); - // frame_support types event_type_registry .register_type_size::("DispatchInfo"); @@ -403,7 +397,6 @@ pub fn register_default_type_sizes( event_type_registry.register_type_size::("AuthorityId"); event_type_registry.register_type_size::("AccountIndex"); - event_type_registry.register_type_size::("SessionIndex"); event_type_registry.register_type_size::("PropIndex"); event_type_registry.register_type_size::("ProposalIndex"); event_type_registry.register_type_size::("AuthorityIndex"); From d501164039e9e04ae4a442d2a1e9a43bc1b73229 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 11 Feb 2021 16:15:36 +0000 Subject: [PATCH 15/18] Fix duplicate type registration --- src/frame/staking.rs | 8 -------- src/runtimes.rs | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/frame/staking.rs b/src/frame/staking.rs index b5c1cda3b0..60984d6be6 100644 --- a/src/frame/staking.rs +++ b/src/frame/staking.rs @@ -59,20 +59,12 @@ pub struct SetPayeeCall { pub _runtime: PhantomData, } -/// Identity of a Grandpa authority. -pub type AuthorityId = crate::runtimes::app::grandpa::Public; -/// The weight of an authority. -pub type AuthorityWeight = u64; -/// A list of Grandpa authorities with associated weights. -pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>; - /// The subset of the `frame::Trait` that a client must implement. #[module] #[rustfmt::skip] pub trait Staking: Balances { #![event_alias(ElectionCompute = u8)] #![event_type(EraIndex)] - #![event_type(AuthorityList)] } /// Number of eras to keep in history. diff --git a/src/runtimes.rs b/src/runtimes.rs index 546228c65f..9c843ec032 100644 --- a/src/runtimes.rs +++ b/src/runtimes.rs @@ -365,6 +365,13 @@ impl Balances for KusamaRuntime { type Balance = u128; } +/// Identity of a Grandpa authority. +pub type AuthorityId = crate::runtimes::app::grandpa::Public; +/// The weight of an authority. +pub type AuthorityWeight = u64; +/// A list of Grandpa authorities with associated weights. +pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>; + /// Register default common runtime type sizes pub fn register_default_type_sizes( event_type_registry: &mut EventTypeRegistry, @@ -389,23 +396,46 @@ pub fn register_default_type_sizes( .register_type_size::("Status"); // aliases etc. - type AuthorityId = [u8; 32]; - type AuthorityWeight = u64; - event_type_registry.register_type_size::("ReferendumIndex"); event_type_registry.register_type_size::<[u8; 16]>("Kind"); - event_type_registry.register_type_size::("AuthorityId"); event_type_registry.register_type_size::("AccountIndex"); event_type_registry.register_type_size::("PropIndex"); event_type_registry.register_type_size::("ProposalIndex"); event_type_registry.register_type_size::("AuthorityIndex"); - event_type_registry.register_type_size::("AuthorityWeight"); event_type_registry.register_type_size::("MemberCount"); event_type_registry.register_type_size::("VoteThreshold"); event_type_registry .register_type_size::<(T::BlockNumber, u32)>("TaskAddress"); + + event_type_registry.register_type_size::("AuthorityId"); + event_type_registry.register_type_size::("AuthorityWeight"); event_type_registry .register_type_size::>("AuthorityList"); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_register_default_runtime_type_sizes() { + EventTypeRegistry::::new(); + } + + #[test] + fn can_register_node_template_runtime_type_sizes() { + EventTypeRegistry::::new(); + } + + #[test] + fn can_register_contracts_template_runtime_type_sizes() { + EventTypeRegistry::::new(); + } + + #[test] + fn can_register_kusama_runtime_type_sizes() { + EventTypeRegistry::::new(); + } +} From e31cfc8e55ec97d481412c1b4572ce7752dd9d41 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 11 Feb 2021 16:16:27 +0000 Subject: [PATCH 16/18] Fmt --- src/events.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/events.rs b/src/events.rs index eb3b53db48..20241fb0a7 100644 --- a/src/events.rs +++ b/src/events.rs @@ -29,7 +29,10 @@ use sp_runtime::{ }; use std::{ collections::{ - hash_map::{Entry, HashMap}, + hash_map::{ + Entry, + HashMap, + }, HashSet, }, fmt, @@ -294,7 +297,7 @@ impl EventTypeRegistry { // type to the output stream (&mut Vec). match self.segmenters.entry(name.to_string()) { Entry::Occupied(_) => panic!("Already a type registered with key {}", name), - Entry::Vacant(entry) => entry.insert(Box::new(TypeMarker::::default())) + Entry::Vacant(entry) => entry.insert(Box::new(TypeMarker::::default())), }; } From cc0ae520d62373d1331de80bd79001cf105feb32 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Feb 2021 17:11:21 +0000 Subject: [PATCH 17/18] review: use is_empty() Co-authored-by: Niklas Adolfsson --- src/events.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events.rs b/src/events.rs index 8d21ccdcfc..d7da6fefa3 100644 --- a/src/events.rs +++ b/src/events.rs @@ -179,7 +179,7 @@ impl EventsDecoder { Err(err) => return Err(err), }; - if event_errors.len() == 0 { + if event_errors.is_empty() { r.push((phase.clone(), raw)); } From f1eda2a4105241682b9bb73339003bcea6b2c33c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 18 Feb 2021 09:53:14 +0000 Subject: [PATCH 18/18] Add panic docs --- src/events.rs | 4 ++++ src/lib.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/events.rs b/src/events.rs index d7da6fefa3..2cda82f0fe 100644 --- a/src/events.rs +++ b/src/events.rs @@ -289,6 +289,10 @@ impl EventTypeRegistry { } /// Register a type. + /// + /// # Panics + /// + /// If there is already a type size registered with this name. pub fn register_type_size(&mut self, name: &str) where U: Codec + Send + Sync + 'static, diff --git a/src/lib.rs b/src/lib.rs index 90656d57b9..a7a5628aa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,6 +158,10 @@ impl ClientBuilder { /// Register a custom type segmenter, for consuming types in events where the size cannot /// be inferred from the metadata. + /// + /// # Panics + /// + /// If there is already a type size registered with this name. pub fn register_type_size(mut self, name: &str) -> Self where U: Codec + Send + Sync + 'static,