diff --git a/Cargo.lock b/Cargo.lock index 4a4413905a40e..488a4d6d4c8c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2770,9 +2770,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "15.1.0" +version = "15.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +checksum = "f2a893ede8dde2293e94dacf9c8f5db5d0506cd909257a8f0ac2b7d610baf50c" dependencies = [ "cfg-if", "parity-scale-codec", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 7d16a1afa1f2d..b8e25b4734392 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -19,8 +19,8 @@ //! The Substrate runtime. This can be compiled with `#[no_std]`, ready for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512. -#![recursion_limit = "512"] +// `construct_runtime!` does a lot of recursion and requires us to increase the limits. +#![recursion_limit = "1024"] use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 4eebcfa4f3766..cbcc474eb8e28 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.163", default-features = false, features = ["alloc", "derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -frame-metadata = { version = "15.1.0", default-features = false, features = ["v14", "v15-unstable"] } +frame-metadata = { version = "15.2.0", default-features = false, features = ["unstable"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-std = { version = "8.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "23.0.0", default-features = false, path = "../../primitives/io" } diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs deleted file mode 100644 index fcd9b32141ab5..0000000000000 --- a/frame/support/procedural/src/construct_runtime/expand/event.rs +++ /dev/null @@ -1,168 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License - -use crate::construct_runtime::Pallet; -use proc_macro2::TokenStream; -use quote::quote; -use std::str::FromStr; -use syn::{Generics, Ident}; - -pub fn expand_outer_event( - runtime: &Ident, - pallet_decls: &[Pallet], - scrate: &TokenStream, -) -> syn::Result { - let mut event_variants = TokenStream::new(); - let mut event_conversions = TokenStream::new(); - let mut query_event_part_macros = Vec::new(); - - for pallet_decl in pallet_decls { - if let Some(pallet_entry) = pallet_decl.find_part("Event") { - let path = &pallet_decl.path; - let pallet_name = &pallet_decl.name; - let index = pallet_decl.index; - let instance = pallet_decl.instance.as_ref(); - let generics = &pallet_entry.generics; - - if instance.is_some() && generics.params.is_empty() { - let msg = format!( - "Instantiable pallet with no generic `Event` cannot \ - be constructed: pallet `{}` must have generic `Event`", - pallet_name, - ); - return Err(syn::Error::new(pallet_name.span(), msg)) - } - - let part_is_generic = !generics.params.is_empty(); - let pallet_event = match (instance, part_is_generic) { - (Some(inst), true) => quote!(#path::Event::<#runtime, #path::#inst>), - (Some(inst), false) => quote!(#path::Event::<#path::#inst>), - (None, true) => quote!(#path::Event::<#runtime>), - (None, false) => quote!(#path::Event), - }; - - event_variants.extend(expand_event_variant( - runtime, - pallet_decl, - index, - instance, - generics, - )); - event_conversions.extend(expand_event_conversion(scrate, pallet_decl, &pallet_event)); - query_event_part_macros.push(quote! { - #path::__substrate_event_check::is_event_part_defined!(#pallet_name); - }); - } - } - - Ok(quote! { - #( #query_event_part_macros )* - - #[derive( - Clone, PartialEq, Eq, - #scrate::codec::Encode, - #scrate::codec::Decode, - #scrate::scale_info::TypeInfo, - #scrate::RuntimeDebug, - )] - #[allow(non_camel_case_types)] - pub enum RuntimeEvent { - #event_variants - } - - #event_conversions - }) -} - -fn expand_event_variant( - runtime: &Ident, - pallet: &Pallet, - index: u8, - instance: Option<&Ident>, - generics: &Generics, -) -> TokenStream { - let path = &pallet.path; - let variant_name = &pallet.name; - let part_is_generic = !generics.params.is_empty(); - let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { - let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) - .expect("was successfully parsed before; qed"); - quote! { - #acc - #attr - } - }); - - match instance { - Some(inst) if part_is_generic => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Event<#runtime, #path::#inst>), - }, - Some(inst) => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Event<#path::#inst>), - }, - None if part_is_generic => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Event<#runtime>), - }, - None => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Event), - }, - } -} - -fn expand_event_conversion( - scrate: &TokenStream, - pallet: &Pallet, - pallet_event: &TokenStream, -) -> TokenStream { - let variant_name = &pallet.name; - let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { - let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) - .expect("was successfully parsed before; qed"); - quote! { - #acc - #attr - } - }); - - quote! { - #attr - impl From<#pallet_event> for RuntimeEvent { - fn from(x: #pallet_event) -> Self { - RuntimeEvent::#variant_name(x) - } - } - #attr - impl TryInto<#pallet_event> for RuntimeEvent { - type Error = (); - - fn try_into(self) -> #scrate::sp_std::result::Result<#pallet_event, Self::Error> { - match self { - Self::#variant_name(evt) => Ok(evt), - _ => Err(()), - } - } - } - } -} diff --git a/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/frame/support/procedural/src/construct_runtime/expand/metadata.rs index 81fc93ba3c9ef..3448ba84ec20b 100644 --- a/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License -use crate::construct_runtime::Pallet; +use crate::construct_runtime::{parse::PalletPath, Pallet}; use proc_macro2::TokenStream; use quote::quote; use std::str::FromStr; @@ -26,6 +26,7 @@ pub fn expand_runtime_metadata( pallet_declarations: &[Pallet], scrate: &TokenStream, extrinsic: &TypePath, + system_path: &PalletPath, ) -> TokenStream { let pallets = pallet_declarations .iter() @@ -115,6 +116,13 @@ pub fn expand_runtime_metadata( }, ty: #scrate::scale_info::meta_type::<#runtime>(), apis: (&rt).runtime_metadata(), + outer_enums: #scrate::metadata_ir::OuterEnumsIR { + call_enum_ty: #scrate::scale_info::meta_type::< + <#runtime as #system_path::Config>::RuntimeCall + >(), + event_enum_ty: #scrate::scale_info::meta_type::(), + error_enum_ty: #scrate::scale_info::meta_type::(), + } } } diff --git a/frame/support/procedural/src/construct_runtime/expand/mod.rs b/frame/support/procedural/src/construct_runtime/expand/mod.rs index 0fd98bb4dda13..830338f9265ff 100644 --- a/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -17,24 +17,24 @@ mod call; mod config; -mod event; mod freeze_reason; mod hold_reason; mod inherent; mod lock_id; mod metadata; mod origin; +mod outer_enums; mod slash_reason; mod unsigned; pub use call::expand_outer_dispatch; pub use config::expand_outer_config; -pub use event::expand_outer_event; pub use freeze_reason::expand_outer_freeze_reason; pub use hold_reason::expand_outer_hold_reason; pub use inherent::expand_outer_inherent; pub use lock_id::expand_outer_lock_id; pub use metadata::expand_runtime_metadata; pub use origin::expand_outer_origin; +pub use outer_enums::{expand_outer_enum, OuterEnumType}; pub use slash_reason::expand_outer_slash_reason; pub use unsigned::expand_outer_validate_unsigned; diff --git a/frame/support/procedural/src/construct_runtime/expand/outer_enums.rs b/frame/support/procedural/src/construct_runtime/expand/outer_enums.rs new file mode 100644 index 0000000000000..544f63be2bfa1 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime/expand/outer_enums.rs @@ -0,0 +1,283 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::construct_runtime::Pallet; +use proc_macro2::{Span, TokenStream}; +use quote::{quote, ToTokens}; +use std::str::FromStr; +use syn::{Generics, Ident}; + +/// Represents the types supported for creating an outer enum. +#[derive(Clone, Copy, PartialEq)] +pub enum OuterEnumType { + /// Collects the Event enums from all pallets. + Event, + /// Collects the Error enums from all pallets. + Error, +} + +impl OuterEnumType { + /// The name of the structure this enum represents. + fn struct_name(&self) -> &str { + match self { + OuterEnumType::Event => "RuntimeEvent", + OuterEnumType::Error => "RuntimeError", + } + } + + /// The name of the variant (ie `Event` or `Error`). + fn variant_name(&self) -> &str { + match self { + OuterEnumType::Event => "Event", + OuterEnumType::Error => "Error", + } + } +} + +impl ToTokens for OuterEnumType { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + OuterEnumType::Event => quote!(Event).to_tokens(tokens), + OuterEnumType::Error => quote!(Error).to_tokens(tokens), + } + } +} + +/// Create an outer enum that encapsulates all pallets as variants. +/// +/// Each variant represents a pallet and contains the corresponding type declared with either: +/// - #[pallet::event] for the [`OuterEnumType::Event`] variant +/// - #[pallet::error] for the [`OuterEnumType::Error`] variant +/// +/// The name of the outer enum is prefixed with Runtime, resulting in names like RuntimeEvent +/// or RuntimeError. +/// +/// This structure facilitates the decoding process by leveraging the metadata. +/// +/// # Example +/// +/// The code generate looks like the following for [`OuterEnumType::Event`]. +/// +/// ```ignore +/// enum RuntimeEvent { +/// #[codec(index = 0)] +/// System(pallet_system::Event), +/// +/// #[codec(index = 5)] +/// Balances(pallet_system::Event), +/// } +/// ``` +/// +/// Notice that the pallet index is preserved using the `#[codec(index = ..)]` attribute. +pub fn expand_outer_enum( + runtime: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream, + enum_ty: OuterEnumType, +) -> syn::Result { + // Stores all pallet variants. + let mut enum_variants = TokenStream::new(); + // Generates the enum conversion between the `Runtime` outer enum and the pallet's enum. + let mut enum_conversions = TokenStream::new(); + // Specific for events to query via `is_event_part_defined!`. + let mut query_enum_part_macros = Vec::new(); + + let enum_name_str = enum_ty.variant_name(); + let enum_name_ident = Ident::new(enum_ty.struct_name(), Span::call_site()); + + for pallet_decl in pallet_decls { + let Some(pallet_entry) = pallet_decl.find_part(enum_name_str) else { + continue + }; + + let path = &pallet_decl.path; + let pallet_name = &pallet_decl.name; + let index = pallet_decl.index; + let instance = pallet_decl.instance.as_ref(); + let generics = &pallet_entry.generics; + + if instance.is_some() && generics.params.is_empty() { + let msg = format!( + "Instantiable pallet with no generic `{}` cannot \ + be constructed: pallet `{}` must have generic `{}`", + enum_name_str, pallet_name, enum_name_str, + ); + return Err(syn::Error::new(pallet_name.span(), msg)) + } + + let part_is_generic = !generics.params.is_empty(); + let pallet_enum = match (instance, part_is_generic) { + (Some(inst), true) => quote!(#path::#enum_ty::<#runtime, #path::#inst>), + (Some(inst), false) => quote!(#path::#enum_ty::<#path::#inst>), + (None, true) => quote!(#path::#enum_ty::<#runtime>), + (None, false) => quote!(#path::#enum_ty), + }; + + enum_variants.extend(expand_enum_variant( + runtime, + pallet_decl, + index, + instance, + generics, + enum_ty, + )); + enum_conversions.extend(expand_enum_conversion( + scrate, + pallet_decl, + &pallet_enum, + &enum_name_ident, + )); + + if enum_ty == OuterEnumType::Event { + query_enum_part_macros.push(quote! { + #path::__substrate_event_check::is_event_part_defined!(#pallet_name); + }); + } + } + + // Derives specific for the event. + let event_custom_derives = + if enum_ty == OuterEnumType::Event { quote!(Clone, PartialEq, Eq,) } else { quote!() }; + + // Implementation specific for errors. + let error_custom_impl = generate_error_impl(scrate, enum_ty); + + Ok(quote! { + #( #query_enum_part_macros )* + + #[derive( + #event_custom_derives + #scrate::codec::Encode, + #scrate::codec::Decode, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + #[allow(non_camel_case_types)] + pub enum #enum_name_ident { + #enum_variants + } + + #enum_conversions + + #error_custom_impl + }) +} + +fn expand_enum_variant( + runtime: &Ident, + pallet: &Pallet, + index: u8, + instance: Option<&Ident>, + generics: &Generics, + enum_ty: OuterEnumType, +) -> TokenStream { + let path = &pallet.path; + let variant_name = &pallet.name; + let part_is_generic = !generics.params.is_empty(); + let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); + + match instance { + Some(inst) if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::#enum_ty<#runtime, #path::#inst>), + }, + Some(inst) => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::#enum_ty<#path::#inst>), + }, + None if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::#enum_ty<#runtime>), + }, + None => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::#enum_ty), + }, + } +} + +fn expand_enum_conversion( + scrate: &TokenStream, + pallet: &Pallet, + pallet_enum: &TokenStream, + enum_name_ident: &Ident, +) -> TokenStream { + let variant_name = &pallet.name; + let attr = pallet.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { + let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); + + quote! { + #attr + impl From<#pallet_enum> for #enum_name_ident { + fn from(x: #pallet_enum) -> Self { + #enum_name_ident + ::#variant_name(x) + } + } + #attr + impl TryInto<#pallet_enum> for #enum_name_ident { + type Error = (); + + fn try_into(self) -> #scrate::sp_std::result::Result<#pallet_enum, Self::Error> { + match self { + Self::#variant_name(evt) => Ok(evt), + _ => Err(()), + } + } + } + } +} + +fn generate_error_impl(scrate: &TokenStream, enum_ty: OuterEnumType) -> TokenStream { + // Implementation is specific to `Error`s. + if enum_ty == OuterEnumType::Event { + return quote! {} + } + + let enum_name_ident = Ident::new(enum_ty.struct_name(), Span::call_site()); + + quote! { + impl #enum_name_ident { + /// Optionally convert the `DispatchError` into the `RuntimeError`. + /// + /// Returns `Some` if the error matches the `DispatchError::Module` variant, otherwise `None`. + pub fn from_dispatch_error(err: #scrate::sp_runtime::DispatchError) -> Option { + let #scrate::sp_runtime::DispatchError::Module(module_error) = err else { return None }; + + let bytes = #scrate::codec::Encode::encode(&module_error); + #scrate::codec::Decode::decode(&mut &bytes[..]).ok() + } + } + } +} diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 9879a65d684a6..203d43ab3cc39 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -20,17 +20,69 @@ //! `construct_runtime` implementation is recursive and can generate code which will call itself in //! order to get all the pallet parts for each pallet. //! -//! Pallets define their parts (`Call`, `Storage`, ..) either explicitly with the syntax -//! `::{Call, ...}` or implicitly. +//! Pallets can define their parts: +//! - Implicitely: `System: frame_system` +//! - Explicitly: `System: frame_system::{Pallet, Call}` //! -//! In case a pallet defines its parts implicitly, then the pallet must provide the -//! `tt_default_parts` macro. `construct_runtime` will generate some code which utilizes `tt_call` -//! to call the `tt_default_parts` macro of the pallet. `tt_default_parts` will then return the -//! default pallet parts as input tokens to the `match_and_replace` macro, which ultimately -//! generates a call to `construct_runtime` again, this time with all the pallet parts explicitly -//! defined. +//! The `construct_runtime` transitions from the implicit definition to the explict one. +//! From the explicit state, Substrate expands the pallets with additional information +//! that is to be included in the runtime metadata. This expansion makes visible some extra +//! parts of the pallets, mainly the `Error` if defined. The expanded state looks like +//! `System: frame_system expanded::{Error} ::{Pallet, Call}` and concatenates the extra expanded +//! parts with the user-provided parts. For example, the `Pallet`, `Call` and `Error` parts are +//! collected. +//! +//! Pallets must provide the `tt_extra_parts` and `tt_default_parts` macros for these transitions. +//! These are automatically implemented by the `#[pallet::pallet]` macro. +//! +//! This macro also generates the following enums for ease of decoding: +//! - `enum RuntimeCall`: This type contains the information needed to decode extrinsics. +//! - `enum RuntimeEvent`: This type contains the information needed to decode events. +//! - `enum RuntimeError`: While this cannot be used directly to decode `sp_runtime::DispatchError` +//! from the chain, it contains the information needed to decode the +//! `sp_runtime::DispatchError::Module`. +//! +//! # State Transitions +//! +//! ```ignore +//! +----------+ +//! | Implicit | -----------+ +//! +----------+ | +//! | | +//! v v +//! +----------+ +------------------+ +//! | Explicit | --> | ExplicitExpanded | +//! +----------+ +------------------+ +//! ``` +//! +//! When all pallet parts are implcit, then the `construct_runtime!` macro expands to its final +//! state, the `ExplicitExpanded`. Otherwise, all implicit parts are converted to an explicit +//! expanded part allow the `construct_runtime!` to expand any remaining explicit parts to an +//! explicit expanded part. +//! +//! # Implicit to Explicit +//! +//! The `construct_runtime` macro transforms the implicit declaration of each pallet +//! `System: frame_system` to an explicit one `System: frame_system::{Pallet, Call}` using the +//! `tt_default_parts` macro. +//! +//! The `tt_default_parts` macro exposes a comma separated list of pallet parts. For example, the +//! `Event` part is exposed only if the pallet implements an event via `#[pallet::event]` macro. +//! The tokens generated by this macro are ` expanded :: { Pallet, Call }` for our example. +//! +//! The `match_and_insert` macro takes in 3 arguments: +//! - target: This is the `TokenStream` that contains the `construct_runtime!` macro. +//! - pattern: The pattern to match against in the target stream. +//! - tokens: The tokens to added after the pattern match. +//! +//! The `construct_runtime` macro uses the `tt_call` to get the default pallet parts via +//! the `tt_default_parts` macro defined by each pallet. The pallet parts are then returned as +//! input to the `match_and_replace` macro. +//! The `match_and_replace` then will modify the the `construct_runtime!` to expand the implicit +//! definition to the explicit one. +//! +//! For example, //! -//! E.g. //! ```ignore //! construct_runtime!( //! //... @@ -106,6 +158,7 @@ //! tokens = [{ ::{Pallet, Call} }] //! } //! ``` +//! //! Which will then finally expand to the following: //! ```ignore //! construct_runtime!( @@ -116,6 +169,7 @@ //! } //! ) //! ``` +//! //! This call has no implicit pallet parts, thus it will expand to the runtime construction: //! ```ignore //! pub struct Runtime { ... } @@ -140,6 +194,19 @@ //! | w/ pallet parts | //! +--------------------+ //! ``` +//! +//! # Explicit to Explicit Expanded +//! +//! Users normally do not care about this transition. +//! +//! Similarly to the previous transition, the macro expansion transforms `System: +//! frame_system::{Pallet, Call}` into `System: frame_system expanded::{Error} ::{Pallet, Call}`. +//! The `expanded` section adds extra parts that the Substrate would like to expose for each pallet +//! by default. This is done to expose the approprite types for metadata construction. +//! +//! This time, instead of calling `tt_default_parts` we are using the `tt_extra_parts` macro. +//! This macro returns the ` :: expanded { Error }` list of additional parts we would like to +//! expose. mod expand; mod parse; @@ -171,9 +238,16 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { let res = match definition { RuntimeDeclaration::Implicit(implicit_def) => check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()).and_then( - |_| construct_runtime_intermediary_expansion(input_copy.into(), implicit_def), + |_| construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def), ), - RuntimeDeclaration::Explicit(explicit_decl) => + RuntimeDeclaration::Explicit(explicit_decl) => check_pallet_number( + input_copy.clone().into(), + explicit_decl.pallets.len(), + ) + .and_then(|_| { + construct_runtime_explicit_to_explicit_expanded(input_copy.into(), explicit_decl) + }), + RuntimeDeclaration::ExplicitExpanded(explicit_decl) => check_pallet_number(input_copy.into(), explicit_decl.pallets.len()) .and_then(|_| construct_runtime_final_expansion(explicit_decl)), }; @@ -189,9 +263,14 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { res.into() } -/// When some pallet have implicit parts definition then the macro will expand into a macro call to -/// `construct_runtime_args` of each pallets, see root documentation. -fn construct_runtime_intermediary_expansion( +/// All pallets that have implicit pallet parts (ie `System: frame_system`) are +/// expanded with the default parts defined by the pallet's `tt_default_parts` macro. +/// +/// This function transforms the [`RuntimeDeclaration::Implicit`] into +/// [`RuntimeDeclaration::Explicit`] that is not yet fully expanded. +/// +/// For more details, please refer to the root documentation. +fn construct_runtime_implicit_to_explicit( input: TokenStream2, definition: ImplicitRuntimeDeclaration, ) -> Result { @@ -218,6 +297,42 @@ fn construct_runtime_intermediary_expansion( Ok(expansion) } +/// All pallets that have +/// (I): explicit pallet parts (ie `System: frame_system::{Pallet, Call}`) and +/// (II): are not fully expanded (ie do not include the `Error` expansion part) +/// are fully expanded by including the parts from the pallet's `tt_extra_parts` macro. +/// +/// This function transforms the [`RuntimeDeclaration::Explicit`] that is not yet fully expanded +/// into [`RuntimeDeclaration::ExplicitExpanded`] fully expanded. +/// +/// For more details, please refer to the root documentation. +fn construct_runtime_explicit_to_explicit_expanded( + input: TokenStream2, + definition: ExplicitRuntimeDeclaration, +) -> Result { + let frame_support = generate_crate_access_2018("frame-support")?; + let mut expansion = quote::quote!( + #frame_support::construct_runtime! { #input } + ); + for pallet in definition.pallets.iter().filter(|pallet| !pallet.is_expanded) { + let pallet_path = &pallet.path; + let pallet_name = &pallet.name; + let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(::<#instance>)); + expansion = quote::quote!( + #frame_support::tt_call! { + macro = [{ #pallet_path::tt_extra_parts }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name: #pallet_path #pallet_instance }] + } + } + ); + } + + Ok(expansion) +} + /// All pallets have explicit definition of parts, this will expand to the runtime declaration. fn construct_runtime_final_expansion( definition: ExplicitRuntimeDeclaration, @@ -264,14 +379,23 @@ fn construct_runtime_final_expansion( let scrate = generate_crate_access(hidden_crate_name, "frame-support"); let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support"); - let outer_event = expand::expand_outer_event(&name, &pallets, &scrate)?; + let outer_event = + expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Event)?; + let outer_error = + expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Error)?; let outer_origin = expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?; let all_pallets = decl_all_pallets(&name, pallets.iter(), &features); let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); - let metadata = expand::expand_runtime_metadata(&name, &pallets, &scrate, &unchecked_extrinsic); + let metadata = expand::expand_runtime_metadata( + &name, + &pallets, + &scrate, + &unchecked_extrinsic, + &system_pallet.path, + ); let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); let inherent = expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); @@ -331,6 +455,8 @@ fn construct_runtime_final_expansion( #outer_event + #outer_error + #outer_origin #all_pallets diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index f819a90d1b5cd..b731bb0c83e27 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -35,6 +35,7 @@ mod keyword { syn::custom_keyword!(Call); syn::custom_keyword!(Storage); syn::custom_keyword!(Event); + syn::custom_keyword!(Error); syn::custom_keyword!(Config); syn::custom_keyword!(Origin); syn::custom_keyword!(Inherent); @@ -45,6 +46,7 @@ mod keyword { syn::custom_keyword!(SlashReason); syn::custom_keyword!(exclude_parts); syn::custom_keyword!(use_parts); + syn::custom_keyword!(expanded); } /// Declaration of a runtime. @@ -56,6 +58,7 @@ mod keyword { pub enum RuntimeDeclaration { Implicit(ImplicitRuntimeDeclaration), Explicit(ExplicitRuntimeDeclaration), + ExplicitExpanded(ExplicitRuntimeDeclaration), } /// Declaration of a runtime with some pallet with implicit declaration of parts. @@ -106,6 +109,13 @@ impl Parse for RuntimeDeclaration { pallets, pallets_token, })), + PalletsConversion::ExplicitExpanded(pallets) => + Ok(RuntimeDeclaration::ExplicitExpanded(ExplicitRuntimeDeclaration { + name, + where_section, + pallets, + pallets_token, + })), } } } @@ -188,6 +198,8 @@ impl Parse for WhereDefinition { /// The declaration of a pallet. #[derive(Debug, Clone)] pub struct PalletDeclaration { + /// Is this pallet fully expanded? + pub is_expanded: bool, /// The name of the pallet, e.g.`System` in `System: frame_system`. pub name: Ident, /// Optional attributes tagged right above a pallet declaration. @@ -233,6 +245,7 @@ impl Parse for PalletDeclaration { let _: Token![>] = input.parse()?; res } else if !(input.peek(Token![::]) && input.peek3(token::Brace)) && + !input.peek(keyword::expanded) && !input.peek(keyword::exclude_parts) && !input.peek(keyword::use_parts) && !input.peek(Token![=]) && @@ -246,10 +259,21 @@ impl Parse for PalletDeclaration { None }; + // Check if the pallet is fully expanded. + let (is_expanded, extra_parts) = if input.peek(keyword::expanded) { + let _: keyword::expanded = input.parse()?; + let _: Token![::] = input.parse()?; + (true, parse_pallet_parts(input)?) + } else { + (false, vec![]) + }; + // Parse for explicit parts let pallet_parts = if input.peek(Token![::]) && input.peek3(token::Brace) { let _: Token![::] = input.parse()?; - Some(parse_pallet_parts(input)?) + let mut parts = parse_pallet_parts(input)?; + parts.extend(extra_parts.into_iter()); + Some(parts) } else if !input.peek(keyword::exclude_parts) && !input.peek(keyword::use_parts) && !input.peek(Token![=]) && @@ -260,7 +284,7 @@ impl Parse for PalletDeclaration { "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", )) } else { - None + is_expanded.then_some(extra_parts) }; // Parse for specified parts @@ -288,7 +312,7 @@ impl Parse for PalletDeclaration { None }; - Ok(Self { attrs, name, path, instance, pallet_parts, specified_parts, index }) + Ok(Self { is_expanded, attrs, name, path, instance, pallet_parts, specified_parts, index }) } } @@ -371,6 +395,7 @@ pub enum PalletPartKeyword { Call(keyword::Call), Storage(keyword::Storage), Event(keyword::Event), + Error(keyword::Error), Config(keyword::Config), Origin(keyword::Origin), Inherent(keyword::Inherent), @@ -393,6 +418,8 @@ impl Parse for PalletPartKeyword { Ok(Self::Storage(input.parse()?)) } else if lookahead.peek(keyword::Event) { Ok(Self::Event(input.parse()?)) + } else if lookahead.peek(keyword::Error) { + Ok(Self::Error(input.parse()?)) } else if lookahead.peek(keyword::Config) { Ok(Self::Config(input.parse()?)) } else if lookahead.peek(keyword::Origin) { @@ -423,6 +450,7 @@ impl PalletPartKeyword { Self::Call(_) => "Call", Self::Storage(_) => "Storage", Self::Event(_) => "Event", + Self::Error(_) => "Error", Self::Config(_) => "Config", Self::Origin(_) => "Origin", Self::Inherent(_) => "Inherent", @@ -441,7 +469,7 @@ impl PalletPartKeyword { /// Returns the names of all pallet parts that allow to have a generic argument. fn all_generic_arg() -> &'static [&'static str] { - &["Event", "Origin", "Config"] + &["Event", "Error", "Origin", "Config"] } } @@ -452,6 +480,7 @@ impl ToTokens for PalletPartKeyword { Self::Call(inner) => inner.to_tokens(tokens), Self::Storage(inner) => inner.to_tokens(tokens), Self::Event(inner) => inner.to_tokens(tokens), + Self::Error(inner) => inner.to_tokens(tokens), Self::Config(inner) => inner.to_tokens(tokens), Self::Origin(inner) => inner.to_tokens(tokens), Self::Inherent(inner) => inner.to_tokens(tokens), @@ -554,6 +583,8 @@ fn parse_pallet_parts_no_generic(input: ParseStream) -> Result | Explicit | -> | ExplicitExpanded | +/// +----------+ +----------+ +------------------+ +/// ``` enum PalletsConversion { + /// Pallets implicitely declare parts. + /// + /// `System: frame_system`. Implicit(Vec), + /// Pallets explicitly declare parts. + /// + /// `System: frame_system::{Pallet, Call}` + /// + /// However, for backwards compatibility with Polkadot/Kusama + /// we must propagate some other parts to the pallet by default. Explicit(Vec), + /// Pallets explicitly declare parts that are fully expanded. + /// + /// This is the end state that contains extra parts included by + /// default by Subtrate. + /// + /// `System: frame_system expanded::{Error} ::{Pallet, Call}` + /// + /// For this example, the `Pallet`, `Call` and `Error` parts are collected. + ExplicitExpanded(Vec), } /// Convert from the parsed pallet declaration to their final information. @@ -604,6 +661,7 @@ fn convert_pallets(pallets: Vec) -> syn::Result = None; let mut names = HashMap::new(); + let mut is_expanded = true; let pallets = pallets .into_iter() @@ -698,7 +756,10 @@ fn convert_pallets(pallets: Vec) -> syn::Result>>()?; + is_expanded &= pallet.is_expanded; + Ok(Pallet { + is_expanded: pallet.is_expanded, name: pallet.name, index: final_index, path: pallet.path, @@ -709,5 +770,9 @@ fn convert_pallets(pallets: Vec) -> syn::Result>>()?; - Ok(PalletsConversion::Explicit(pallets)) + if is_expanded { + Ok(PalletsConversion::ExplicitExpanded(pallets)) + } else { + Ok(PalletsConversion::Explicit(pallets)) + } } diff --git a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index f36c765f7beb6..356bdbf67e923 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -26,6 +26,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { let count = COUNTER.with(|counter| counter.borrow_mut().inc()); let default_parts_unique_id = syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span()); + let extra_parts_unique_id = + syn::Ident::new(&format!("__tt_extra_parts_{}", count), def.item.span()); let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); @@ -36,6 +38,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { quote::quote!( Event #gen , ) }); + let error_part = def.error.as_ref().map(|_| quote::quote!(Error,)); + let origin_part = def.origin.as_ref().map(|origin| { let gen = origin.is_generic.then(|| quote::quote!( )); quote::quote!( Origin #gen , ) @@ -95,8 +99,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { $($frame_support)*::tt_return! { $caller tokens = [{ - ::{ - Pallet, #call_part #storage_part #event_part #origin_part #config_part + expanded::{ + Pallet, #call_part #storage_part #event_part #error_part #origin_part #config_part #inherent_part #validate_unsigned_part #freeze_reason_part #hold_reason_part #lock_id_part #slash_reason_part } @@ -106,5 +110,33 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { } pub use #default_parts_unique_id as tt_default_parts; + + + // This macro is similar to the `tt_default_parts!`. It expands the pallets thare are declared + // explicitly (`System: frame_system::{Pallet, Call}`) with extra parts. + // + // For example, after expansion an explicit pallet would look like: + // `System: expanded::{Error} ::{Pallet, Call}`. + // + // The `expanded` keyword is a marker of the final state of the `construct_runtime!`. + #[macro_export] + #[doc(hidden)] + macro_rules! #extra_parts_unique_id { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support)*::tt_return! { + $caller + tokens = [{ + expanded::{ + #error_part + } + }] + } + }; + } + + pub use #extra_parts_unique_id as tt_extra_parts; ) } diff --git a/frame/support/test/tests/common/mod.rs b/frame/support/test/tests/common/mod.rs new file mode 100644 index 0000000000000..b02ecc1b6e1dd --- /dev/null +++ b/frame/support/test/tests/common/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///! Common functionality between tests. +pub mod outer_enums; diff --git a/frame/support/test/tests/common/outer_enums.rs b/frame/support/test/tests/common/outer_enums.rs new file mode 100644 index 0000000000000..98139b0f0d1a8 --- /dev/null +++ b/frame/support/test/tests/common/outer_enums.rs @@ -0,0 +1,146 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Create 3 pallets for testing the outer error enum construction: +// +// - `pallet`: declares an error with `#[pallet::error]` +// - `pallet2`: declares an error with `#[pallet::error]` +// - `pallet3`: does not declare an error. + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::event] + pub enum Event, I: 'static = ()> { + /// Something + Something(u32), + } + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + phantom: PhantomData<(T, I)>, + } + + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { phantom: Default::default() } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) {} + } + + #[pallet::error] + #[derive(PartialEq, Eq)] + pub enum Error { + /// doc comment put into metadata + InsufficientProposersBalance, + NonExistentStorageValue, + } +} + +#[frame_support::pallet] +pub mod pallet2 { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::event] + pub enum Event, I: 'static = ()> { + /// Something + Something(u32), + } + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + phantom: PhantomData<(T, I)>, + } + + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { phantom: Default::default() } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) {} + } + + #[pallet::error] + #[derive(PartialEq, Eq)] + pub enum Error { + /// doc comment put into metadata + OtherInsufficientProposersBalance, + OtherNonExistentStorageValue, + } +} + +#[frame_support::pallet] +pub mod pallet3 { + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + } + + #[pallet::event] + pub enum Event, I: 'static = ()> { + /// Something + Something(u32), + } + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + phantom: PhantomData<(T, I)>, + } + + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { phantom: Default::default() } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) {} + } +} diff --git a/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr b/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr index 06caa036b91ff..ca2bb998e06d3 100644 --- a/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr +++ b/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr @@ -1,4 +1,4 @@ -error: `Call` is not allowed to have generics. Only the following pallets are allowed to have generics: `Event`, `Origin`, `Config`. +error: `Call` is not allowed to have generics. Only the following pallets are allowed to have generics: `Event`, `Error`, `Origin`, `Config`. --> $DIR/generics_in_invalid_module.rs:10:36 | 10 | Balance: balances::::{Call, Origin}, diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr index 42f79e96d4473..f1c3929fff25f 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr @@ -1,4 +1,4 @@ -error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` +error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` --> $DIR/invalid_module_details_keyword.rs:9:20 | 9 | system: System::{enum}, diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs b/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs index d627ffd5b66f7..173916f2ff6eb 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs +++ b/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.rs @@ -7,7 +7,7 @@ construct_runtime! { UncheckedExtrinsic = UncheckedExtrinsic { System: system::{Pallet}, - Balance: balances::{Error}, + Balance: balances::{Unexpected}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr b/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr index 6d535ca4335fc..2d5eeb5108fb9 100644 --- a/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr +++ b/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr @@ -1,5 +1,5 @@ -error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` +error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` --> $DIR/invalid_module_entry.rs:10:23 | -10 | Balance: balances::{Error}, - | ^^^^^ +10 | Balance: balances::{Unexpected}, + | ^^^^^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs b/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs index 3cd2f157d0475..d3018f02f89e3 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs +++ b/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.rs @@ -6,8 +6,8 @@ construct_runtime! { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet}, - Balance: balances::::{Event}, + System: system expanded::{}::{Pallet}, + Balance: balances:: expanded::{}::{Event}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr b/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr index b1aa9b86cd0d6..97968df36a482 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr +++ b/frame/support/test/tests/construct_runtime_ui/missing_event_generic_on_module_with_instance.stderr @@ -1,5 +1,5 @@ error: Instantiable pallet with no generic `Event` cannot be constructed: pallet `Balance` must have generic `Event` --> $DIR/missing_event_generic_on_module_with_instance.rs:10:3 | -10 | Balance: balances::::{Event}, +10 | Balance: balances:: expanded::{}::{Event}, | ^^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs b/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs index 787ba20117678..5fc238067f287 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs +++ b/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.rs @@ -6,8 +6,8 @@ construct_runtime! { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Pallet}, - Balance: balances::::{Origin}, + System: system expanded::{}::{Pallet}, + Balance: balances:: expanded::{}::{Origin}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr b/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr index 63bb7442a8576..f7df25d4c363f 100644 --- a/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr +++ b/frame/support/test/tests/construct_runtime_ui/missing_origin_generic_on_module_with_instance.stderr @@ -1,5 +1,5 @@ error: Instantiable pallet with no generic `Origin` cannot be constructed: pallet `Balance` must have generic `Origin` --> $DIR/missing_origin_generic_on_module_with_instance.rs:10:3 | -10 | Balance: balances::::{Origin}, +10 | Balance: balances:: expanded::{}::{Origin}, | ^^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index 35212df8f457c..28622eb08e443 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -52,8 +52,8 @@ construct_runtime! { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Pallet: pallet::{Pallet, Event}, + System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet expanded::{}::{Pallet, Event}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index ec753e9a03129..f6365ceb1a9cd 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -52,8 +52,8 @@ construct_runtime! { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Pallet: pallet::{Pallet, Config}, + System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet expanded::{}::{Pallet, Config}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index 22eaccca42d97..83179a51abc8f 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -52,8 +52,8 @@ construct_runtime! { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Pallet: pallet::{Pallet, Inherent}, + System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet expanded::{}::{Pallet, Inherent}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index 1705fff49dda8..b15a2d3349043 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -52,8 +52,8 @@ construct_runtime! { NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Pallet: pallet::{Pallet, Origin}, + System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, + Pallet: pallet expanded::{}::{Pallet, Origin}, } } diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 8f64d30940725..b5573d816eff2 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -1,6 +1,6 @@ use frame_support::construct_runtime; -use sp_runtime::{generic, traits::BlakeTwo256}; use sp_core::sr25519; +use sp_runtime::{generic, traits::BlakeTwo256}; #[frame_support::pallet] mod pallet { diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index 84f1e54d5c24e..211df67b70056 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -28,50 +28,54 @@ error[E0599]: no variant or associated item named `Pallet` found for enum `Runti | || -^^^^^^ variant or associated item not found in `RuntimeCall` | ||________| | | -57 | | } -58 | | } - | |__- variant or associated item `Pallet` not found for this enum +... | error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | -11 | pub struct Pallet(_); - | -------------------- function or associated item `pre_dispatch` not found for this struct +11 | pub struct Pallet(_); + | -------------------- function or associated item `pre_dispatch` not found for this struct ... -49 | construct_runtime! { - | _^ -50 | | pub struct Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, +49 | construct_runtime! { + | __^ + | | _| + | || +50 | || pub struct Runtime where +51 | || Block = Block, +52 | || NodeBlock = Block, +... || +57 | || } +58 | || } + | ||_- in this macro invocation ... | -57 | | } -58 | | } - | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `pre_dispatch`, perhaps you need to implement one of them: candidate #1: `SignedExtension` candidate #2: `ValidateUnsigned` - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `validate_unsigned` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | -11 | pub struct Pallet(_); - | -------------------- function or associated item `validate_unsigned` not found for this struct +11 | pub struct Pallet(_); + | -------------------- function or associated item `validate_unsigned` not found for this struct ... -49 | construct_runtime! { - | _^ -50 | | pub struct Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, +49 | construct_runtime! { + | __^ + | | _| + | || +50 | || pub struct Runtime where +51 | || Block = Block, +52 | || NodeBlock = Block, +... || +57 | || } +58 | || } + | ||_- in this macro invocation ... | -57 | | } -58 | | } - | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `validate_unsigned`, perhaps you need to implement one of them: candidate #1: `SignedExtension` candidate #2: `ValidateUnsigned` - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 0747753289af0..7918f93605e5c 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -419,6 +419,39 @@ fn error_expand() { ); } +#[test] +fn module_error_outer_enum_expand() { + // assert that all variants of the Example pallet are included into the + // RuntimeError definition. + match RuntimeError::Example(pallet::Error::InsufficientProposersBalance) { + RuntimeError::Example(example) => match example { + pallet::Error::InsufficientProposersBalance => (), + pallet::Error::NonExistentStorageValue => (), + // Extra pattern added by `construct_runtime`. + pallet::Error::__Ignore(_, _) => (), + }, + _ => (), + }; +} + +#[test] +fn module_error_from_dispatch_error() { + let dispatch_err = DispatchError::Module(ModuleError { + index: 1, + error: [0; 4], + message: Some("InsufficientProposersBalance"), + }); + let err = RuntimeError::from_dispatch_error(dispatch_err).unwrap(); + + match err { + RuntimeError::Example(pallet::Error::InsufficientProposersBalance) => (), + _ => panic!("Module error constructed incorrectly"), + }; + + // Only `ModuleError` is converted. + assert!(RuntimeError::from_dispatch_error(DispatchError::BadOrigin).is_none()); +} + #[test] fn instance_expand() { // assert same type diff --git a/frame/support/test/tests/pallet_outer_enums_explicit.rs b/frame/support/test/tests/pallet_outer_enums_explicit.rs new file mode 100644 index 0000000000000..dc98ec43fd933 --- /dev/null +++ b/frame/support/test/tests/pallet_outer_enums_explicit.rs @@ -0,0 +1,140 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::traits::ConstU32; + +mod common; + +use common::outer_enums::{pallet, pallet2}; + +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u32; + type RuntimeCall = RuntimeCall; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl common::outer_enums::pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +frame_support::construct_runtime!( + pub struct Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system::{Pallet, Config, Call, Event }, + + // This pallet exposes the Error type explicitly. + Example: common::outer_enums::pallet::{Pallet, Config, Event, Error}, + Instance1Example: common::outer_enums::pallet::::{ Pallet, Config, Event }, + + // This pallet does not mention the Error type, but it must be propagated (similarly to the polkadot/kusama). + Example2: common::outer_enums::pallet2::{Pallet, Config, Event }, + Instance1Example2: common::outer_enums::pallet2::::{Pallet, Config, Event}, + + // This pallet does not declare any errors. + Example3: common::outer_enums::pallet3::{Pallet, Config, Event}, + Instance1Example3: common::outer_enums::pallet3::::{Pallet, Config, Event}, + } +); + +#[test] +fn module_error_outer_enum_expand_explicit() { + // The Runtime has *all* parts explicitly defined. + + // Check that all error types are propagated + match RuntimeError::Example(pallet::Error::InsufficientProposersBalance) { + // Error passed implicitely to the pallet system. + RuntimeError::System(system) => match system { + frame_system::Error::InvalidSpecName => (), + frame_system::Error::SpecVersionNeedsToIncrease => (), + frame_system::Error::FailedToExtractRuntimeVersion => (), + frame_system::Error::NonDefaultComposite => (), + frame_system::Error::NonZeroRefCount => (), + frame_system::Error::CallFiltered => (), + frame_system::Error::__Ignore(_, _) => (), + }, + + // Error declared explicitly. + RuntimeError::Example(example) => match example { + pallet::Error::InsufficientProposersBalance => (), + pallet::Error::NonExistentStorageValue => (), + pallet::Error::__Ignore(_, _) => (), + }, + // Error declared explicitly. + RuntimeError::Instance1Example(example) => match example { + pallet::Error::InsufficientProposersBalance => (), + pallet::Error::NonExistentStorageValue => (), + pallet::Error::__Ignore(_, _) => (), + }, + + // Error must propagate even if not defined explicitly as pallet part. + RuntimeError::Example2(example) => match example { + pallet2::Error::OtherInsufficientProposersBalance => (), + pallet2::Error::OtherNonExistentStorageValue => (), + pallet2::Error::__Ignore(_, _) => (), + }, + // Error must propagate even if not defined explicitly as pallet part. + RuntimeError::Instance1Example2(example) => match example { + pallet2::Error::OtherInsufficientProposersBalance => (), + pallet2::Error::OtherNonExistentStorageValue => (), + pallet2::Error::__Ignore(_, _) => (), + }, + }; +} diff --git a/frame/support/test/tests/pallet_outer_enums_implicit.rs b/frame/support/test/tests/pallet_outer_enums_implicit.rs new file mode 100644 index 0000000000000..9a14538c35930 --- /dev/null +++ b/frame/support/test/tests/pallet_outer_enums_implicit.rs @@ -0,0 +1,140 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::traits::ConstU32; + +mod common; + +use common::outer_enums::{pallet, pallet2}; + +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u32; + type RuntimeCall = RuntimeCall; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU32<250>; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl common::outer_enums::pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} +impl common::outer_enums::pallet3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +frame_support::construct_runtime!( + pub struct Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system exclude_parts { Storage }, + + // Pallet exposes `Error` implicitely. + Example: common::outer_enums::pallet, + Instance1Example: common::outer_enums::pallet::, + + // Pallet exposes `Error` implicitely. + Example2: common::outer_enums::pallet2, + Instance1Example2: common::outer_enums::pallet2::, + + // Pallet does not implement error. + Example3: common::outer_enums::pallet3, + Instance1Example3: common::outer_enums::pallet3::, + } +); + +#[test] +fn module_error_outer_enum_expand_implicit() { + // The Runtime has *all* parts implicitly defined. + + // Check that all error types are propagated + match RuntimeError::Example(pallet::Error::InsufficientProposersBalance) { + // Error passed implicitely to the pallet system. + RuntimeError::System(system) => match system { + frame_system::Error::InvalidSpecName => (), + frame_system::Error::SpecVersionNeedsToIncrease => (), + frame_system::Error::FailedToExtractRuntimeVersion => (), + frame_system::Error::NonDefaultComposite => (), + frame_system::Error::NonZeroRefCount => (), + frame_system::Error::CallFiltered => (), + frame_system::Error::__Ignore(_, _) => (), + }, + + // Error declared explicitly. + RuntimeError::Example(example) => match example { + pallet::Error::InsufficientProposersBalance => (), + pallet::Error::NonExistentStorageValue => (), + pallet::Error::__Ignore(_, _) => (), + }, + // Error declared explicitly. + RuntimeError::Instance1Example(example) => match example { + pallet::Error::InsufficientProposersBalance => (), + pallet::Error::NonExistentStorageValue => (), + pallet::Error::__Ignore(_, _) => (), + }, + + // Error must propagate even if not defined explicitly as pallet part. + RuntimeError::Example2(example) => match example { + pallet2::Error::OtherInsufficientProposersBalance => (), + pallet2::Error::OtherNonExistentStorageValue => (), + pallet2::Error::__Ignore(_, _) => (), + }, + // Error must propagate even if not defined explicitly as pallet part. + RuntimeError::Instance1Example2(example) => match example { + pallet2::Error::OtherInsufficientProposersBalance => (), + pallet2::Error::OtherNonExistentStorageValue => (), + pallet2::Error::__Ignore(_, _) => (), + }, + }; +} diff --git a/primitives/metadata-ir/Cargo.toml b/primitives/metadata-ir/Cargo.toml index 955f9673e6c27..924fc08027563 100644 --- a/primitives/metadata-ir/Cargo.toml +++ b/primitives/metadata-ir/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -frame-metadata = { version = "15.1.0", default-features = false, features = ["v14", "v15-unstable"] } +frame-metadata = { version = "15.2.0", default-features = false, features = ["unstable"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-std = { version = "8.0.0", default-features = false, path = "../std" } diff --git a/primitives/metadata-ir/src/lib.rs b/primitives/metadata-ir/src/lib.rs index 3ddc2911d4c93..a932585a75ca9 100644 --- a/primitives/metadata-ir/src/lib.rs +++ b/primitives/metadata-ir/src/lib.rs @@ -85,6 +85,11 @@ mod test { }, ty: meta_type::<()>(), apis: vec![], + outer_enums: OuterEnumsIR { + call_enum_ty: meta_type::<()>(), + event_enum_ty: meta_type::<()>(), + error_enum_ty: meta_type::<()>(), + }, } } diff --git a/primitives/metadata-ir/src/types.rs b/primitives/metadata-ir/src/types.rs index 93ee54891d89f..76d9385cd3cbf 100644 --- a/primitives/metadata-ir/src/types.rs +++ b/primitives/metadata-ir/src/types.rs @@ -39,6 +39,8 @@ pub struct MetadataIR { pub ty: T::Type, /// Metadata of the Runtime API. pub apis: Vec>, + /// The outer enums types as found in the runtime. + pub outer_enums: OuterEnumsIR, } /// Metadata of a runtime trait. @@ -398,3 +400,40 @@ impl From for PalletErrorMetadataIR { Self { ty } } } + +/// The type of the outer enums. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct OuterEnumsIR { + /// The type of the outer `RuntimeCall` enum. + pub call_enum_ty: T::Type, + /// The type of the outer `RuntimeEvent` enum. + pub event_enum_ty: T::Type, + /// The module error type of the + /// [`DispatchError::Module`](https://docs.rs/sp-runtime/24.0.0/sp_runtime/enum.DispatchError.html#variant.Module) variant. + /// + /// The `Module` variant will be 5 scale encoded bytes which are normally decoded into + /// an `{ index: u8, error: [u8; 4] }` struct. This type ID points to an enum type which + /// instead interprets the first `index` byte as a pallet variant, and the remaining `error` + /// bytes as the appropriate `pallet::Error` type. It is an equally valid way to decode the + /// error bytes, and can be more informative. + /// + /// # Note + /// + /// - This type cannot be used directly to decode `sp_runtime::DispatchError` from the chain. + /// It provides just the information needed to decode `sp_runtime::DispatchError::Module`. + /// - Decoding the 5 error bytes into this type will not always lead to all of the bytes being + /// consumed; many error types do not require all of the bytes to represent them fully. + pub error_enum_ty: T::Type, +} + +impl IntoPortable for OuterEnumsIR { + type Output = OuterEnumsIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + OuterEnumsIR { + call_enum_ty: registry.register_type(&self.call_enum_ty), + event_enum_ty: registry.register_type(&self.event_enum_ty), + error_enum_ty: registry.register_type(&self.error_enum_ty), + } + } +} diff --git a/primitives/metadata-ir/src/v15.rs b/primitives/metadata-ir/src/v15.rs index 86441228d008e..814a5ae98372f 100644 --- a/primitives/metadata-ir/src/v15.rs +++ b/primitives/metadata-ir/src/v15.rs @@ -17,20 +17,17 @@ //! Convert the IR to V15 metadata. +use crate::OuterEnumsIR; + use super::types::{ - ExtrinsicMetadataIR, MetadataIR, PalletCallMetadataIR, PalletConstantMetadataIR, - PalletErrorMetadataIR, PalletEventMetadataIR, PalletMetadataIR, PalletStorageMetadataIR, - RuntimeApiMetadataIR, RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, - SignedExtensionMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, - StorageHasherIR, + ExtrinsicMetadataIR, MetadataIR, PalletMetadataIR, RuntimeApiMetadataIR, + RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, SignedExtensionMetadataIR, }; use frame_metadata::v15::{ - ExtrinsicMetadata, PalletCallMetadata, PalletConstantMetadata, PalletErrorMetadata, - PalletEventMetadata, PalletMetadata, PalletStorageMetadata, RuntimeApiMetadata, + CustomMetadata, ExtrinsicMetadata, OuterEnums, PalletMetadata, RuntimeApiMetadata, RuntimeApiMethodMetadata, RuntimeApiMethodParamMetadata, RuntimeMetadataV15, - SignedExtensionMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, - StorageHasher, + SignedExtensionMetadata, }; impl From for RuntimeMetadataV15 { @@ -40,6 +37,10 @@ impl From for RuntimeMetadataV15 { ir.extrinsic.into(), ir.ty, ir.apis.into_iter().map(Into::into).collect(), + ir.outer_enums.into(), + // Substrate does not collect yet the custom metadata fields. + // This allows us to extend the V15 easily. + CustomMetadata { map: Default::default() }, ) } } @@ -86,87 +87,6 @@ impl From for PalletMetadata { } } -impl From for StorageEntryModifier { - fn from(ir: StorageEntryModifierIR) -> Self { - match ir { - StorageEntryModifierIR::Optional => StorageEntryModifier::Optional, - StorageEntryModifierIR::Default => StorageEntryModifier::Default, - } - } -} - -impl From for StorageHasher { - fn from(ir: StorageHasherIR) -> Self { - match ir { - StorageHasherIR::Blake2_128 => StorageHasher::Blake2_128, - StorageHasherIR::Blake2_256 => StorageHasher::Blake2_256, - StorageHasherIR::Blake2_128Concat => StorageHasher::Blake2_128Concat, - StorageHasherIR::Twox128 => StorageHasher::Twox128, - StorageHasherIR::Twox256 => StorageHasher::Twox256, - StorageHasherIR::Twox64Concat => StorageHasher::Twox64Concat, - StorageHasherIR::Identity => StorageHasher::Identity, - } - } -} - -impl From for StorageEntryType { - fn from(ir: StorageEntryTypeIR) -> Self { - match ir { - StorageEntryTypeIR::Plain(ty) => StorageEntryType::Plain(ty), - StorageEntryTypeIR::Map { hashers, key, value } => StorageEntryType::Map { - hashers: hashers.into_iter().map(Into::into).collect(), - key, - value, - }, - } - } -} - -impl From for StorageEntryMetadata { - fn from(ir: StorageEntryMetadataIR) -> Self { - StorageEntryMetadata { - name: ir.name, - modifier: ir.modifier.into(), - ty: ir.ty.into(), - default: ir.default, - docs: ir.docs, - } - } -} - -impl From for PalletStorageMetadata { - fn from(ir: PalletStorageMetadataIR) -> Self { - PalletStorageMetadata { - prefix: ir.prefix, - entries: ir.entries.into_iter().map(Into::into).collect(), - } - } -} - -impl From for PalletCallMetadata { - fn from(ir: PalletCallMetadataIR) -> Self { - PalletCallMetadata { ty: ir.ty } - } -} - -impl From for PalletEventMetadata { - fn from(ir: PalletEventMetadataIR) -> Self { - PalletEventMetadata { ty: ir.ty } - } -} - -impl From for PalletConstantMetadata { - fn from(ir: PalletConstantMetadataIR) -> Self { - PalletConstantMetadata { name: ir.name, ty: ir.ty, value: ir.value, docs: ir.docs } - } -} - -impl From for PalletErrorMetadata { - fn from(ir: PalletErrorMetadataIR) -> Self { - PalletErrorMetadata { ty: ir.ty } - } -} - impl From for SignedExtensionMetadata { fn from(ir: SignedExtensionMetadataIR) -> Self { SignedExtensionMetadata { @@ -180,9 +100,23 @@ impl From for SignedExtensionMetadata { impl From for ExtrinsicMetadata { fn from(ir: ExtrinsicMetadataIR) -> Self { ExtrinsicMetadata { - ty: ir.ty, version: ir.version, signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), + // Note: These fields are populated by complementary PR: https://github.com/paritytech/substrate/pull/14123. + address_ty: ir.ty, + call_ty: ir.ty, + signature_ty: ir.ty, + extra_ty: ir.ty, + } + } +} + +impl From for OuterEnums { + fn from(ir: OuterEnumsIR) -> Self { + OuterEnums { + call_enum_ty: ir.call_enum_ty, + event_enum_ty: ir.event_enum_ty, + error_enum_ty: ir.error_enum_ty, } } }