From 76481c594653deddf7d2b2a1363446bab215d380 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Sat, 3 Jun 2023 18:05:23 +0530 Subject: [PATCH 01/19] Initial setup --- bin/node-template/runtime/src/lib.rs | 6 ++ .../src/construct_runtime_v2/expand/mod.rs | 38 +++++++ .../expand/runtime_struct.rs | 26 +++++ .../src/construct_runtime_v2/mod.rs | 33 +++++++ .../src/construct_runtime_v2/parse/helper.rs | 37 +++++++ .../src/construct_runtime_v2/parse/mod.rs | 99 +++++++++++++++++++ .../parse/runtime_struct.rs | 40 ++++++++ frame/support/procedural/src/lib.rs | 6 ++ frame/support/procedural/src/pallet/mod.rs | 2 +- frame/support/src/lib.rs | 2 +- 10 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/mod.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/mod.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/helper.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/mod.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index b32ea0d958100..ed9f59cdb7f30 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -294,6 +294,12 @@ construct_runtime!( } ); +#[frame_support::construct_runtime_v2] +mod runtime { + #[frame::runtime] + pub struct Runtime2; +} + /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs new file mode 100644 index 0000000000000..824be5387184b --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -0,0 +1,38 @@ +// 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. + +mod runtime_struct; + +use crate::construct_runtime_v2::Def; +use quote::ToTokens; + +pub fn expand(mut def: Def) -> proc_macro2::TokenStream { + let runtime_struct = runtime_struct::expand_runtime_struct(&mut def); + + let new_items = quote::quote!( + #runtime_struct + ); + + def.item + .content + .as_mut() + .expect("This is checked by parsing") + .1 + .push(syn::Item::Verbatim(new_items)); + + def.item.into_token_stream() +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs new file mode 100644 index 0000000000000..effb3b5c6b9bd --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs @@ -0,0 +1,26 @@ +// 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_v2::expand::Def; + +pub fn expand_runtime_struct(def: &mut Def) -> proc_macro2::TokenStream { + // let runtime_ident = &def.runtime_struct.runtime; + + quote::quote_spanned!(def.runtime_struct.attr_span => + // pub struct #runtime_ident; + ) +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/mod.rs b/frame/support/procedural/src/construct_runtime_v2/mod.rs new file mode 100644 index 0000000000000..b121a8f5de263 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/mod.rs @@ -0,0 +1,33 @@ +// 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 proc_macro::TokenStream; +pub use parse::Def; + +mod parse; +mod expand; + +pub fn construct_runtime( + attrs: TokenStream, + item: TokenStream, +) -> TokenStream { + let item = syn::parse_macro_input!(item as syn::ItemMod); + match parse::Def::try_from(item) { + Ok(def) => expand::expand(def).into(), + Err(e) => e.to_compile_error().into(), + } +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs b/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs new file mode 100644 index 0000000000000..7f7d7dd1fd029 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs @@ -0,0 +1,37 @@ +// 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::pallet::parse::helper::MutItemAttrs; +use quote::ToTokens; + +pub(crate) fn take_first_item_runtime_attr( + item: &mut impl MutItemAttrs, +) -> syn::Result> +where + Attr: syn::parse::Parse, +{ + let attrs = if let Some(attrs) = item.mut_item_attrs() { attrs } else { return Ok(None) }; + + if let Some(index) = attrs.iter().position(|attr| { + attr.path().segments.first().map_or(false, |segment| segment.ident == "frame") + }) { + let runtime_attr = attrs.remove(index); + Ok(Some(syn::parse2(runtime_attr.into_token_stream())?)) + } else { + Ok(None) + } +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs new file mode 100644 index 0000000000000..716454a1adb81 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -0,0 +1,99 @@ +// 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. + +pub mod runtime_struct; +pub mod helper; + +use syn::spanned::Spanned; +pub struct Def { + pub item: syn::ItemMod, + pub runtime_struct: runtime_struct::RuntimeStructDef, +} + +impl Def { + pub fn try_from(mut item: syn::ItemMod) -> syn::Result { + let item_span = item.span(); + let items = &mut item + .content + .as_mut() + .ok_or_else(|| { + let msg = "Invalid runtime definition, expected mod to be inlined."; + syn::Error::new(item_span, msg) + })? + .1; + + let mut runtime_struct = None; + + for (index, item) in items.iter_mut().enumerate() { + let runtime_attr: Option = helper::take_first_item_runtime_attr(item)?; + + match runtime_attr { + Some(RuntimeAttr::Runtime(span)) if runtime_struct.is_none() => { + let p = runtime_struct::RuntimeStructDef::try_from(span, index, item)?; + runtime_struct = Some(p); + }, + Some(attr) => { + let msg = "Invalid duplicated attribute"; + return Err(syn::Error::new(attr.span(), msg)) + }, + None => (), + } + } + + let def = Def { + item, + runtime_struct: runtime_struct + .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::runtime]`"))?, + }; + + Ok(def) + } +} + +mod keyword { + syn::custom_keyword!(frame); + syn::custom_keyword!(runtime); +} + +enum RuntimeAttr { + Runtime(proc_macro2::Span), +} + +impl RuntimeAttr { + fn span(&self) -> proc_macro2::Span { + match self { + Self::Runtime(span) => *span, + } + } +} + +impl syn::parse::Parse for RuntimeAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::runtime) { + Ok(RuntimeAttr::Runtime(content.parse::()?.span())) + } else { + Err(lookahead.error()) + } + } +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs new file mode 100644 index 0000000000000..f1371018a9d6a --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs @@ -0,0 +1,40 @@ +// 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 syn::spanned::Spanned; +pub struct RuntimeStructDef { + pub attr_span: proc_macro2::Span, +} + +impl RuntimeStructDef { + pub fn try_from( + attr_span: proc_macro2::Span, + index: usize, + item: &mut syn::Item, + ) -> syn::Result { + let item = if let syn::Item::Struct(item) = item { + item + } else { + let msg = "Invalid frame::runtime, expected struct definition"; + return Err(syn::Error::new(item.span(), msg)) + }; + + Ok(Self { + attr_span + }) + } +} \ No newline at end of file diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 84a8b37f92e06..a726dc5024278 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -22,6 +22,7 @@ mod benchmark; mod clone_no_bound; mod construct_runtime; +mod construct_runtime_v2; mod crate_version; mod debug_no_bound; mod default_no_bound; @@ -1738,3 +1739,8 @@ pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { pub fn composite_enum(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } + +#[proc_macro_attribute] +pub fn construct_runtime_v2(attr: TokenStream, item: TokenStream) -> TokenStream { + construct_runtime_v2::construct_runtime(attr, item) +} \ No newline at end of file diff --git a/frame/support/procedural/src/pallet/mod.rs b/frame/support/procedural/src/pallet/mod.rs index 3618711051d7f..42d8272fb23ed 100644 --- a/frame/support/procedural/src/pallet/mod.rs +++ b/frame/support/procedural/src/pallet/mod.rs @@ -26,7 +26,7 @@ //! to user defined types. And also crate new types and implement block. mod expand; -mod parse; +pub(crate) mod parse; pub use parse::{composite::keyword::CompositeKeyword, Def}; use syn::spanned::Spanned; diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 7800fd8bba8a5..57f308fd76efd 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -535,7 +535,7 @@ pub fn debug(data: &impl sp_std::fmt::Debug) { #[doc(inline)] pub use frame_support_procedural::{ - construct_runtime, decl_storage, match_and_insert, transactional, PalletError, + construct_runtime, construct_runtime_v2, decl_storage, match_and_insert, transactional, PalletError, RuntimeDebugNoBound, }; From 9b921e8be80b00540bdd806dc948ad98b993046b Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Sat, 3 Jun 2023 18:24:30 +0530 Subject: [PATCH 02/19] Adds runtime ident --- .../src/construct_runtime_v2/expand/mod.rs | 13 ++----------- .../construct_runtime_v2/expand/runtime_struct.rs | 4 ++-- .../construct_runtime_v2/parse/runtime_struct.rs | 2 ++ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index 824be5387184b..634f0d3a3da29 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -23,16 +23,7 @@ use quote::ToTokens; pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let runtime_struct = runtime_struct::expand_runtime_struct(&mut def); - let new_items = quote::quote!( + quote::quote!( #runtime_struct - ); - - def.item - .content - .as_mut() - .expect("This is checked by parsing") - .1 - .push(syn::Item::Verbatim(new_items)); - - def.item.into_token_stream() + ) } \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs index effb3b5c6b9bd..f0229f5c791b9 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs @@ -18,9 +18,9 @@ use crate::construct_runtime_v2::expand::Def; pub fn expand_runtime_struct(def: &mut Def) -> proc_macro2::TokenStream { - // let runtime_ident = &def.runtime_struct.runtime; + let runtime_ident = &def.runtime_struct.ident; quote::quote_spanned!(def.runtime_struct.attr_span => - // pub struct #runtime_ident; + pub struct #runtime_ident; ) } \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs index f1371018a9d6a..f3604ff7619b4 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs @@ -17,6 +17,7 @@ use syn::spanned::Spanned; pub struct RuntimeStructDef { + pub ident: syn::Ident, pub attr_span: proc_macro2::Span, } @@ -34,6 +35,7 @@ impl RuntimeStructDef { }; Ok(Self { + ident: item.ident.clone(), attr_span }) } From d50a686e4143d1639883f8f2697542f7d21b882d Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:41:48 +0530 Subject: [PATCH 03/19] Minor fix --- frame/support/procedural/src/construct_runtime_v2/expand/mod.rs | 2 +- .../src/construct_runtime_v2/expand/runtime_struct.rs | 2 +- frame/support/procedural/src/construct_runtime_v2/mod.rs | 2 +- .../support/procedural/src/construct_runtime_v2/parse/helper.rs | 2 +- frame/support/procedural/src/construct_runtime_v2/parse/mod.rs | 2 +- .../procedural/src/construct_runtime_v2/parse/runtime_struct.rs | 2 +- frame/support/procedural/src/lib.rs | 1 + 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index 634f0d3a3da29..ed38a0d9d160e 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -26,4 +26,4 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { quote::quote!( #runtime_struct ) -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs index f0229f5c791b9..57291412aa3d0 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs @@ -23,4 +23,4 @@ pub fn expand_runtime_struct(def: &mut Def) -> proc_macro2::TokenStream { quote::quote_spanned!(def.runtime_struct.attr_span => pub struct #runtime_ident; ) -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/construct_runtime_v2/mod.rs b/frame/support/procedural/src/construct_runtime_v2/mod.rs index b121a8f5de263..f69317f6e2c8c 100644 --- a/frame/support/procedural/src/construct_runtime_v2/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/mod.rs @@ -30,4 +30,4 @@ pub fn construct_runtime( Ok(def) => expand::expand(def).into(), Err(e) => e.to_compile_error().into(), } -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs b/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs index 7f7d7dd1fd029..b442370d3a68a 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/helper.rs @@ -34,4 +34,4 @@ where } else { Ok(None) } -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index 716454a1adb81..84a34e05011f9 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -96,4 +96,4 @@ impl syn::parse::Parse for RuntimeAttr { Err(lookahead.error()) } } -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs index f3604ff7619b4..f47721bdd6f85 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs @@ -39,4 +39,4 @@ impl RuntimeStructDef { attr_span }) } -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 812a439b4fd94..4be982acc2695 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -22,6 +22,7 @@ mod benchmark; mod clone_no_bound; mod construct_runtime; +mod construct_runtime_v2; mod crate_version; mod debug_no_bound; mod default_no_bound; From 70c93b11bb19e7e10225e8df5559e1ed3cd798d5 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Mon, 31 Jul 2023 10:32:57 +0530 Subject: [PATCH 04/19] Some more changes --- bin/node-template/runtime/src/lib.rs | 13 +++ .../procedural/src/construct_runtime/mod.rs | 4 +- .../procedural/src/construct_runtime/parse.rs | 4 +- .../src/construct_runtime_v2/expand/mod.rs | 20 +++- .../src/construct_runtime_v2/mod.rs | 8 +- .../src/construct_runtime_v2/parse/mod.rs | 107 +++++++++++++++++- .../src/construct_runtime_v2/parse/pallets.rs | 81 +++++++++++++ .../src/pallet/expand/tt_default_parts.rs | 48 ++++++++ 8 files changed, 275 insertions(+), 10 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 9539fef3205df..a62587c1d3267 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -294,6 +294,19 @@ construct_runtime!( mod runtime { #[frame::runtime] pub struct Runtime2; + + #[frame::pallets] + pub struct AllPallets { + System: frame_system, + // Timestamp: pallet_timestamp, + // Aura: pallet_aura, + // Grandpa: pallet_grandpa, + // Balances: pallet_balances, + // TransactionPayment: pallet_transaction_payment, + // Sudo: pallet_sudo, + // // Include the custom logic from the pallet-template in the runtime. + // TemplateModule: pallet_template, + } } /// The address format for describing accounts. diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index efc2244154479..9a86ace25c7f0 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -209,7 +209,7 @@ //! expose. mod expand; -mod parse; +pub mod parse; use cfg_expr::Predicate; use frame_support_procedural_tools::{ @@ -798,7 +798,7 @@ fn decl_static_assertions( } } -fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { +pub fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> { let max_pallet_num = { if cfg!(feature = "tuples-96") { 96 diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 9b08e16469754..fe663d4a586ab 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -627,7 +627,7 @@ impl Pallet { /// | Implicit | -> | Explicit | -> | ExplicitExpanded | /// +----------+ +----------+ +------------------+ /// ``` -enum PalletsConversion { +pub enum PalletsConversion { /// Pallets implicitely declare parts. /// /// `System: frame_system`. @@ -655,7 +655,7 @@ enum PalletsConversion { /// Check if all pallet have explicit declaration of their parts, if so then assign index to each /// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number /// incrementedly from last explicit or 0. -fn convert_pallets(pallets: Vec) -> syn::Result { +pub fn convert_pallets(pallets: Vec) -> syn::Result { if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { return Ok(PalletsConversion::Implicit(pallets)) } diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index ed38a0d9d160e..c1447bcff4fac 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -18,12 +18,24 @@ mod runtime_struct; use crate::construct_runtime_v2::Def; -use quote::ToTokens; +use crate::construct_runtime_v2::parse::pallets::AllPalletsDeclaration; pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let runtime_struct = runtime_struct::expand_runtime_struct(&mut def); - quote::quote!( - #runtime_struct - ) + match def.pallets { + (AllPalletsDeclaration::Implicit(decl), result) => { + println!("Implicit {}", result.clone()); + result + } + (AllPalletsDeclaration::Explicit(decl), result) => { + println!("Explicit"); + result + } + (AllPalletsDeclaration::ExplicitExpanded(decl), _) => { + quote::quote!( + #runtime_struct + ) + } + } } diff --git a/frame/support/procedural/src/construct_runtime_v2/mod.rs b/frame/support/procedural/src/construct_runtime_v2/mod.rs index f69317f6e2c8c..d610290803f4b 100644 --- a/frame/support/procedural/src/construct_runtime_v2/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/mod.rs @@ -21,11 +21,17 @@ pub use parse::Def; mod parse; mod expand; +use proc_macro2::TokenStream as TokenStream2; +use quote::ToTokens; + pub fn construct_runtime( attrs: TokenStream, item: TokenStream, ) -> TokenStream { - let item = syn::parse_macro_input!(item as syn::ItemMod); + // let item = syn::parse_macro_input!(item as syn::ItemMod); + let item: syn::ItemMod = syn::parse(item).unwrap(); + let input_main: TokenStream2 = item.to_token_stream().into(); + println!("input_main: {}", input_main); match parse::Def::try_from(item) { Ok(def) => expand::expand(def).into(), Err(e) => e.to_compile_error().into(), diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index 84a34e05011f9..e9d4df0a0fb32 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -16,16 +16,31 @@ // limitations under the License. pub mod runtime_struct; +pub mod pallets; pub mod helper; use syn::spanned::Spanned; +use syn::Result; +use quote::ToTokens; + +use self::pallets::AllPalletsDeclaration; +use crate::construct_runtime::check_pallet_number; +use crate::construct_runtime_v2::parse::pallets::{ImplicitAllPalletsDeclaration, ExplicitAllPalletsDeclaration}; +use frame_support_procedural_tools::{ + generate_crate_access, generate_crate_access_2018, generate_hidden_includes, +}; +use proc_macro2::TokenStream as TokenStream2; + pub struct Def { pub item: syn::ItemMod, pub runtime_struct: runtime_struct::RuntimeStructDef, + pub pallets: (pallets::AllPalletsDeclaration, TokenStream2), } impl Def { pub fn try_from(mut item: syn::ItemMod) -> syn::Result { + let input_main: TokenStream2 = item.to_token_stream().into(); + // println!("input_main: {}", input_main); let item_span = item.span(); let items = &mut item .content @@ -37,6 +52,7 @@ impl Def { .1; let mut runtime_struct = None; + let mut pallets = None; for (index, item) in items.iter_mut().enumerate() { let runtime_attr: Option = helper::take_first_item_runtime_attr(item)?; @@ -46,6 +62,30 @@ impl Def { let p = runtime_struct::RuntimeStructDef::try_from(span, index, item)?; runtime_struct = Some(p); }, + Some(RuntimeAttr::Pallets(span)) if pallets.is_none() => { + let input: TokenStream2 = item.to_token_stream().into(); + let input_copy = input_main.clone(); + let definition = syn::parse2::(input)?; + let res = match definition.clone() { + AllPalletsDeclaration::Implicit(implicit_def) => + check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()).and_then( + |_| construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def), + ), + AllPalletsDeclaration::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) + }), + AllPalletsDeclaration::ExplicitExpanded(explicit_decl) => + check_pallet_number(input_copy.clone().into(), explicit_decl.pallets.len()) + .and_then(|_| Ok(input_copy)), + }?; + // println!("definition: {:?}", definition); + // println!("res: {}", res); + // let p = syn::parse2::(res)?; + pallets = Some((definition, res)); + }, Some(attr) => { let msg = "Invalid duplicated attribute"; return Err(syn::Error::new(attr.span(), msg)) @@ -58,6 +98,8 @@ impl Def { item, runtime_struct: runtime_struct .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::runtime]`"))?, + pallets: pallets + .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::pallets]`"))?, }; Ok(def) @@ -67,16 +109,19 @@ impl Def { mod keyword { syn::custom_keyword!(frame); syn::custom_keyword!(runtime); + syn::custom_keyword!(pallets); } enum RuntimeAttr { Runtime(proc_macro2::Span), + Pallets(proc_macro2::Span), } impl RuntimeAttr { fn span(&self) -> proc_macro2::Span { match self { Self::Runtime(span) => *span, + Self::Pallets(span) => *span, } } } @@ -92,8 +137,68 @@ impl syn::parse::Parse for RuntimeAttr { let lookahead = content.lookahead1(); if lookahead.peek(keyword::runtime) { Ok(RuntimeAttr::Runtime(content.parse::()?.span())) - } else { + }else if lookahead.peek(keyword::pallets) { + Ok(RuntimeAttr::Pallets(content.parse::()?.span())) + } else { Err(lookahead.error()) } } } + +fn construct_runtime_implicit_to_explicit( + input: TokenStream2, + definition: ImplicitAllPalletsDeclaration, +) -> Result { + println!("construct_runtime_implicit_to_explicit"); + let frame_support = generate_crate_access_2018("frame-support")?; + let mut expansion = quote::quote!( + #[frame_support::construct_runtime_v2] + #input + ); + for pallet in definition.pallets.iter().filter(|pallet| pallet.pallet_parts.is_none()) { + 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_default_parts_v2 }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name: #pallet_path #pallet_instance }] + } + } + ); + } + + Ok(expansion) +} + +fn construct_runtime_explicit_to_explicit_expanded( + input: TokenStream2, + definition: ExplicitAllPalletsDeclaration, +) -> Result { + println!("construct_runtime_explicit_to_explicit_expanded"); + let frame_support = generate_crate_access_2018("frame-support")?; + let mut expansion = quote::quote!( + #[frame_support::construct_runtime_v2] + #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_v2 }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name: #pallet_path #pallet_instance }] + } + } + ); + } + + Ok(expansion) +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs new file mode 100644 index 0000000000000..cbef8fe2806a9 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -0,0 +1,81 @@ +// 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_procedural_tools::syn_ext as ext; +use syn::{Ident, Result, Token, token}; +use syn::parse::{Parse, ParseStream}; +use crate::construct_runtime::parse::{convert_pallets, PalletsConversion, PalletDeclaration, Pallet}; + +#[derive(Debug, Clone)] +pub enum AllPalletsDeclaration { + Implicit(ImplicitAllPalletsDeclaration), + Explicit(ExplicitAllPalletsDeclaration), + ExplicitExpanded(ExplicitAllPalletsDeclaration), +} + +/// Declaration of a runtime with some pallet with implicit declaration of parts. +#[derive(Debug, Clone)] +pub struct ImplicitAllPalletsDeclaration { + pub name: Ident, + pub pallets: Vec, +} + +/// Declaration of a runtime with all pallet having explicit declaration of parts. +#[derive(Debug, Clone)] +pub struct ExplicitAllPalletsDeclaration { + pub name: Ident, + pub pallets: Vec, + pub pallets_token: token::Brace, +} + +impl Parse for AllPalletsDeclaration { + fn parse(input: ParseStream) -> Result { + input.parse::()?; + + // Support either `enum` or `struct`. + if input.peek(Token![struct]) { + input.parse::()?; + } else { + input.parse::()?; + } + + let name = input.parse::()?; + let pallets = + input.parse::>>()?; + let pallets_token = pallets.token; + + match convert_pallets(pallets.content.inner.into_iter().collect())? { + PalletsConversion::Implicit(pallets) => + Ok(AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration { + name, + pallets, + })), + PalletsConversion::Explicit(pallets) => + Ok(AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { + name, + pallets, + pallets_token, + })), + PalletsConversion::ExplicitExpanded(pallets) => + Ok(AllPalletsDeclaration::ExplicitExpanded(ExplicitAllPalletsDeclaration { + name, + pallets, + pallets_token, + })), + } + } +} 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 356bdbf67e923..9677ecd318450 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -28,6 +28,10 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { 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 default_parts_unique_id_v2 = + syn::Ident::new(&format!("__tt_default_parts_v2_{}", count), def.item.span()); + let extra_parts_unique_id_v2 = + syn::Ident::new(&format!("__tt_extra_parts_v2_{}", count), def.item.span()); let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); @@ -138,5 +142,49 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { } pub use #extra_parts_unique_id as tt_extra_parts; + + #[macro_export] + #[doc(hidden)] + macro_rules! #default_parts_unique_id_v2 { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support)*::tt_return! { + $caller + tokens = [{ + ::Call + }] + } + }; + } + + pub use #default_parts_unique_id_v2 as tt_default_parts_v2; + + + // 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_v2 { + { + $caller:tt + frame_support = [{ $($frame_support:ident)::* }] + } => { + $($frame_support)*::tt_return! { + $caller + tokens = [{ + + }] + } + }; + } + + pub use #extra_parts_unique_id_v2 as tt_extra_parts_v2; ) } From 6f05e1fb04feaac5be4e4faf989fc31c0f9f98af Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Tue, 15 Aug 2023 19:17:44 +0530 Subject: [PATCH 05/19] Fixes recursive parsing --- bin/node-template/runtime/src/lib.rs | 19 + .../procedural/src/construct_runtime/mod.rs | 4 + .../src/construct_runtime_v2/expand/mod.rs | 4 +- .../src/construct_runtime_v2/mod.rs | 5 +- .../src/construct_runtime_v2/parse/mod.rs | 18 +- .../src/construct_runtime_v2/parse/pallets.rs | 627 +++++++++++++++++- .../src/pallet/expand/tt_default_parts.rs | 2 +- 7 files changed, 663 insertions(+), 16 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 310a8404bc2c5..721d2410c94fd 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -312,6 +312,25 @@ mod runtime { } } +// frame_support::tt_call!{ +// macro = [{ frame_system::tt_default_parts_v2 }] +// frame_support = [{ frame_support }] +// ~~> frame_support::match_and_insert! { +// target = +// [{ +// #[frame_support::construct_runtime_v2] +// mod runtime { +// #[frame::runtime] +// pub struct Runtime2; + +// #[frame::pallets] +// pub struct AllPallets { System : frame_system, } +// } +// }] +// pattern = [{ System : frame_system }] +// } +// } + /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 9a86ace25c7f0..5b474237343c5 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -230,6 +230,7 @@ const SYSTEM_PALLET_NAME: &str = "System"; /// `construct_runtime` again, or expand to the final runtime definition. pub fn construct_runtime(input: TokenStream) -> TokenStream { let input_copy = input.clone(); + println!("input_main_old: {}", input_copy.clone()); let definition = syn::parse_macro_input!(input as RuntimeDeclaration); let res = match definition { @@ -271,6 +272,7 @@ fn construct_runtime_implicit_to_explicit( input: TokenStream2, definition: ImplicitRuntimeDeclaration, ) -> Result { + println!("construct_runtime_implicit_to_explicit_old"); let frame_support = generate_crate_access_2018("frame-support")?; let mut expansion = quote::quote!( #frame_support::construct_runtime! { #input } @@ -307,6 +309,7 @@ fn construct_runtime_explicit_to_explicit_expanded( input: TokenStream2, definition: ExplicitRuntimeDeclaration, ) -> Result { + println!("construct_runtime_explicit_to_explicit_expanded_old"); let frame_support = generate_crate_access_2018("frame-support")?; let mut expansion = quote::quote!( #frame_support::construct_runtime! { #input } @@ -334,6 +337,7 @@ fn construct_runtime_explicit_to_explicit_expanded( fn construct_runtime_final_expansion( definition: ExplicitRuntimeDeclaration, ) -> Result { + println!("construct_runtime_final_old"); let ExplicitRuntimeDeclaration { name, pallets, pallets_token, where_section } = definition; let system_pallet = diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index c1447bcff4fac..8f9602f6c9d81 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -30,7 +30,9 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { } (AllPalletsDeclaration::Explicit(decl), result) => { println!("Explicit"); - result + quote::quote!( + #runtime_struct + ) } (AllPalletsDeclaration::ExplicitExpanded(decl), _) => { quote::quote!( diff --git a/frame/support/procedural/src/construct_runtime_v2/mod.rs b/frame/support/procedural/src/construct_runtime_v2/mod.rs index d610290803f4b..737edc3a8cf9a 100644 --- a/frame/support/procedural/src/construct_runtime_v2/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/mod.rs @@ -28,10 +28,7 @@ pub fn construct_runtime( attrs: TokenStream, item: TokenStream, ) -> TokenStream { - // let item = syn::parse_macro_input!(item as syn::ItemMod); - let item: syn::ItemMod = syn::parse(item).unwrap(); - let input_main: TokenStream2 = item.to_token_stream().into(); - println!("input_main: {}", input_main); + let item = syn::parse_macro_input!(item as syn::ItemMod); match parse::Def::try_from(item) { Ok(def) => expand::expand(def).into(), Err(e) => e.to_compile_error().into(), diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index e9d4df0a0fb32..a30f8850a9f80 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -40,7 +40,7 @@ pub struct Def { impl Def { pub fn try_from(mut item: syn::ItemMod) -> syn::Result { let input_main: TokenStream2 = item.to_token_stream().into(); - // println!("input_main: {}", input_main); + println!("input_main: {}", input_main); let item_span = item.span(); let items = &mut item .content @@ -64,7 +64,7 @@ impl Def { }, Some(RuntimeAttr::Pallets(span)) if pallets.is_none() => { let input: TokenStream2 = item.to_token_stream().into(); - let input_copy = input_main.clone(); + let input_copy: TokenStream2 = input_main.clone(); let definition = syn::parse2::(input)?; let res = match definition.clone() { AllPalletsDeclaration::Implicit(implicit_def) => @@ -74,16 +74,20 @@ impl Def { AllPalletsDeclaration::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) - }), + ).and_then( + |_| Ok(input_copy) + // |_| { + // construct_runtime_explicit_to_explicit_expanded(input_copy.into(), explicit_decl) + // } + ), AllPalletsDeclaration::ExplicitExpanded(explicit_decl) => check_pallet_number(input_copy.clone().into(), explicit_decl.pallets.len()) .and_then(|_| Ok(input_copy)), }?; // println!("definition: {:?}", definition); - // println!("res: {}", res); - // let p = syn::parse2::(res)?; + println!("res: {}", res); + // let p = syn::parse2::(res)?; + // let res = quote::quote!(); pallets = Some((definition, res)); }, Some(attr) => { diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index cbef8fe2806a9..bb4860c3dbe87 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -16,9 +16,39 @@ // limitations under the License. use frame_support_procedural_tools::syn_ext as ext; -use syn::{Ident, Result, Token, token}; -use syn::parse::{Parse, ParseStream}; -use crate::construct_runtime::parse::{convert_pallets, PalletsConversion, PalletDeclaration, Pallet}; +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; +use std::collections::{HashMap, HashSet}; +use syn::{ + ext::IdentExt, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + spanned::Spanned, + token, Attribute, Error, Ident, Path, Result, Token, +}; +use crate::construct_runtime::parse::{WhereDefinition, WhereKind}; + +mod keyword { + syn::custom_keyword!(Block); + syn::custom_keyword!(NodeBlock); + syn::custom_keyword!(UncheckedExtrinsic); + syn::custom_keyword!(Pallet); + 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); + syn::custom_keyword!(ValidateUnsigned); + syn::custom_keyword!(FreezeReason); + syn::custom_keyword!(HoldReason); + syn::custom_keyword!(LockId); + syn::custom_keyword!(SlashReason); + syn::custom_keyword!(exclude_parts); + syn::custom_keyword!(use_parts); + syn::custom_keyword!(expanded); +} #[derive(Debug, Clone)] pub enum AllPalletsDeclaration { @@ -79,3 +109,594 @@ impl Parse for AllPalletsDeclaration { } } } + +/// 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. + pub attrs: Vec, + /// Optional fixed index, e.g. `MyPallet ... = 3,`. + pub index: Option, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: PalletPath, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, + /// The declared pallet parts, + /// e.g. `Some([Pallet, Call])` for `System: system::{Pallet, Call}` + /// or `None` for `System: system`. + pub pallet_parts: Option>, + /// The specified parts, either use_parts or exclude_parts. + pub specified_parts: SpecifiedParts, +} + +/// The possible declaration of pallet parts to use. +#[derive(Debug, Clone)] +pub enum SpecifiedParts { + /// Use all the pallet parts except those specified. + Exclude(Vec), + /// Use only the specified pallet parts. + Use(Vec), + /// Use the all the pallet parts. + All, +} + +impl Parse for PalletDeclaration { + fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + + let name = input.parse()?; + let _: Token![:] = input.parse()?; + let path = input.parse()?; + // println!("path: {:?}", path); + + // // Parse for instance. + // let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { + // let _: Token![::] = input.parse()?; + // let _: Token![<] = input.parse()?; + // let res = Some(input.parse()?); + // let _: Token![>] = input.parse()?; + // res + // } else if !(input.peek(Token![+])) && + // !input.peek(keyword::expanded) && + // !input.peek(keyword::exclude_parts) && + // !input.peek(keyword::use_parts) && + // !input.peek(Token![=]) && + // !input.peek(Token![,]) && + // !input.is_empty() + // { + // return Err(input.error( + // "Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`", + // )); + // } else { + // None + // }; + let instance = 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![]) + // }; + + let (is_expanded, extra_parts) = (false, vec![]); + + // Parse for explicit parts + let pallet_parts = if input.peek(Token![+]) { + let _: Token![+] = input.parse()?; + 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![=]) && + !input.peek(Token![,]) && + !input.is_empty() + { + return Err(input.error( + "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", + )) + } else { + is_expanded.then_some(extra_parts) + }; + + // Parse for specified parts + // let specified_parts = if input.peek(keyword::exclude_parts) { + // let _: keyword::exclude_parts = input.parse()?; + // SpecifiedParts::Exclude(parse_pallet_parts_no_generic(input)?) + // } else if input.peek(keyword::use_parts) { + // let _: keyword::use_parts = input.parse()?; + // SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?) + // } else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() { + // return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")) + // } else { + // SpecifiedParts::All + // }; + + let specified_parts = SpecifiedParts::All; + + + // Parse for pallet index + // let index = if input.peek(Token![=]) { + // input.parse::()?; + // let index = input.parse::()?; + // let index = index.base10_parse::()?; + // Some(index) + // } else if !input.peek(Token![,]) && !input.is_empty() { + // return Err(input.error("Unexpected tokens, expected one of `=`, `,`")) + // } else { + // None + // }; + let index = None; + + Ok(Self { is_expanded, attrs, name, path, instance, pallet_parts, specified_parts, index }) + } +} + +/// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard +/// Rust path with a few restrictions: +/// - No leading colons allowed +/// - Path segments can only consist of identifers separated by colons +#[derive(Debug, Clone)] +pub struct PalletPath { + pub inner: Path, +} + +impl PalletPath { + pub fn module_name(&self) -> String { + self.inner.segments.iter().fold(String::new(), |mut acc, segment| { + if !acc.is_empty() { + acc.push_str("::"); + } + acc.push_str(&segment.ident.to_string()); + acc + }) + } +} + +impl Parse for PalletPath { + fn parse(input: ParseStream) -> Result { + let mut res = + PalletPath { inner: Path { leading_colon: None, segments: Punctuated::new() } }; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![crate]) || + lookahead.peek(Token![self]) || + lookahead.peek(Token![super]) || + lookahead.peek(Ident) + { + let ident = input.call(Ident::parse_any)?; + res.inner.segments.push(ident.into()); + } else { + return Err(lookahead.error()) + } + + while input.peek(Token![::]) && input.peek3(Ident) { + input.parse::()?; + let ident = input.parse::()?; + res.inner.segments.push(ident.into()); + } + Ok(res) + } +} + +impl quote::ToTokens for PalletPath { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.inner.to_tokens(tokens); + } +} + +/// Parse [`PalletPart`]'s from a braces enclosed list that is split by commas, e.g. +/// +/// `{ Call, Event }` +fn parse_pallet_parts(input: ParseStream) -> Result> { + // let pallet_parts: ext::Punctuated = input.parse()?; + let pallet_parts = Punctuated::::parse_separated_nonempty(&input)?; + + let mut resolved = HashSet::new(); + for part in pallet_parts.iter() { + if !resolved.insert(part.name()) { + let msg = format!( + "`{}` was already declared before. Please remove the duplicate declaration", + part.name(), + ); + return Err(Error::new(part.keyword.span(), msg)) + } + } + + Ok(pallet_parts.into_iter().collect()) +} + +#[derive(Debug, Clone)] +pub enum PalletPartKeyword { + Pallet(keyword::Pallet), + Call(keyword::Call), + Storage(keyword::Storage), + Event(keyword::Event), + Error(keyword::Error), + Config(keyword::Config), + Origin(keyword::Origin), + Inherent(keyword::Inherent), + ValidateUnsigned(keyword::ValidateUnsigned), + FreezeReason(keyword::FreezeReason), + HoldReason(keyword::HoldReason), + LockId(keyword::LockId), + SlashReason(keyword::SlashReason), +} + +impl Parse for PalletPartKeyword { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::Pallet) { + Ok(Self::Pallet(input.parse()?)) + } else if lookahead.peek(keyword::Call) { + Ok(Self::Call(input.parse()?)) + } else if lookahead.peek(keyword::Storage) { + 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) { + Ok(Self::Origin(input.parse()?)) + } else if lookahead.peek(keyword::Inherent) { + Ok(Self::Inherent(input.parse()?)) + } else if lookahead.peek(keyword::ValidateUnsigned) { + Ok(Self::ValidateUnsigned(input.parse()?)) + } else if lookahead.peek(keyword::FreezeReason) { + Ok(Self::FreezeReason(input.parse()?)) + } else if lookahead.peek(keyword::HoldReason) { + Ok(Self::HoldReason(input.parse()?)) + } else if lookahead.peek(keyword::LockId) { + Ok(Self::LockId(input.parse()?)) + } else if lookahead.peek(keyword::SlashReason) { + Ok(Self::SlashReason(input.parse()?)) + } else { + Err(lookahead.error()) + } + } +} + +impl PalletPartKeyword { + /// Returns the name of `Self`. + fn name(&self) -> &'static str { + match self { + Self::Pallet(_) => "Pallet", + Self::Call(_) => "Call", + Self::Storage(_) => "Storage", + Self::Event(_) => "Event", + Self::Error(_) => "Error", + Self::Config(_) => "Config", + Self::Origin(_) => "Origin", + Self::Inherent(_) => "Inherent", + Self::ValidateUnsigned(_) => "ValidateUnsigned", + Self::FreezeReason(_) => "FreezeReason", + Self::HoldReason(_) => "HoldReason", + Self::LockId(_) => "LockId", + Self::SlashReason(_) => "SlashReason", + } + } + + /// Returns `true` if this pallet part is allowed to have generic arguments. + fn allows_generic(&self) -> bool { + Self::all_generic_arg().iter().any(|n| *n == self.name()) + } + + /// Returns the names of all pallet parts that allow to have a generic argument. + fn all_generic_arg() -> &'static [&'static str] { + &["Event", "Error", "Origin", "Config"] + } +} + +impl ToTokens for PalletPartKeyword { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Pallet(inner) => inner.to_tokens(tokens), + 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), + Self::ValidateUnsigned(inner) => inner.to_tokens(tokens), + Self::FreezeReason(inner) => inner.to_tokens(tokens), + Self::HoldReason(inner) => inner.to_tokens(tokens), + Self::LockId(inner) => inner.to_tokens(tokens), + Self::SlashReason(inner) => inner.to_tokens(tokens), + } + } +} + +#[derive(Debug, Clone)] +pub struct PalletPart { + pub keyword: PalletPartKeyword, + pub generics: syn::Generics, +} + +impl Parse for PalletPart { + fn parse(input: ParseStream) -> Result { + let keyword: PalletPartKeyword = input.parse()?; + + let generics: syn::Generics = input.parse()?; + if !generics.params.is_empty() && !keyword.allows_generic() { + let valid_generics = PalletPart::format_names(PalletPartKeyword::all_generic_arg()); + let msg = format!( + "`{}` is not allowed to have generics. \ + Only the following pallets are allowed to have generics: {}.", + keyword.name(), + valid_generics, + ); + return Err(syn::Error::new(keyword.span(), msg)) + } + + Ok(Self { keyword, generics }) + } +} + +impl PalletPart { + pub fn format_names(names: &[&'static str]) -> String { + let res: Vec<_> = names.iter().map(|s| format!("`{}`", s)).collect(); + res.join(", ") + } + + /// The name of this pallet part. + pub fn name(&self) -> &'static str { + self.keyword.name() + } +} + +fn remove_kind( + input: ParseStream, + kind: WhereKind, + definitions: &mut Vec, +) -> Result { + if let Some(pos) = definitions.iter().position(|d| d.kind == kind) { + Ok(definitions.remove(pos)) + } else { + let msg = format!( + "Missing associated type for `{:?}`. Add `{:?}` = ... to where section.", + kind, kind + ); + Err(input.error(msg)) + } +} + +/// The declaration of a part without its generics +#[derive(Debug, Clone)] +pub struct PalletPartNoGeneric { + keyword: PalletPartKeyword, +} + +impl Parse for PalletPartNoGeneric { + fn parse(input: ParseStream) -> Result { + Ok(Self { keyword: input.parse()? }) + } +} + +/// Parse [`PalletPartNoGeneric`]'s from a braces enclosed list that is split by commas, e.g. +/// +/// `{ Call, Event }` +fn parse_pallet_parts_no_generic(input: ParseStream) -> Result> { + let pallet_parts: ext::Braces> = + input.parse()?; + + let mut resolved = HashSet::new(); + for part in pallet_parts.content.inner.iter() { + if !resolved.insert(part.keyword.name()) { + let msg = format!( + "`{}` was already declared before. Please remove the duplicate declaration", + part.keyword.name(), + ); + return Err(Error::new(part.keyword.span(), msg)) + } + } + + Ok(pallet_parts.content.inner.into_iter().collect()) +} + +/// The final definition of a pallet with the resulting fixed index and explicit parts. +#[derive(Debug, Clone)] +pub struct Pallet { + /// Is this pallet fully expanded? + pub is_expanded: bool, + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Either automatically infered, or defined (e.g. `MyPallet ... = 3,`). + pub index: u8, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: PalletPath, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, + /// The pallet parts to use for the pallet. + pub pallet_parts: Vec, + /// Expressions specified inside of a #[cfg] attribute. + pub cfg_pattern: Vec, +} + +impl Pallet { + /// Get resolved pallet parts + pub fn pallet_parts(&self) -> &[PalletPart] { + &self.pallet_parts + } + + /// Find matching parts + pub fn find_part(&self, name: &str) -> Option<&PalletPart> { + self.pallet_parts.iter().find(|part| part.name() == name) + } + + /// Return whether pallet contains part + pub fn exists_part(&self, name: &str) -> bool { + self.find_part(name).is_some() + } +} + +/// Result of a conversion of a declaration of pallets. +/// +/// # State Transitions +/// +/// ```ignore +/// +----------+ +----------+ +------------------+ +/// | Implicit | -> | Explicit | -> | ExplicitExpanded | +/// +----------+ +----------+ +------------------+ +/// ``` +pub 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. +/// +/// Check if all pallet have explicit declaration of their parts, if so then assign index to each +/// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number +/// incrementedly from last explicit or 0. +pub fn convert_pallets(pallets: Vec) -> syn::Result { + if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { + return Ok(PalletsConversion::Implicit(pallets)) + } + + let mut indices = HashMap::new(); + let mut last_index: Option = None; + let mut names = HashMap::new(); + let mut is_expanded = true; + + let pallets = pallets + .into_iter() + .map(|pallet| { + let final_index = match pallet.index { + Some(i) => i, + None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| { + let msg = "Pallet index doesn't fit into u8, index is 256"; + syn::Error::new(pallet.name.span(), msg) + })?, + }; + + last_index = Some(final_index); + + if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) { + let msg = format!( + "Pallet indices are conflicting: Both pallets {} and {} are at index {}", + used_pallet, pallet.name, final_index, + ); + let mut err = syn::Error::new(used_pallet.span(), &msg); + err.combine(syn::Error::new(pallet.name.span(), msg)); + return Err(err) + } + + if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { + let msg = "Two pallets with the same name!"; + + let mut err = syn::Error::new(used_pallet, &msg); + err.combine(syn::Error::new(pallet.name.span(), &msg)); + return Err(err) + } + + let mut pallet_parts = pallet.pallet_parts.expect("Checked above"); + + let available_parts = + pallet_parts.iter().map(|part| part.keyword.name()).collect::>(); + + // Check parts are correctly specified + match &pallet.specified_parts { + SpecifiedParts::Exclude(parts) | SpecifiedParts::Use(parts) => + for part in parts { + if !available_parts.contains(part.keyword.name()) { + let msg = format!( + "Invalid pallet part specified, the pallet `{}` doesn't have the \ + `{}` part. Available parts are: {}.", + pallet.name, + part.keyword.name(), + pallet_parts.iter().fold(String::new(), |fold, part| { + if fold.is_empty() { + format!("`{}`", part.keyword.name()) + } else { + format!("{}, `{}`", fold, part.keyword.name()) + } + }) + ); + return Err(syn::Error::new(part.keyword.span(), msg)) + } + }, + SpecifiedParts::All => (), + } + + // Set only specified parts. + match pallet.specified_parts { + SpecifiedParts::Exclude(excluded_parts) => pallet_parts.retain(|part| { + !excluded_parts + .iter() + .any(|excluded_part| excluded_part.keyword.name() == part.keyword.name()) + }), + SpecifiedParts::Use(used_parts) => pallet_parts.retain(|part| { + used_parts.iter().any(|use_part| use_part.keyword.name() == part.keyword.name()) + }), + SpecifiedParts::All => (), + } + + let cfg_pattern = pallet + .attrs + .iter() + .map(|attr| { + if attr.path().segments.first().map_or(false, |s| s.ident != "cfg") { + let msg = "Unsupported attribute, only #[cfg] is supported on pallet \ + declarations in `construct_runtime`"; + return Err(syn::Error::new(attr.span(), msg)) + } + + attr.parse_args_with(|input: syn::parse::ParseStream| { + // Required, otherwise the parse stream doesn't advance and will result in + // an error. + let input = input.parse::()?; + cfg_expr::Expression::parse(&input.to_string()) + .map_err(|e| syn::Error::new(attr.span(), e.to_string())) + }) + }) + .collect::>>()?; + + is_expanded &= pallet.is_expanded; + + Ok(Pallet { + is_expanded: pallet.is_expanded, + name: pallet.name, + index: final_index, + path: pallet.path, + instance: pallet.instance, + cfg_pattern, + pallet_parts, + }) + }) + .collect::>>()?; + + 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 9677ecd318450..92766c9cef9dc 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -153,7 +153,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { $($frame_support)*::tt_return! { $caller tokens = [{ - ::Call + + Pallet + Call }] } }; From 0010b1f86899f115ac46465cf6279d0e3fbe5c90 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:28:20 +0530 Subject: [PATCH 06/19] Starts to get things in order --- bin/node-template/runtime/src/lib.rs | 16 +++--- .../src/construct_runtime_v2/expand/mod.rs | 5 -- .../src/construct_runtime_v2/parse/mod.rs | 45 +--------------- .../src/construct_runtime_v2/parse/pallets.rs | 51 ++----------------- 4 files changed, 14 insertions(+), 103 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 721d2410c94fd..74252b9b965f7 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -301,14 +301,14 @@ mod runtime { #[frame::pallets] pub struct AllPallets { System: frame_system, - // Timestamp: pallet_timestamp, - // Aura: pallet_aura, - // Grandpa: pallet_grandpa, - // Balances: pallet_balances, - // TransactionPayment: pallet_transaction_payment, - // Sudo: pallet_sudo, - // // Include the custom logic from the pallet-template in the runtime. - // TemplateModule: pallet_template, + Timestamp: pallet_timestamp, + Aura: pallet_aura, + Grandpa: pallet_grandpa, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + Sudo: pallet_sudo, + // Include the custom logic from the pallet-template in the runtime. + TemplateModule: pallet_template, } } diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index 8f9602f6c9d81..dff47fbaa076d 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -34,10 +34,5 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { #runtime_struct ) } - (AllPalletsDeclaration::ExplicitExpanded(decl), _) => { - quote::quote!( - #runtime_struct - ) - } } } diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index a30f8850a9f80..a0c9eb8ab1f02 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -71,23 +71,10 @@ impl Def { check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()).and_then( |_| construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def), ), - AllPalletsDeclaration::Explicit(explicit_decl) => check_pallet_number( - input_copy.clone().into(), - explicit_decl.pallets.len(), - ).and_then( - |_| Ok(input_copy) - // |_| { - // construct_runtime_explicit_to_explicit_expanded(input_copy.into(), explicit_decl) - // } - ), - AllPalletsDeclaration::ExplicitExpanded(explicit_decl) => + AllPalletsDeclaration::Explicit(explicit_decl) => check_pallet_number(input_copy.clone().into(), explicit_decl.pallets.len()) .and_then(|_| Ok(input_copy)), }?; - // println!("definition: {:?}", definition); - println!("res: {}", res); - // let p = syn::parse2::(res)?; - // let res = quote::quote!(); pallets = Some((definition, res)); }, Some(attr) => { @@ -153,7 +140,6 @@ fn construct_runtime_implicit_to_explicit( input: TokenStream2, definition: ImplicitAllPalletsDeclaration, ) -> Result { - println!("construct_runtime_implicit_to_explicit"); let frame_support = generate_crate_access_2018("frame-support")?; let mut expansion = quote::quote!( #[frame_support::construct_runtime_v2] @@ -177,32 +163,3 @@ fn construct_runtime_implicit_to_explicit( Ok(expansion) } - -fn construct_runtime_explicit_to_explicit_expanded( - input: TokenStream2, - definition: ExplicitAllPalletsDeclaration, -) -> Result { - println!("construct_runtime_explicit_to_explicit_expanded"); - let frame_support = generate_crate_access_2018("frame-support")?; - let mut expansion = quote::quote!( - #[frame_support::construct_runtime_v2] - #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_v2 }] - frame_support = [{ #frame_support }] - ~~> #frame_support::match_and_insert! { - target = [{ #expansion }] - pattern = [{ #pallet_name: #pallet_path #pallet_instance }] - } - } - ); - } - - Ok(expansion) -} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index bb4860c3dbe87..499b9609cf38e 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -26,12 +26,8 @@ use syn::{ spanned::Spanned, token, Attribute, Error, Ident, Path, Result, Token, }; -use crate::construct_runtime::parse::{WhereDefinition, WhereKind}; mod keyword { - syn::custom_keyword!(Block); - syn::custom_keyword!(NodeBlock); - syn::custom_keyword!(UncheckedExtrinsic); syn::custom_keyword!(Pallet); syn::custom_keyword!(Call); syn::custom_keyword!(Storage); @@ -47,14 +43,12 @@ mod keyword { syn::custom_keyword!(SlashReason); syn::custom_keyword!(exclude_parts); syn::custom_keyword!(use_parts); - syn::custom_keyword!(expanded); } #[derive(Debug, Clone)] pub enum AllPalletsDeclaration { Implicit(ImplicitAllPalletsDeclaration), Explicit(ExplicitAllPalletsDeclaration), - ExplicitExpanded(ExplicitAllPalletsDeclaration), } /// Declaration of a runtime with some pallet with implicit declaration of parts. @@ -100,12 +94,6 @@ impl Parse for AllPalletsDeclaration { pallets, pallets_token, })), - PalletsConversion::ExplicitExpanded(pallets) => - Ok(AllPalletsDeclaration::ExplicitExpanded(ExplicitAllPalletsDeclaration { - name, - pallets, - pallets_token, - })), } } } @@ -455,22 +443,6 @@ impl PalletPart { } } -fn remove_kind( - input: ParseStream, - kind: WhereKind, - definitions: &mut Vec, -) -> Result { - if let Some(pos) = definitions.iter().position(|d| d.kind == kind) { - Ok(definitions.remove(pos)) - } else { - let msg = format!( - "Missing associated type for `{:?}`. Add `{:?}` = ... to where section.", - kind, kind - ); - Err(input.error(msg)) - } -} - /// The declaration of a part without its generics #[derive(Debug, Clone)] pub struct PalletPartNoGeneric { @@ -545,9 +517,9 @@ impl Pallet { /// # State Transitions /// /// ```ignore -/// +----------+ +----------+ +------------------+ -/// | Implicit | -> | Explicit | -> | ExplicitExpanded | -/// +----------+ +----------+ +------------------+ +/// +----------+ +----------+ +/// | Implicit | -> | Explicit | +/// +----------+ +----------+ /// ``` pub enum PalletsConversion { /// Pallets implicitely declare parts. @@ -556,20 +528,11 @@ pub enum PalletsConversion { Implicit(Vec), /// Pallets explicitly declare parts. /// - /// `System: frame_system::{Pallet, Call}` + /// `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. @@ -694,9 +657,5 @@ pub fn convert_pallets(pallets: Vec) -> syn::Result>>()?; - if is_expanded { - Ok(PalletsConversion::ExplicitExpanded(pallets)) - } else { - Ok(PalletsConversion::Explicit(pallets)) - } + Ok(PalletsConversion::Explicit(pallets)) } From 5f8d5cd555e805e6566521eedcb94627fa205495 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:35:41 +0530 Subject: [PATCH 07/19] Removes changes in older macro --- .../procedural/src/construct_runtime/mod.rs | 6 +--- .../procedural/src/construct_runtime/parse.rs | 4 +-- .../src/construct_runtime_v2/expand/mod.rs | 7 +++-- .../src/construct_runtime_v2/parse/pallets.rs | 4 +-- .../src/pallet/expand/tt_default_parts.rs | 28 ------------------- 5 files changed, 9 insertions(+), 40 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 5b474237343c5..794042e37b79a 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -209,7 +209,7 @@ //! expose. mod expand; -pub mod parse; +mod parse; use cfg_expr::Predicate; use frame_support_procedural_tools::{ @@ -230,7 +230,6 @@ const SYSTEM_PALLET_NAME: &str = "System"; /// `construct_runtime` again, or expand to the final runtime definition. pub fn construct_runtime(input: TokenStream) -> TokenStream { let input_copy = input.clone(); - println!("input_main_old: {}", input_copy.clone()); let definition = syn::parse_macro_input!(input as RuntimeDeclaration); let res = match definition { @@ -272,7 +271,6 @@ fn construct_runtime_implicit_to_explicit( input: TokenStream2, definition: ImplicitRuntimeDeclaration, ) -> Result { - println!("construct_runtime_implicit_to_explicit_old"); let frame_support = generate_crate_access_2018("frame-support")?; let mut expansion = quote::quote!( #frame_support::construct_runtime! { #input } @@ -309,7 +307,6 @@ fn construct_runtime_explicit_to_explicit_expanded( input: TokenStream2, definition: ExplicitRuntimeDeclaration, ) -> Result { - println!("construct_runtime_explicit_to_explicit_expanded_old"); let frame_support = generate_crate_access_2018("frame-support")?; let mut expansion = quote::quote!( #frame_support::construct_runtime! { #input } @@ -337,7 +334,6 @@ fn construct_runtime_explicit_to_explicit_expanded( fn construct_runtime_final_expansion( definition: ExplicitRuntimeDeclaration, ) -> Result { - println!("construct_runtime_final_old"); let ExplicitRuntimeDeclaration { name, pallets, pallets_token, where_section } = definition; let system_pallet = diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index fe663d4a586ab..9b08e16469754 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -627,7 +627,7 @@ impl Pallet { /// | Implicit | -> | Explicit | -> | ExplicitExpanded | /// +----------+ +----------+ +------------------+ /// ``` -pub enum PalletsConversion { +enum PalletsConversion { /// Pallets implicitely declare parts. /// /// `System: frame_system`. @@ -655,7 +655,7 @@ pub enum PalletsConversion { /// Check if all pallet have explicit declaration of their parts, if so then assign index to each /// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number /// incrementedly from last explicit or 0. -pub fn convert_pallets(pallets: Vec) -> syn::Result { +fn convert_pallets(pallets: Vec) -> syn::Result { if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { return Ok(PalletsConversion::Implicit(pallets)) } diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index dff47fbaa076d..69a369730c492 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -21,15 +21,16 @@ use crate::construct_runtime_v2::Def; use crate::construct_runtime_v2::parse::pallets::AllPalletsDeclaration; pub fn expand(mut def: Def) -> proc_macro2::TokenStream { - let runtime_struct = runtime_struct::expand_runtime_struct(&mut def); - match def.pallets { (AllPalletsDeclaration::Implicit(decl), result) => { println!("Implicit {}", result.clone()); result } - (AllPalletsDeclaration::Explicit(decl), result) => { + (AllPalletsDeclaration::Explicit(ref decl), ref result) => { println!("Explicit"); + + let runtime_struct = runtime_struct::expand_runtime_struct(&mut def); + quote::quote!( #runtime_struct ) diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index 499b9609cf38e..cda51957c098b 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -521,7 +521,7 @@ impl Pallet { /// | Implicit | -> | Explicit | /// +----------+ +----------+ /// ``` -pub enum PalletsConversion { +enum PalletsConversion { /// Pallets implicitely declare parts. /// /// `System: frame_system`. @@ -540,7 +540,7 @@ pub enum PalletsConversion { /// Check if all pallet have explicit declaration of their parts, if so then assign index to each /// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number /// incrementedly from last explicit or 0. -pub fn convert_pallets(pallets: Vec) -> syn::Result { +fn convert_pallets(pallets: Vec) -> syn::Result { if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { return Ok(PalletsConversion::Implicit(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 92766c9cef9dc..83204583e3428 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -30,8 +30,6 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { syn::Ident::new(&format!("__tt_extra_parts_{}", count), def.item.span()); let default_parts_unique_id_v2 = syn::Ident::new(&format!("__tt_default_parts_v2_{}", count), def.item.span()); - let extra_parts_unique_id_v2 = - syn::Ident::new(&format!("__tt_extra_parts_v2_{}", count), def.item.span()); let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); @@ -160,31 +158,5 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { } pub use #default_parts_unique_id_v2 as tt_default_parts_v2; - - - // 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_v2 { - { - $caller:tt - frame_support = [{ $($frame_support:ident)::* }] - } => { - $($frame_support)*::tt_return! { - $caller - tokens = [{ - - }] - } - }; - } - - pub use #extra_parts_unique_id_v2 as tt_extra_parts_v2; ) } From 7f1c618c61c05d92cf17dac6a2820ee83ffbab0a Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:16:55 +0530 Subject: [PATCH 08/19] Fixes build --- bin/node-template/runtime/src/lib.rs | 37 +- .../src/construct_runtime_v2/expand/call.rs | 211 ++++++++ .../src/construct_runtime_v2/expand/config.rs | 140 +++++ .../expand/freeze_reason.rs | 68 +++ .../expand/hold_reason.rs | 68 +++ .../construct_runtime_v2/expand/inherent.rs | 252 +++++++++ .../construct_runtime_v2/expand/lock_id.rs | 68 +++ .../construct_runtime_v2/expand/metadata.rs | 258 +++++++++ .../src/construct_runtime_v2/expand/mod.rs | 497 +++++++++++++++++- .../src/construct_runtime_v2/expand/origin.rs | 456 ++++++++++++++++ .../expand/outer_enums.rs | 281 ++++++++++ .../expand/runtime_struct.rs | 26 - .../expand/slash_reason.rs | 68 +++ .../construct_runtime_v2/expand/unsigned.rs | 89 ++++ .../src/construct_runtime_v2/parse/mod.rs | 1 - .../src/pallet/expand/tt_default_parts.rs | 104 +++- 16 files changed, 2553 insertions(+), 71 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/call.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/config.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/origin.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs create mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 74252b9b965f7..59c993f26af2c 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -279,27 +279,13 @@ impl pallet_template::Config for Runtime { } // Create the runtime by composing the FRAME pallets that were previously configured. -construct_runtime!( - pub struct Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - Aura: pallet_aura, - Grandpa: pallet_grandpa, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - Sudo: pallet_sudo, - // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template, - } -); - #[frame_support::construct_runtime_v2] mod runtime { #[frame::runtime] - pub struct Runtime2; + pub struct Runtime; #[frame::pallets] - pub struct AllPallets { + pub struct Pallets { System: frame_system, Timestamp: pallet_timestamp, Aura: pallet_aura, @@ -312,25 +298,6 @@ mod runtime { } } -// frame_support::tt_call!{ -// macro = [{ frame_system::tt_default_parts_v2 }] -// frame_support = [{ frame_support }] -// ~~> frame_support::match_and_insert! { -// target = -// [{ -// #[frame_support::construct_runtime_v2] -// mod runtime { -// #[frame::runtime] -// pub struct Runtime2; - -// #[frame::pallets] -// pub struct AllPallets { System : frame_system, } -// } -// }] -// pattern = [{ System : frame_system }] -// } -// } - /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/call.rs b/frame/support/procedural/src/construct_runtime_v2/expand/call.rs new file mode 100644 index 0000000000000..60c206c899ee5 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/call.rs @@ -0,0 +1,211 @@ +// 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_v2::parse::pallets::Pallet; +use proc_macro2::TokenStream; +use quote::quote; +use std::str::FromStr; +use syn::Ident; + +pub fn expand_outer_dispatch( + runtime: &Ident, + system_pallet: &Pallet, + pallet_decls: &[Pallet], + scrate: &TokenStream, +) -> TokenStream { + let mut variant_defs = TokenStream::new(); + let mut variant_patterns = Vec::new(); + let mut query_call_part_macros = Vec::new(); + let mut pallet_names = Vec::new(); + let mut pallet_attrs = Vec::new(); + let system_path = &system_pallet.path; + + let pallets_with_call = pallet_decls.iter().filter(|decl| decl.exists_part("Call")); + + for pallet_declaration in pallets_with_call { + let name = &pallet_declaration.name; + let path = &pallet_declaration.path; + let index = pallet_declaration.index; + let attr = + pallet_declaration.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 + } + }); + + variant_defs.extend(quote! { + #attr + #[codec(index = #index)] + #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ), + }); + variant_patterns.push(quote!(RuntimeCall::#name(call))); + pallet_names.push(name); + pallet_attrs.push(attr); + query_call_part_macros.push(quote! { + #path::__substrate_call_check::is_call_part_defined!(#name); + }); + } + + quote! { + #( #query_call_part_macros )* + + #[derive( + Clone, PartialEq, Eq, + #scrate::codec::Encode, + #scrate::codec::Decode, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeCall { + #variant_defs + } + #[cfg(test)] + impl RuntimeCall { + /// Return a list of the module names together with their size in memory. + pub const fn sizes() -> &'static [( &'static str, usize )] { + use #scrate::dispatch::Callable; + use core::mem::size_of; + &[#( + #pallet_attrs + ( + stringify!(#pallet_names), + size_of::< <#pallet_names as Callable<#runtime>>::RuntimeCall >(), + ), + )*] + } + + /// Panics with diagnostic information if the size is greater than the given `limit`. + pub fn assert_size_under(limit: usize) { + let size = core::mem::size_of::(); + let call_oversize = size > limit; + if call_oversize { + println!("Size of `Call` is {} bytes (provided limit is {} bytes)", size, limit); + let mut sizes = Self::sizes().to_vec(); + sizes.sort_by_key(|x| -(x.1 as isize)); + for (i, &(name, size)) in sizes.iter().enumerate().take(5) { + println!("Offender #{}: {} at {} bytes", i + 1, name, size); + } + if let Some((_, next_size)) = sizes.get(5) { + println!("{} others of size {} bytes or less", sizes.len() - 5, next_size); + } + panic!( + "Size of `Call` is more than limit; use `Box` on complex parameter types to reduce the + size of `Call`. + If the limit is too strong, maybe consider providing a higher limit." + ); + } + } + } + impl #scrate::dispatch::GetDispatchInfo for RuntimeCall { + fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo { + match self { + #( + #pallet_attrs + #variant_patterns => call.get_dispatch_info(), + )* + } + } + } + + impl #scrate::dispatch::GetCallMetadata for RuntimeCall { + fn get_call_metadata(&self) -> #scrate::dispatch::CallMetadata { + use #scrate::dispatch::GetCallName; + match self { + #( + #pallet_attrs + #variant_patterns => { + let function_name = call.get_call_name(); + let pallet_name = stringify!(#pallet_names); + #scrate::dispatch::CallMetadata { function_name, pallet_name } + } + )* + } + } + + fn get_module_names() -> &'static [&'static str] { + &[#( + #pallet_attrs + stringify!(#pallet_names), + )*] + } + + fn get_call_names(module: &str) -> &'static [&'static str] { + use #scrate::dispatch::{Callable, GetCallName}; + match module { + #( + #pallet_attrs + stringify!(#pallet_names) => + <<#pallet_names as Callable<#runtime>>::RuntimeCall + as GetCallName>::get_call_names(), + )* + _ => unreachable!(), + } + } + } + impl #scrate::dispatch::Dispatchable for RuntimeCall { + type RuntimeOrigin = RuntimeOrigin; + type Config = RuntimeCall; + type Info = #scrate::dispatch::DispatchInfo; + type PostInfo = #scrate::dispatch::PostDispatchInfo; + fn dispatch(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { + if !::filter_call(&origin, &self) { + return #scrate::sp_std::result::Result::Err( + #system_path::Error::<#runtime>::CallFiltered.into() + ); + } + + #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) + } + } + impl #scrate::traits::UnfilteredDispatchable for RuntimeCall { + type RuntimeOrigin = RuntimeOrigin; + fn dispatch_bypass_filter(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { + match self { + #( + #pallet_attrs + #variant_patterns => + #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(call, origin), + )* + } + } + } + + #( + #pallet_attrs + impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { + #[allow(unreachable_patterns)] + fn is_sub_type(&self) -> Option<&#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> { + match self { + #variant_patterns => Some(call), + // May be unreachable + _ => None, + } + } + } + + #pallet_attrs + impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { + fn from(call: #scrate::dispatch::CallableCallFor<#pallet_names, #runtime>) -> Self { + #variant_patterns + } + } + )* + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/config.rs b/frame/support/procedural/src/construct_runtime_v2/expand/config.rs new file mode 100644 index 0000000000000..36b39e4cbd5d5 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/config.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 crate::construct_runtime_v2::parse::pallets::Pallet; +use inflector::Inflector; +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use std::str::FromStr; +use syn::Ident; + +pub fn expand_outer_config( + runtime: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream, +) -> TokenStream { + let mut types = TokenStream::new(); + let mut fields = TokenStream::new(); + let mut genesis_build_calls = TokenStream::new(); + let mut query_genesis_config_part_macros = Vec::new(); + + for decl in pallet_decls { + if let Some(pallet_entry) = decl.find_part("Config") { + let path = &decl.path; + let pallet_name = &decl.name; + let path_str = path.into_token_stream().to_string(); + let config = format_ident!("{}Config", pallet_name); + let field_name = + &Ident::new(&pallet_name.to_string().to_snake_case(), decl.name.span()); + let part_is_generic = !pallet_entry.generics.params.is_empty(); + let attr = &decl.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 + } + }); + + types.extend(expand_config_types(attr, runtime, decl, &config, part_is_generic)); + fields.extend(quote!(#attr pub #field_name: #config,)); + genesis_build_calls + .extend(expand_config_build_storage_call(scrate, &config, attr, field_name)); + query_genesis_config_part_macros.push(quote! { + #path::__substrate_genesis_config_check::is_genesis_config_defined!(#pallet_name); + #[cfg(feature = "std")] + #path::__substrate_genesis_config_check::is_std_enabled_for_genesis!(#pallet_name, #path_str); + }); + } + } + + quote! { + #( #query_genesis_config_part_macros )* + + #types + + use #scrate::serde as __genesis_config_serde_import__; + #[derive(#scrate::serde::Serialize, #scrate::serde::Deserialize, Default)] + #[serde(rename_all = "camelCase")] + #[serde(deny_unknown_fields)] + #[serde(crate = "__genesis_config_serde_import__")] + pub struct RuntimeGenesisConfig { + #fields + } + + #[cfg(any(feature = "std", test))] + #[deprecated(note = "GenesisConfig is planned to be removed in December 2023. Use `RuntimeGenesisConfig` instead.")] + pub type GenesisConfig = RuntimeGenesisConfig; + + #[cfg(any(feature = "std", test))] + impl #scrate::sp_runtime::BuildStorage for RuntimeGenesisConfig { + fn assimilate_storage( + &self, + storage: &mut #scrate::sp_runtime::Storage, + ) -> std::result::Result<(), String> { + #scrate::BasicExternalities::execute_with_storage(storage, || { + ::build(&self); + Ok(()) + }) + } + } + + impl #scrate::traits::BuildGenesisConfig for RuntimeGenesisConfig { + fn build(&self) { + #genesis_build_calls + ::on_genesis(); + } + } + } +} + +fn expand_config_types( + attr: &TokenStream, + runtime: &Ident, + decl: &Pallet, + config: &Ident, + part_is_generic: bool, +) -> TokenStream { + let path = &decl.path; + + match (decl.instance.as_ref(), part_is_generic) { + (Some(inst), true) => quote! { + #attr + pub type #config = #path::GenesisConfig<#runtime, #path::#inst>; + }, + (None, true) => quote! { + #attr + pub type #config = #path::GenesisConfig<#runtime>; + }, + (_, false) => quote! { + #attr + pub type #config = #path::GenesisConfig; + }, + } +} + +fn expand_config_build_storage_call( + scrate: &TokenStream, + pallet_genesis_config: &Ident, + attr: &TokenStream, + field_name: &Ident, +) -> TokenStream { + quote! { + #attr + <#pallet_genesis_config as #scrate::traits::BuildGenesisConfig>::build(&self.#field_name); + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs b/frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs new file mode 100644 index 0000000000000..2a11e180c49e0 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs @@ -0,0 +1,68 @@ +// 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_v2::parse::pallets::{PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut freeze_reason_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("FreezeReason") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + freeze_reason_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + /// A reason for placing a freeze on funds. + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeFreezeReason { + #( #freeze_reason_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::FreezeReason> for RuntimeFreezeReason { + fn from(hr: #path::FreezeReason) -> Self { + RuntimeFreezeReason::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::FreezeReason), + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs b/frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs new file mode 100644 index 0000000000000..7f305e788c17d --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs @@ -0,0 +1,68 @@ +// 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_v2::parse::pallets::{PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut hold_reason_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("HoldReason") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + hold_reason_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + /// A reason for placing a hold on funds. + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeHoldReason { + #( #hold_reason_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::HoldReason> for RuntimeHoldReason { + fn from(hr: #path::HoldReason) -> Self { + RuntimeHoldReason::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::HoldReason), + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs b/frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs new file mode 100644 index 0000000000000..913328d974e47 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs @@ -0,0 +1,252 @@ +// 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_v2::parse::pallets::Pallet; +use proc_macro2::TokenStream; +use quote::quote; +use std::str::FromStr; +use syn::Ident; + +pub fn expand_outer_inherent( + runtime: &Ident, + block: &TokenStream, + unchecked_extrinsic: &TokenStream, + pallet_decls: &[Pallet], + scrate: &TokenStream, +) -> TokenStream { + let mut pallet_names = Vec::new(); + let mut pallet_attrs = Vec::new(); + let mut query_inherent_part_macros = Vec::new(); + + for pallet_decl in pallet_decls { + if pallet_decl.exists_part("Inherent") { + let name = &pallet_decl.name; + let path = &pallet_decl.path; + let attr = pallet_decl.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 + } + }); + + pallet_names.push(name); + pallet_attrs.push(attr); + query_inherent_part_macros.push(quote! { + #path::__substrate_inherent_check::is_inherent_part_defined!(#name); + }); + } + } + + quote! { + #( #query_inherent_part_macros )* + + trait InherentDataExt { + fn create_extrinsics(&self) -> + #scrate::sp_std::vec::Vec<<#block as #scrate::sp_runtime::traits::Block>::Extrinsic>; + fn check_extrinsics(&self, block: &#block) -> #scrate::inherent::CheckInherentsResult; + } + + impl InherentDataExt for #scrate::inherent::InherentData { + fn create_extrinsics(&self) -> + #scrate::sp_std::vec::Vec<<#block as #scrate::sp_runtime::traits::Block>::Extrinsic> + { + use #scrate::inherent::ProvideInherent; + + let mut inherents = #scrate::sp_std::vec::Vec::new(); + + #( + #pallet_attrs + if let Some(inherent) = #pallet_names::create_inherent(self) { + let inherent = <#unchecked_extrinsic as #scrate::sp_runtime::traits::Extrinsic>::new( + inherent.into(), + None, + ).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return \ + `Some`; qed"); + + inherents.push(inherent); + } + )* + + inherents + } + + fn check_extrinsics(&self, block: &#block) -> #scrate::inherent::CheckInherentsResult { + use #scrate::inherent::{ProvideInherent, IsFatalError}; + use #scrate::traits::{IsSubType, ExtrinsicCall}; + use #scrate::sp_runtime::traits::Block as _; + use #scrate::_private::sp_inherents::Error; + use #scrate::log; + + let mut result = #scrate::inherent::CheckInherentsResult::new(); + + // This handle assume we abort on the first fatal error. + fn handle_put_error_result(res: Result<(), Error>) { + const LOG_TARGET: &str = "runtime::inherent"; + match res { + Ok(()) => (), + Err(Error::InherentDataExists(id)) => + log::debug!( + target: LOG_TARGET, + "Some error already reported for inherent {:?}, new non fatal \ + error is ignored", + id + ), + Err(Error::FatalErrorReported) => + log::error!( + target: LOG_TARGET, + "Fatal error already reported, unexpected considering there is \ + only one fatal error", + ), + Err(_) => + log::error!( + target: LOG_TARGET, + "Unexpected error from `put_error` operation", + ), + } + } + + for xt in block.extrinsics() { + // Inherents are before any other extrinsics. + // And signed extrinsics are not inherents. + if #scrate::sp_runtime::traits::Extrinsic::is_signed(xt).unwrap_or(false) { + break + } + + let mut is_inherent = false; + + #( + #pallet_attrs + { + let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); + if let Some(call) = IsSubType::<_>::is_sub_type(call) { + if #pallet_names::is_inherent(call) { + is_inherent = true; + if let Err(e) = #pallet_names::check_inherent(call, self) { + handle_put_error_result(result.put_error( + #pallet_names::INHERENT_IDENTIFIER, &e + )); + if e.is_fatal_error() { + return result; + } + } + } + } + } + )* + + // Inherents are before any other extrinsics. + // No module marked it as inherent thus it is not. + if !is_inherent { + break + } + } + + #( + #pallet_attrs + match #pallet_names::is_inherent_required(self) { + Ok(Some(e)) => { + let found = block.extrinsics().iter().any(|xt| { + let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) + .unwrap_or(false); + + if !is_signed { + let call = < + #unchecked_extrinsic as ExtrinsicCall + >::call(xt); + if let Some(call) = IsSubType::<_>::is_sub_type(call) { + #pallet_names::is_inherent(&call) + } else { + false + } + } else { + // Signed extrinsics are not inherents. + false + } + }); + + if !found { + handle_put_error_result(result.put_error( + #pallet_names::INHERENT_IDENTIFIER, &e + )); + if e.is_fatal_error() { + return result; + } + } + }, + Ok(None) => (), + Err(e) => { + handle_put_error_result(result.put_error( + #pallet_names::INHERENT_IDENTIFIER, &e + )); + if e.is_fatal_error() { + return result; + } + }, + } + )* + + result + } + } + + impl #scrate::traits::EnsureInherentsAreFirst<#block> for #runtime { + fn ensure_inherents_are_first(block: &#block) -> Result<(), u32> { + use #scrate::inherent::ProvideInherent; + use #scrate::traits::{IsSubType, ExtrinsicCall}; + use #scrate::sp_runtime::traits::Block as _; + + let mut first_signed_observed = false; + + for (i, xt) in block.extrinsics().iter().enumerate() { + let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) + .unwrap_or(false); + + let is_inherent = if is_signed { + // Signed extrinsics are not inherents. + false + } else { + let mut is_inherent = false; + #( + #pallet_attrs + { + let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); + if let Some(call) = IsSubType::<_>::is_sub_type(call) { + if #pallet_names::is_inherent(&call) { + is_inherent = true; + } + } + } + )* + is_inherent + }; + + if !is_inherent { + first_signed_observed = true; + } + + if first_signed_observed && is_inherent { + return Err(i as u32) + } + } + + Ok(()) + } + } + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs b/frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs new file mode 100644 index 0000000000000..94bfe276f34a1 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs @@ -0,0 +1,68 @@ +// 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_v2::parse::pallets::{PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut lock_id_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("LockId") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + lock_id_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + /// An identifier for each lock placed on funds. + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeLockId { + #( #lock_id_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::LockId> for RuntimeLockId { + fn from(hr: #path::LockId) -> Self { + RuntimeLockId::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::LockId), + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs b/frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs new file mode 100644 index 0000000000000..a7884d4f28767 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs @@ -0,0 +1,258 @@ +// 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_v2::parse::pallets::{PalletPath, Pallet}; +use proc_macro2::TokenStream; +use quote::quote; +use std::str::FromStr; +use syn::Ident; + +pub fn expand_runtime_metadata( + runtime: &Ident, + pallet_declarations: &[Pallet], + scrate: &TokenStream, + extrinsic: &TokenStream, + system_path: &PalletPath, +) -> TokenStream { + let pallets = pallet_declarations + .iter() + .filter_map(|pallet_declaration| { + pallet_declaration.find_part("Pallet").map(|_| { + let filtered_names: Vec<_> = pallet_declaration + .pallet_parts() + .iter() + .filter(|part| part.name() != "Pallet") + .map(|part| part.name()) + .collect(); + (pallet_declaration, filtered_names) + }) + }) + .map(|(decl, filtered_names)| { + let name = &decl.name; + let index = &decl.index; + let storage = expand_pallet_metadata_storage(&filtered_names, runtime, decl); + let calls = expand_pallet_metadata_calls(&filtered_names, runtime, decl); + let event = expand_pallet_metadata_events(&filtered_names, runtime, scrate, decl); + let constants = expand_pallet_metadata_constants(runtime, decl); + let errors = expand_pallet_metadata_errors(runtime, decl); + let docs = expand_pallet_metadata_docs(runtime, decl); + let attr = decl.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 + #scrate::metadata_ir::PalletMetadataIR { + name: stringify!(#name), + index: #index, + storage: #storage, + calls: #calls, + event: #event, + constants: #constants, + error: #errors, + docs: #docs, + } + } + }) + .collect::>(); + + quote! { + impl #runtime { + fn metadata_ir() -> #scrate::metadata_ir::MetadataIR { + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. + // `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`), + // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!` + // is called. + // + // `Deref` needs a reference for resolving the function call. + let rt = #runtime; + + let ty = #scrate::scale_info::meta_type::<#extrinsic>(); + let address_ty = #scrate::scale_info::meta_type::< + <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureAddress + >(); + let call_ty = #scrate::scale_info::meta_type::< + <#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::Call + >(); + let signature_ty = #scrate::scale_info::meta_type::< + <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::Signature + >(); + let extra_ty = #scrate::scale_info::meta_type::< + <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureExtra + >(); + + #scrate::metadata_ir::MetadataIR { + pallets: #scrate::sp_std::vec![ #(#pallets),* ], + extrinsic: #scrate::metadata_ir::ExtrinsicMetadataIR { + ty, + version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION, + address_ty, + call_ty, + signature_ty, + extra_ty, + signed_extensions: < + < + #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata + >::SignedExtensions as #scrate::sp_runtime::traits::SignedExtension + >::metadata() + .into_iter() + .map(|meta| #scrate::metadata_ir::SignedExtensionMetadataIR { + identifier: meta.identifier, + ty: meta.ty, + additional_signed: meta.additional_signed, + }) + .collect(), + }, + 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::(), + } + } + } + + pub fn metadata() -> #scrate::metadata::RuntimeMetadataPrefixed { + // Note: this always returns the V14 version. The runtime API function + // must be deprecated. + #scrate::metadata_ir::into_v14(#runtime::metadata_ir()) + } + + pub fn metadata_at_version(version: u32) -> Option<#scrate::OpaqueMetadata> { + #scrate::metadata_ir::into_version(#runtime::metadata_ir(), version).map(|prefixed| { + #scrate::OpaqueMetadata::new(prefixed.into()) + }) + } + + pub fn metadata_versions() -> #scrate::sp_std::vec::Vec { + #scrate::metadata_ir::supported_versions() + } + } + } +} + +fn expand_pallet_metadata_storage( + filtered_names: &[&'static str], + runtime: &Ident, + decl: &Pallet, +) -> TokenStream { + if filtered_names.contains(&"Storage") { + let instance = decl.instance.as_ref().into_iter(); + let path = &decl.path; + + quote! { + Some(#path::Pallet::<#runtime #(, #path::#instance)*>::storage_metadata()) + } + } else { + quote!(None) + } +} + +fn expand_pallet_metadata_calls( + filtered_names: &[&'static str], + runtime: &Ident, + decl: &Pallet, +) -> TokenStream { + if filtered_names.contains(&"Call") { + let instance = decl.instance.as_ref().into_iter(); + let path = &decl.path; + + quote! { + Some(#path::Pallet::<#runtime #(, #path::#instance)*>::call_functions()) + } + } else { + quote!(None) + } +} + +fn expand_pallet_metadata_events( + filtered_names: &[&'static str], + runtime: &Ident, + scrate: &TokenStream, + decl: &Pallet, +) -> TokenStream { + if filtered_names.contains(&"Event") { + let path = &decl.path; + let part_is_generic = !decl + .find_part("Event") + .expect("Event part exists; qed") + .generics + .params + .is_empty(); + let pallet_event = match (decl.instance.as_ref(), 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), + }; + + quote! { + Some( + #scrate::metadata_ir::PalletEventMetadataIR { + ty: #scrate::scale_info::meta_type::<#pallet_event>() + } + ) + } + } else { + quote!(None) + } +} + +fn expand_pallet_metadata_constants(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_constants_metadata() + } +} + +fn expand_pallet_metadata_errors(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::error_metadata() + } +} + +fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata() + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index 69a369730c492..1fca2be0e9aab 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -15,25 +15,506 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod runtime_struct; +mod call; +mod config; +mod freeze_reason; +mod hold_reason; +mod inherent; +mod lock_id; +mod metadata; +mod origin; +mod outer_enums; +mod slash_reason; +mod unsigned; use crate::construct_runtime_v2::Def; -use crate::construct_runtime_v2::parse::pallets::AllPalletsDeclaration; +use crate::construct_runtime_v2::parse::pallets::{AllPalletsDeclaration, ExplicitAllPalletsDeclaration}; +use crate::construct_runtime_v2::parse::pallets::Pallet; +use syn::{Ident, Result}; +use quote::quote; +use proc_macro2::TokenStream as TokenStream2; +use std::collections::HashSet; +use frame_support_procedural_tools::generate_crate_access; +use frame_support_procedural_tools::generate_hidden_includes; +use frame_support_procedural_tools::generate_crate_access_2018; +use std::str::FromStr; +use itertools::Itertools; +use cfg_expr::Predicate; + +/// The fixed name of the system pallet. +const SYSTEM_PALLET_NAME: &str = "System"; pub fn expand(mut def: Def) -> proc_macro2::TokenStream { match def.pallets { (AllPalletsDeclaration::Implicit(decl), result) => { - println!("Implicit {}", result.clone()); result } (AllPalletsDeclaration::Explicit(ref decl), ref result) => { - println!("Explicit"); + let res = construct_runtime_final_expansion(def.runtime_struct.ident.clone(), decl.clone()); - let runtime_struct = runtime_struct::expand_runtime_struct(&mut def); + let res = res.unwrap_or_else(|e| e.to_compile_error()); - quote::quote!( - #runtime_struct - ) + let res = expander::Expander::new("construct_runtime") + .dry(std::env::var("FRAME_EXPAND").is_err()) + .verbose(true) + .write_to_out_dir(res) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + res.into() } } } + +fn construct_runtime_final_expansion( + name: Ident, + definition: ExplicitAllPalletsDeclaration, +) -> Result { + let ExplicitAllPalletsDeclaration { pallets, pallets_token, .. } = definition; + + let system_pallet = + pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { + syn::Error::new( + pallets_token.span.join(), + "`System` pallet declaration is missing. \ + Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", + ) + })?; + if !system_pallet.cfg_pattern.is_empty() { + return Err(syn::Error::new( + system_pallet.name.span(), + "`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes", + )) + } + + let features = pallets + .iter() + .filter_map(|decl| { + (!decl.cfg_pattern.is_empty()).then(|| { + decl.cfg_pattern.iter().flat_map(|attr| { + attr.predicates().filter_map(|pred| match pred { + Predicate::Feature(feat) => Some(feat), + Predicate::Test => Some("test"), + _ => None, + }) + }) + }) + }) + .flatten() + .collect::>(); + + let hidden_crate_name = "construct_runtime"; + let scrate = generate_crate_access(hidden_crate_name, "frame-support"); + let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support"); + + let frame_system = generate_crate_access_2018("frame-system")?; + let block = quote!(<#name as #frame_system::Config>::Block); + let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); + + let outer_event = + outer_enums::expand_outer_enum(&name, &pallets, &scrate, outer_enums::OuterEnumType::Event)?; + let outer_error = + outer_enums::expand_outer_enum(&name, &pallets, &scrate, outer_enums::OuterEnumType::Error)?; + + let outer_origin = origin::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 = call::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); + let metadata = metadata::expand_runtime_metadata( + &name, + &pallets, + &scrate, + &unchecked_extrinsic, + &system_pallet.path, + ); + let outer_config = config::expand_outer_config(&name, &pallets, &scrate); + let inherent = + inherent::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); + let validate_unsigned = unsigned::expand_outer_validate_unsigned(&name, &pallets, &scrate); + let freeze_reason = freeze_reason::expand_outer_freeze_reason(&pallets, &scrate); + let hold_reason = hold_reason::expand_outer_hold_reason(&pallets, &scrate); + let lock_id = lock_id::expand_outer_lock_id(&pallets, &scrate); + let slash_reason = slash_reason::expand_outer_slash_reason(&pallets, &scrate); + let integrity_test = decl_integrity_test(&scrate); + let static_assertions = decl_static_assertions(&name, &pallets, &scrate); + + let res = quote!( + #scrate_decl + + // Prevent UncheckedExtrinsic to print unused warning. + const _: () = { + #[allow(unused)] + type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic; + }; + + #[derive( + Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug, + #scrate::scale_info::TypeInfo + )] + pub struct #name; + impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name { + type RuntimeBlock = #block; + } + + // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. + // The function is implemented by calling `impl_runtime_apis!`. + // + // However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`. + // Rely on the `Deref` trait to differentiate between a runtime that implements + // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!). + // + // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. + // `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`), + // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). + // + // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` + // when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!` + // is called. + + #[doc(hidden)] + trait InternalConstructRuntime { + #[inline(always)] + fn runtime_metadata(&self) -> #scrate::sp_std::vec::Vec<#scrate::metadata_ir::RuntimeApiMetadataIR> { + Default::default() + } + } + #[doc(hidden)] + impl InternalConstructRuntime for &#name {} + + #outer_event + + #outer_error + + #outer_origin + + #all_pallets + + #pallet_to_index + + #dispatch + + #metadata + + #outer_config + + #inherent + + #validate_unsigned + + #freeze_reason + + #hold_reason + + #lock_id + + #slash_reason + + #integrity_test + + #static_assertions + ); + + Ok(res) +} + +fn decl_all_pallets<'a>( + runtime: &'a Ident, + pallet_declarations: impl Iterator, + features: &HashSet<&str>, +) -> TokenStream2 { + let mut types = TokenStream2::new(); + + // Every feature set to the pallet names that should be included by this feature set. + let mut features_to_names = features + .iter() + .map(|f| *f) + .powerset() + .map(|feat| (HashSet::from_iter(feat), Vec::new())) + .collect::, Vec<_>)>>(); + + for pallet_declaration in pallet_declarations { + let type_name = &pallet_declaration.name; + let pallet = &pallet_declaration.path; + let mut generics = vec![quote!(#runtime)]; + generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name))); + let mut attrs = Vec::new(); + for cfg in &pallet_declaration.cfg_pattern { + let feat = format!("#[cfg({})]\n", cfg.original()); + attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed")); + } + let type_decl = quote!( + #(#attrs)* + pub type #type_name = #pallet::Pallet <#(#generics),*>; + ); + types.extend(type_decl); + + if pallet_declaration.cfg_pattern.is_empty() { + for (_, names) in features_to_names.iter_mut() { + names.push(&pallet_declaration.name); + } + } else { + for (feature_set, names) in &mut features_to_names { + // Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the + // predicates listed in all `#[cfg]` attributes are effectively joined by `and()`, + // meaning that all of them must match in order to activate the item + let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| { + expr.eval(|pred| match pred { + Predicate::Feature(f) => feature_set.contains(f), + Predicate::Test => feature_set.contains(&"test"), + _ => false, + }) + }); + + if is_feature_active { + names.push(&pallet_declaration.name); + } + } + } + } + + // All possible features. This will be used below for the empty feature set. + let mut all_features = features_to_names + .iter() + .flat_map(|f| f.0.iter().cloned()) + .collect::>(); + let attribute_to_names = features_to_names + .into_iter() + .map(|(mut features, names)| { + // If this is the empty feature set, it needs to be changed to negate all available + // features. So, we ensure that there is some type declared when all features are not + // enabled. + if features.is_empty() { + let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter(); + let features = all_features.iter(); + let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]); + + (attr, names) + } else { + let test_cfg = features.remove("test").then_some(quote!(test)).into_iter(); + let disabled_features = all_features.difference(&features); + let features = features.iter(); + let attr = quote!(#[cfg(all( #(#test_cfg,)* #(feature = #features,)* #(not(feature = #disabled_features)),* ))]); + + (attr, names) + } + }) + .collect::>(); + + let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| { + let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types. + /// Excludes the System pallet. + pub type AllPalletsWithoutSystem = ( #(#names,)* ); + } + }); + + let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| { + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types. + pub type AllPalletsWithSystem = ( #(#names,)* ); + } + }); + + let all_pallets_without_system_reversed = attribute_to_names.iter().map(|(attr, names)| { + let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// Excludes the System pallet. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); + } + }); + + let all_pallets_with_system_reversed = attribute_to_names.iter().map(|(attr, names)| { + let names = names.iter().rev(); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithSystemReversed = ( #(#names,)* ); + } + }); + + let all_pallets_reversed_with_system_first = attribute_to_names.iter().map(|(attr, names)| { + let system = quote::format_ident!("{}", SYSTEM_PALLET_NAME); + let names = std::iter::once(&system) + .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME).cloned()); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// With the system pallet first. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); + } + }); + + quote!( + #types + + /// All pallets included in the runtime as a nested tuple of types. + #[deprecated(note = "The type definition has changed from representing all pallets \ + excluding system, in reversed order to become the representation of all pallets \ + including system pallet in regular order. For this reason it is encouraged to use \ + explicitly one of `AllPalletsWithSystem`, `AllPalletsWithoutSystem`, \ + `AllPalletsWithSystemReversed`, `AllPalletsWithoutSystemReversed`. \ + Note that the type `frame_executive::Executive` expects one of `AllPalletsWithSystem` \ + , `AllPalletsWithSystemReversed`, `AllPalletsReversedWithSystemFirst`. More details in \ + https://github.com/paritytech/substrate/pull/10043")] + pub type AllPallets = AllPalletsWithSystem; + + #( #all_pallets_with_system )* + + #( #all_pallets_without_system )* + + #( #all_pallets_with_system_reversed )* + + #( #all_pallets_without_system_reversed )* + + #( #all_pallets_reversed_with_system_first )* + ) +} + +fn decl_pallet_runtime_setup( + runtime: &Ident, + pallet_declarations: &[Pallet], + scrate: &TokenStream2, +) -> TokenStream2 { + let names = pallet_declarations.iter().map(|d| &d.name).collect::>(); + let name_strings = pallet_declarations.iter().map(|d| d.name.to_string()); + let module_names = pallet_declarations.iter().map(|d| d.path.module_name()); + let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize); + let pallet_structs = pallet_declarations + .iter() + .map(|pallet| { + let path = &pallet.path; + match pallet.instance.as_ref() { + Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>), + None => quote!(#path::Pallet<#runtime>), + } + }) + .collect::>(); + let pallet_attrs = pallet_declarations + .iter() + .map(|pallet| { + pallet.cfg_pattern.iter().fold(TokenStream2::new(), |acc, pattern| { + let attr = TokenStream2::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }) + }) + .collect::>(); + + quote!( + /// Provides an implementation of `PalletInfo` to provide information + /// about the pallet setup in the runtime. + pub struct PalletInfo; + + impl #scrate::traits::PalletInfo for PalletInfo { + fn index() -> Option { + let type_id = #scrate::sp_std::any::TypeId::of::

(); + #( + #pallet_attrs + if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { + return Some(#indices) + } + )* + + None + } + + fn name() -> Option<&'static str> { + let type_id = #scrate::sp_std::any::TypeId::of::

(); + #( + #pallet_attrs + if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { + return Some(#name_strings) + } + )* + + None + } + + fn module_name() -> Option<&'static str> { + let type_id = #scrate::sp_std::any::TypeId::of::

(); + #( + #pallet_attrs + if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { + return Some(#module_names) + } + )* + + None + } + + fn crate_version() -> Option<#scrate::traits::CrateVersion> { + let type_id = #scrate::sp_std::any::TypeId::of::

(); + #( + #pallet_attrs + if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { + return Some( + <#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version() + ) + } + )* + + None + } + } + ) +} + +fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { + quote!( + #[cfg(test)] + mod __construct_runtime_integrity_test { + use super::*; + + #[test] + pub fn runtime_integrity_tests() { + #scrate::sp_tracing::try_init_simple(); + ::integrity_test(); + } + } + ) +} + +fn decl_static_assertions( + runtime: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream2, +) -> TokenStream2 { + let error_encoded_size_check = pallet_decls.iter().map(|decl| { + let path = &decl.path; + let assert_message = format!( + "The maximum encoded size of the error type in the `{}` pallet exceeds \ + `MAX_MODULE_ERROR_ENCODED_SIZE`", + decl.name, + ); + + quote! { + #scrate::tt_call! { + macro = [{ #path::tt_error_token }] + frame_support = [{ #scrate }] + ~~> #scrate::assert_error_encoded_size! { + path = [{ #path }] + runtime = [{ #runtime }] + assert_message = [{ #assert_message }] + } + } + } + }); + + quote! { + #(#error_encoded_size_check)* + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/origin.rs b/frame/support/procedural/src/construct_runtime_v2/expand/origin.rs new file mode 100644 index 0000000000000..1191a60f0c44b --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/origin.rs @@ -0,0 +1,456 @@ +// 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_v2::parse::pallets::Pallet; +use proc_macro2::TokenStream; +use quote::quote; +use std::str::FromStr; +use syn::{Generics, Ident}; +use crate::construct_runtime_v2::expand::SYSTEM_PALLET_NAME; + +pub fn expand_outer_origin( + runtime: &Ident, + system_pallet: &Pallet, + pallets: &[Pallet], + scrate: &TokenStream, +) -> syn::Result { + let mut caller_variants = TokenStream::new(); + let mut pallet_conversions = TokenStream::new(); + let mut query_origin_part_macros = Vec::new(); + + for pallet_decl in pallets.iter().filter(|pallet| pallet.name != SYSTEM_PALLET_NAME) { + if let Some(pallet_entry) = pallet_decl.find_part("Origin") { + let instance = pallet_decl.instance.as_ref(); + let index = pallet_decl.index; + let generics = &pallet_entry.generics; + let name = &pallet_decl.name; + let path = &pallet_decl.path; + + if instance.is_some() && generics.params.is_empty() { + let msg = format!( + "Instantiable pallet with no generic `Origin` cannot \ + be constructed: pallet `{}` must have generic `Origin`", + name + ); + return Err(syn::Error::new(name.span(), msg)) + } + + caller_variants.extend(expand_origin_caller_variant( + runtime, + pallet_decl, + index, + instance, + generics, + )); + pallet_conversions.extend(expand_origin_pallet_conversions( + scrate, + runtime, + pallet_decl, + instance, + generics, + )); + query_origin_part_macros.push(quote! { + #path::__substrate_origin_check::is_origin_part_defined!(#name); + }); + } + } + + let system_path = &system_pallet.path; + + let system_index = system_pallet.index; + + let system_path_name = system_path.module_name(); + + let doc_string = get_intra_doc_string( + "Origin is always created with the base filter configured in", + &system_path_name, + ); + + let doc_string_none_origin = + get_intra_doc_string("Create with system none origin and", &system_path_name); + + let doc_string_root_origin = + get_intra_doc_string("Create with system root origin and", &system_path_name); + + let doc_string_signed_origin = + get_intra_doc_string("Create with system signed origin and", &system_path_name); + + let doc_string_runtime_origin = + get_intra_doc_string("Convert to runtime origin, using as filter:", &system_path_name); + + let doc_string_runtime_origin_with_caller = get_intra_doc_string( + "Convert to runtime origin with caller being system signed or none and use filter", + &system_path_name, + ); + + Ok(quote! { + #( #query_origin_part_macros )* + + /// The runtime origin type representing the origin of a call. + /// + #[doc = #doc_string] + #[derive(Clone)] + pub struct RuntimeOrigin { + caller: OriginCaller, + filter: #scrate::sp_std::rc::Rc::RuntimeCall) -> bool>>, + } + + #[cfg(not(feature = "std"))] + impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { + fn fmt( + &self, + fmt: &mut #scrate::sp_std::fmt::Formatter, + ) -> #scrate::sp_std::result::Result<(), #scrate::sp_std::fmt::Error> { + fmt.write_str("") + } + } + + #[cfg(feature = "std")] + impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { + fn fmt( + &self, + fmt: &mut #scrate::sp_std::fmt::Formatter, + ) -> #scrate::sp_std::result::Result<(), #scrate::sp_std::fmt::Error> { + fmt.debug_struct("Origin") + .field("caller", &self.caller) + .field("filter", &"[function ptr]") + .finish() + } + } + + impl #scrate::traits::OriginTrait for RuntimeOrigin { + type Call = <#runtime as #system_path::Config>::RuntimeCall; + type PalletsOrigin = OriginCaller; + type AccountId = <#runtime as #system_path::Config>::AccountId; + + fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { + let f = self.filter.clone(); + + self.filter = #scrate::sp_std::rc::Rc::new(Box::new(move |call| { + f(call) && filter(call) + })); + } + + fn reset_filter(&mut self) { + let filter = < + <#runtime as #system_path::Config>::BaseCallFilter + as #scrate::traits::Contains<<#runtime as #system_path::Config>::RuntimeCall> + >::contains; + + self.filter = #scrate::sp_std::rc::Rc::new(Box::new(filter)); + } + + fn set_caller_from(&mut self, other: impl Into) { + self.caller = other.into().caller; + } + + fn filter_call(&self, call: &Self::Call) -> bool { + match self.caller { + // Root bypasses all filters + OriginCaller::system(#system_path::Origin::<#runtime>::Root) => true, + _ => (self.filter)(call), + } + } + + fn caller(&self) -> &Self::PalletsOrigin { + &self.caller + } + + fn into_caller(self) -> Self::PalletsOrigin { + self.caller + } + + fn try_with_caller( + mut self, + f: impl FnOnce(Self::PalletsOrigin) -> Result, + ) -> Result { + match f(self.caller) { + Ok(r) => Ok(r), + Err(caller) => { self.caller = caller; Err(self) } + } + } + + fn none() -> Self { + #system_path::RawOrigin::None.into() + } + + fn root() -> Self { + #system_path::RawOrigin::Root.into() + } + + fn signed(by: Self::AccountId) -> Self { + #system_path::RawOrigin::Signed(by).into() + } + } + + #[derive( + Clone, PartialEq, Eq, #scrate::RuntimeDebug, #scrate::codec::Encode, + #scrate::codec::Decode, #scrate::scale_info::TypeInfo, #scrate::codec::MaxEncodedLen, + )] + #[allow(non_camel_case_types)] + pub enum OriginCaller { + #[codec(index = #system_index)] + system(#system_path::Origin<#runtime>), + #caller_variants + #[allow(dead_code)] + Void(#scrate::Void) + } + + // For backwards compatibility and ease of accessing these functions. + #[allow(dead_code)] + impl RuntimeOrigin { + #[doc = #doc_string_none_origin] + pub fn none() -> Self { + ::none() + } + + #[doc = #doc_string_root_origin] + pub fn root() -> Self { + ::root() + } + + #[doc = #doc_string_signed_origin] + pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { + ::signed(by) + } + } + + impl From<#system_path::Origin<#runtime>> for OriginCaller { + fn from(x: #system_path::Origin<#runtime>) -> Self { + OriginCaller::system(x) + } + } + + impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller { + fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { + match self { + OriginCaller::system(x) => Some(x), + _ => None, + } + } + fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { + match &self { + OriginCaller::system(o) => Some(o), + _ => None, + } + } + } + + impl TryFrom for #system_path::Origin<#runtime> { + type Error = OriginCaller; + fn try_from(x: OriginCaller) + -> #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, OriginCaller> + { + if let OriginCaller::system(l) = x { + Ok(l) + } else { + Err(x) + } + } + } + + impl From<#system_path::Origin<#runtime>> for RuntimeOrigin { + + #[doc = #doc_string_runtime_origin] + fn from(x: #system_path::Origin<#runtime>) -> Self { + let o: OriginCaller = x.into(); + o.into() + } + } + + impl From for RuntimeOrigin { + fn from(x: OriginCaller) -> Self { + let mut o = RuntimeOrigin { + caller: x, + filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)), + }; + + #scrate::traits::OriginTrait::reset_filter(&mut o); + + o + } + } + + impl From for #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, RuntimeOrigin> { + /// NOTE: converting to pallet origin loses the origin filter information. + fn from(val: RuntimeOrigin) -> Self { + if let OriginCaller::system(l) = val.caller { + Ok(l) + } else { + Err(val) + } + } + } + impl From::AccountId>> for RuntimeOrigin { + #[doc = #doc_string_runtime_origin_with_caller] + fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self { + <#system_path::Origin<#runtime>>::from(x).into() + } + } + + #pallet_conversions + }) +} + +fn expand_origin_caller_variant( + runtime: &Ident, + pallet: &Pallet, + index: u8, + instance: Option<&Ident>, + generics: &Generics, +) -> TokenStream { + let part_is_generic = !generics.params.is_empty(); + let variant_name = &pallet.name; + let path = &pallet.path; + 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::Origin<#runtime, #path::#inst>), + }, + Some(inst) => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin<#path::#inst>), + }, + None if part_is_generic => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin<#runtime>), + }, + None => quote! { + #attr + #[codec(index = #index)] + #variant_name(#path::Origin), + }, + } +} + +fn expand_origin_pallet_conversions( + scrate: &TokenStream, + runtime: &Ident, + pallet: &Pallet, + instance: Option<&Ident>, + generics: &Generics, +) -> TokenStream { + let path = &pallet.path; + let variant_name = &pallet.name; + + let part_is_generic = !generics.params.is_empty(); + let pallet_origin = match instance { + Some(inst) if part_is_generic => quote!(#path::Origin<#runtime, #path::#inst>), + Some(inst) => quote!(#path::Origin<#path::#inst>), + None if part_is_generic => quote!(#path::Origin<#runtime>), + None => quote!(#path::Origin), + }; + + let doc_string = get_intra_doc_string(" Convert to runtime origin using", &path.module_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_origin> for OriginCaller { + fn from(x: #pallet_origin) -> Self { + OriginCaller::#variant_name(x) + } + } + + #attr + impl From<#pallet_origin> for RuntimeOrigin { + #[doc = #doc_string] + fn from(x: #pallet_origin) -> Self { + let x: OriginCaller = x.into(); + x.into() + } + } + + #attr + impl From for #scrate::sp_std::result::Result<#pallet_origin, RuntimeOrigin> { + /// NOTE: converting to pallet origin loses the origin filter information. + fn from(val: RuntimeOrigin) -> Self { + if let OriginCaller::#variant_name(l) = val.caller { + Ok(l) + } else { + Err(val) + } + } + } + + #attr + impl TryFrom for #pallet_origin { + type Error = OriginCaller; + fn try_from( + x: OriginCaller, + ) -> #scrate::sp_std::result::Result<#pallet_origin, OriginCaller> { + if let OriginCaller::#variant_name(l) = x { + Ok(l) + } else { + Err(x) + } + } + } + + #attr + impl<'a> TryFrom<&'a OriginCaller> for &'a #pallet_origin { + type Error = (); + fn try_from( + x: &'a OriginCaller, + ) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> { + if let OriginCaller::#variant_name(l) = x { + Ok(&l) + } else { + Err(()) + } + } + } + + #attr + impl<'a> TryFrom<&'a RuntimeOrigin> for &'a #pallet_origin { + type Error = (); + fn try_from( + x: &'a RuntimeOrigin, + ) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> { + if let OriginCaller::#variant_name(l) = &x.caller { + Ok(&l) + } else { + Err(()) + } + } + } + } +} + +// Get the actual documentation using the doc information and system path name +fn get_intra_doc_string(doc_info: &str, system_path_name: &String) -> String { + format!(" {} [`{}::Config::BaseCallFilter`].", doc_info, system_path_name) +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs b/frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs new file mode 100644 index 0000000000000..48bcafdc1cc44 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs @@ -0,0 +1,281 @@ +// 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_v2::parse::pallets::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_v2/expand/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs deleted file mode 100644 index 57291412aa3d0..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/runtime_struct.rs +++ /dev/null @@ -1,26 +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_v2::expand::Def; - -pub fn expand_runtime_struct(def: &mut Def) -> proc_macro2::TokenStream { - let runtime_ident = &def.runtime_struct.ident; - - quote::quote_spanned!(def.runtime_struct.attr_span => - pub struct #runtime_ident; - ) -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs b/frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs new file mode 100644 index 0000000000000..0f0bacc89a51b --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs @@ -0,0 +1,68 @@ +// 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_v2::parse::pallets::{PalletPath, Pallet}; +use proc_macro2::{Ident, TokenStream}; +use quote::quote; + +pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { + let mut conversion_fns = Vec::new(); + let mut slash_reason_variants = Vec::new(); + for decl in pallet_decls { + if let Some(_) = decl.find_part("SlashReason") { + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + conversion_fns.push(expand_conversion_fn(path, variant_name)); + + slash_reason_variants.push(expand_variant(index, path, variant_name)); + } + } + + quote! { + /// A reason for slashing funds. + #[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, + #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, + #scrate::scale_info::TypeInfo, + #scrate::RuntimeDebug, + )] + pub enum RuntimeSlashReason { + #( #slash_reason_variants )* + } + + #( #conversion_fns )* + } +} + +fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + impl From<#path::SlashReason> for RuntimeSlashReason { + fn from(hr: #path::SlashReason) -> Self { + RuntimeSlashReason::#variant_name(hr) + } + } + } +} + +fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { + quote! { + #[codec(index = #index)] + #variant_name(#path::SlashReason), + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs new file mode 100644 index 0000000000000..dc593ad3cf1a7 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs @@ -0,0 +1,89 @@ +// 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_v2::parse::pallets::Pallet; +use proc_macro2::TokenStream; +use quote::quote; +use std::str::FromStr; +use syn::Ident; + +pub fn expand_outer_validate_unsigned( + runtime: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream, +) -> TokenStream { + let mut pallet_names = Vec::new(); + let mut pallet_attrs = Vec::new(); + let mut query_validate_unsigned_part_macros = Vec::new(); + + for pallet_decl in pallet_decls { + if pallet_decl.exists_part("ValidateUnsigned") { + let name = &pallet_decl.name; + let path = &pallet_decl.path; + let attr = pallet_decl.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 + } + }); + + pallet_names.push(name); + pallet_attrs.push(attr); + query_validate_unsigned_part_macros.push(quote! { + #path::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined!(#name); + }); + } + } + + quote! { + #( #query_validate_unsigned_part_macros )* + + impl #scrate::unsigned::ValidateUnsigned for #runtime { + type Call = RuntimeCall; + + fn pre_dispatch(call: &Self::Call) -> Result<(), #scrate::unsigned::TransactionValidityError> { + #[allow(unreachable_patterns)] + match call { + #( + #pallet_attrs + RuntimeCall::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), + )* + // pre-dispatch should not stop inherent extrinsics, validation should prevent + // including arbitrary (non-inherent) extrinsics to blocks. + _ => Ok(()), + } + } + + fn validate_unsigned( + #[allow(unused_variables)] + source: #scrate::unsigned::TransactionSource, + call: &Self::Call, + ) -> #scrate::unsigned::TransactionValidity { + #[allow(unreachable_patterns)] + match call { + #( + #pallet_attrs + RuntimeCall::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), + )* + _ => #scrate::unsigned::UnknownTransaction::NoUnsignedValidator.into(), + } + } + } + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index a0c9eb8ab1f02..c2e9844d5b44f 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -40,7 +40,6 @@ pub struct Def { impl Def { pub fn try_from(mut item: syn::ItemMod) -> syn::Result { let input_main: TokenStream2 = item.to_token_stream().into(); - println!("input_main: {}", input_main); let item_span = item.span(); let items = &mut item .content 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 83204583e3428..19c60eafa61ad 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -81,6 +81,106 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) .then_some(quote::quote!(SlashReason,)); +let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); + + let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,)); + + let event_part = def.event.as_ref().map(|event| { + let gen = event.gen_kind.is_generic().then(|| quote::quote!( )); + 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 , ) + }); + + let config_part = def.genesis_config.as_ref().map(|genesis_config| { + let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!( )); + quote::quote!( Config #gen , ) + }); + + let inherent_part = def.inherent.as_ref().map(|_| quote::quote!(Inherent,)); + + let validate_unsigned_part = + def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,)); + + let freeze_reason_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_))) + .then_some(quote::quote!(FreezeReason,)); + + let hold_reason_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_))) + .then_some(quote::quote!(HoldReason,)); + + let lock_id_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_))) + .then_some(quote::quote!(LockId,)); + + let slash_reason_part = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) + .then_some(quote::quote!(SlashReason,)); + + let call_part_v2 = def.call.as_ref().map(|_| quote::quote!(+ Call)); + + let storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage)); + + let event_part_v2 = def.event.as_ref().map(|event| { + let gen = event.gen_kind.is_generic().then(|| quote::quote!()); + quote::quote!(+ Event #gen) + }); + + let error_part_v2 = def.error.as_ref().map(|_| quote::quote!(+ Error)); + + let origin_part_v2 = def.origin.as_ref().map(|origin| { + let gen = origin.is_generic.then(|| quote::quote!()); + quote::quote!(+ Origin #gen) + }); + + let config_part_v2 = def.genesis_config.as_ref().map(|genesis_config| { + let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!()); + quote::quote!(+ Config #gen) + }); + + let inherent_part_v2 = def.inherent.as_ref().map(|_| quote::quote!(+ Inherent)); + + let validate_unsigned_part_v2 = + def.validate_unsigned.as_ref().map(|_| quote::quote!(+ ValidateUnsigned)); + + let freeze_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_))) + .then_some(quote::quote!(+ FreezeReason)); + + let hold_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_))) + .then_some(quote::quote!(+ HoldReason)); + + let lock_id_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_))) + .then_some(quote::quote!(+ LockId)); + + let slash_reason_part_v2 = def + .composites + .iter() + .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) + .then_some(quote::quote!(+ SlashReason)); + quote::quote!( // This macro follows the conventions as laid out by the `tt-call` crate. It does not // accept any arguments and simply returns the pallet parts, separated by commas, then @@ -151,7 +251,9 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { $($frame_support)*::tt_return! { $caller tokens = [{ - + Pallet + Call + + Pallet #call_part_v2 #storage_part_v2 #event_part_v2 #error_part_v2 #origin_part_v2 #config_part_v2 + #inherent_part_v2 #validate_unsigned_part_v2 #freeze_reason_part_v2 + #hold_reason_part_v2 #lock_id_part_v2 #slash_reason_part_v2 }] } }; From fff93b3f01a7481f2a39eb203d86712fdeca5cd7 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:35:35 +0530 Subject: [PATCH 09/19] Avoids duplication --- .../procedural/src/construct_runtime/mod.rs | 4 +- .../procedural/src/construct_runtime/parse.rs | 8 +- .../src/construct_runtime_v2/expand/call.rs | 211 -------- .../src/construct_runtime_v2/expand/config.rs | 140 ------ .../expand/freeze_reason.rs | 68 --- .../expand/hold_reason.rs | 68 --- .../construct_runtime_v2/expand/inherent.rs | 252 ---------- .../construct_runtime_v2/expand/lock_id.rs | 68 --- .../construct_runtime_v2/expand/metadata.rs | 258 ---------- .../src/construct_runtime_v2/expand/mod.rs | 40 +- .../src/construct_runtime_v2/expand/origin.rs | 456 ------------------ .../expand/outer_enums.rs | 281 ----------- .../expand/slash_reason.rs | 68 --- .../construct_runtime_v2/expand/unsigned.rs | 89 ---- .../src/construct_runtime_v2/parse/mod.rs | 1 + .../src/construct_runtime_v2/parse/pallets.rs | 248 +--------- 16 files changed, 27 insertions(+), 2233 deletions(-) delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/call.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/config.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/origin.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs delete mode 100644 frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 794042e37b79a..a186cfb38a0e8 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -208,8 +208,8 @@ //! This macro returns the ` :: expanded { Error }` list of additional parts we would like to //! expose. -mod expand; -mod parse; +pub mod expand; +pub mod parse; use cfg_expr::Predicate; use frame_support_procedural_tools::{ diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 9b08e16469754..b407b897e4106 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -446,7 +446,7 @@ impl Parse for PalletPartKeyword { impl PalletPartKeyword { /// Returns the name of `Self`. - fn name(&self) -> &'static str { + pub fn name(&self) -> &'static str { match self { Self::Pallet(_) => "Pallet", Self::Call(_) => "Call", @@ -465,12 +465,12 @@ impl PalletPartKeyword { } /// Returns `true` if this pallet part is allowed to have generic arguments. - fn allows_generic(&self) -> bool { + pub fn allows_generic(&self) -> bool { Self::all_generic_arg().iter().any(|n| *n == self.name()) } /// Returns the names of all pallet parts that allow to have a generic argument. - fn all_generic_arg() -> &'static [&'static str] { + pub fn all_generic_arg() -> &'static [&'static str] { &["Event", "Error", "Origin", "Config"] } } @@ -552,7 +552,7 @@ fn remove_kind( /// The declaration of a part without its generics #[derive(Debug, Clone)] pub struct PalletPartNoGeneric { - keyword: PalletPartKeyword, + pub keyword: PalletPartKeyword, } impl Parse for PalletPartNoGeneric { diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/call.rs b/frame/support/procedural/src/construct_runtime_v2/expand/call.rs deleted file mode 100644 index 60c206c899ee5..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/call.rs +++ /dev/null @@ -1,211 +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_v2::parse::pallets::Pallet; -use proc_macro2::TokenStream; -use quote::quote; -use std::str::FromStr; -use syn::Ident; - -pub fn expand_outer_dispatch( - runtime: &Ident, - system_pallet: &Pallet, - pallet_decls: &[Pallet], - scrate: &TokenStream, -) -> TokenStream { - let mut variant_defs = TokenStream::new(); - let mut variant_patterns = Vec::new(); - let mut query_call_part_macros = Vec::new(); - let mut pallet_names = Vec::new(); - let mut pallet_attrs = Vec::new(); - let system_path = &system_pallet.path; - - let pallets_with_call = pallet_decls.iter().filter(|decl| decl.exists_part("Call")); - - for pallet_declaration in pallets_with_call { - let name = &pallet_declaration.name; - let path = &pallet_declaration.path; - let index = pallet_declaration.index; - let attr = - pallet_declaration.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 - } - }); - - variant_defs.extend(quote! { - #attr - #[codec(index = #index)] - #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ), - }); - variant_patterns.push(quote!(RuntimeCall::#name(call))); - pallet_names.push(name); - pallet_attrs.push(attr); - query_call_part_macros.push(quote! { - #path::__substrate_call_check::is_call_part_defined!(#name); - }); - } - - quote! { - #( #query_call_part_macros )* - - #[derive( - Clone, PartialEq, Eq, - #scrate::codec::Encode, - #scrate::codec::Decode, - #scrate::scale_info::TypeInfo, - #scrate::RuntimeDebug, - )] - pub enum RuntimeCall { - #variant_defs - } - #[cfg(test)] - impl RuntimeCall { - /// Return a list of the module names together with their size in memory. - pub const fn sizes() -> &'static [( &'static str, usize )] { - use #scrate::dispatch::Callable; - use core::mem::size_of; - &[#( - #pallet_attrs - ( - stringify!(#pallet_names), - size_of::< <#pallet_names as Callable<#runtime>>::RuntimeCall >(), - ), - )*] - } - - /// Panics with diagnostic information if the size is greater than the given `limit`. - pub fn assert_size_under(limit: usize) { - let size = core::mem::size_of::(); - let call_oversize = size > limit; - if call_oversize { - println!("Size of `Call` is {} bytes (provided limit is {} bytes)", size, limit); - let mut sizes = Self::sizes().to_vec(); - sizes.sort_by_key(|x| -(x.1 as isize)); - for (i, &(name, size)) in sizes.iter().enumerate().take(5) { - println!("Offender #{}: {} at {} bytes", i + 1, name, size); - } - if let Some((_, next_size)) = sizes.get(5) { - println!("{} others of size {} bytes or less", sizes.len() - 5, next_size); - } - panic!( - "Size of `Call` is more than limit; use `Box` on complex parameter types to reduce the - size of `Call`. - If the limit is too strong, maybe consider providing a higher limit." - ); - } - } - } - impl #scrate::dispatch::GetDispatchInfo for RuntimeCall { - fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo { - match self { - #( - #pallet_attrs - #variant_patterns => call.get_dispatch_info(), - )* - } - } - } - - impl #scrate::dispatch::GetCallMetadata for RuntimeCall { - fn get_call_metadata(&self) -> #scrate::dispatch::CallMetadata { - use #scrate::dispatch::GetCallName; - match self { - #( - #pallet_attrs - #variant_patterns => { - let function_name = call.get_call_name(); - let pallet_name = stringify!(#pallet_names); - #scrate::dispatch::CallMetadata { function_name, pallet_name } - } - )* - } - } - - fn get_module_names() -> &'static [&'static str] { - &[#( - #pallet_attrs - stringify!(#pallet_names), - )*] - } - - fn get_call_names(module: &str) -> &'static [&'static str] { - use #scrate::dispatch::{Callable, GetCallName}; - match module { - #( - #pallet_attrs - stringify!(#pallet_names) => - <<#pallet_names as Callable<#runtime>>::RuntimeCall - as GetCallName>::get_call_names(), - )* - _ => unreachable!(), - } - } - } - impl #scrate::dispatch::Dispatchable for RuntimeCall { - type RuntimeOrigin = RuntimeOrigin; - type Config = RuntimeCall; - type Info = #scrate::dispatch::DispatchInfo; - type PostInfo = #scrate::dispatch::PostDispatchInfo; - fn dispatch(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { - if !::filter_call(&origin, &self) { - return #scrate::sp_std::result::Result::Err( - #system_path::Error::<#runtime>::CallFiltered.into() - ); - } - - #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) - } - } - impl #scrate::traits::UnfilteredDispatchable for RuntimeCall { - type RuntimeOrigin = RuntimeOrigin; - fn dispatch_bypass_filter(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { - match self { - #( - #pallet_attrs - #variant_patterns => - #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(call, origin), - )* - } - } - } - - #( - #pallet_attrs - impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { - #[allow(unreachable_patterns)] - fn is_sub_type(&self) -> Option<&#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> { - match self { - #variant_patterns => Some(call), - // May be unreachable - _ => None, - } - } - } - - #pallet_attrs - impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { - fn from(call: #scrate::dispatch::CallableCallFor<#pallet_names, #runtime>) -> Self { - #variant_patterns - } - } - )* - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/config.rs b/frame/support/procedural/src/construct_runtime_v2/expand/config.rs deleted file mode 100644 index 36b39e4cbd5d5..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/config.rs +++ /dev/null @@ -1,140 +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_v2::parse::pallets::Pallet; -use inflector::Inflector; -use proc_macro2::TokenStream; -use quote::{format_ident, quote, ToTokens}; -use std::str::FromStr; -use syn::Ident; - -pub fn expand_outer_config( - runtime: &Ident, - pallet_decls: &[Pallet], - scrate: &TokenStream, -) -> TokenStream { - let mut types = TokenStream::new(); - let mut fields = TokenStream::new(); - let mut genesis_build_calls = TokenStream::new(); - let mut query_genesis_config_part_macros = Vec::new(); - - for decl in pallet_decls { - if let Some(pallet_entry) = decl.find_part("Config") { - let path = &decl.path; - let pallet_name = &decl.name; - let path_str = path.into_token_stream().to_string(); - let config = format_ident!("{}Config", pallet_name); - let field_name = - &Ident::new(&pallet_name.to_string().to_snake_case(), decl.name.span()); - let part_is_generic = !pallet_entry.generics.params.is_empty(); - let attr = &decl.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 - } - }); - - types.extend(expand_config_types(attr, runtime, decl, &config, part_is_generic)); - fields.extend(quote!(#attr pub #field_name: #config,)); - genesis_build_calls - .extend(expand_config_build_storage_call(scrate, &config, attr, field_name)); - query_genesis_config_part_macros.push(quote! { - #path::__substrate_genesis_config_check::is_genesis_config_defined!(#pallet_name); - #[cfg(feature = "std")] - #path::__substrate_genesis_config_check::is_std_enabled_for_genesis!(#pallet_name, #path_str); - }); - } - } - - quote! { - #( #query_genesis_config_part_macros )* - - #types - - use #scrate::serde as __genesis_config_serde_import__; - #[derive(#scrate::serde::Serialize, #scrate::serde::Deserialize, Default)] - #[serde(rename_all = "camelCase")] - #[serde(deny_unknown_fields)] - #[serde(crate = "__genesis_config_serde_import__")] - pub struct RuntimeGenesisConfig { - #fields - } - - #[cfg(any(feature = "std", test))] - #[deprecated(note = "GenesisConfig is planned to be removed in December 2023. Use `RuntimeGenesisConfig` instead.")] - pub type GenesisConfig = RuntimeGenesisConfig; - - #[cfg(any(feature = "std", test))] - impl #scrate::sp_runtime::BuildStorage for RuntimeGenesisConfig { - fn assimilate_storage( - &self, - storage: &mut #scrate::sp_runtime::Storage, - ) -> std::result::Result<(), String> { - #scrate::BasicExternalities::execute_with_storage(storage, || { - ::build(&self); - Ok(()) - }) - } - } - - impl #scrate::traits::BuildGenesisConfig for RuntimeGenesisConfig { - fn build(&self) { - #genesis_build_calls - ::on_genesis(); - } - } - } -} - -fn expand_config_types( - attr: &TokenStream, - runtime: &Ident, - decl: &Pallet, - config: &Ident, - part_is_generic: bool, -) -> TokenStream { - let path = &decl.path; - - match (decl.instance.as_ref(), part_is_generic) { - (Some(inst), true) => quote! { - #attr - pub type #config = #path::GenesisConfig<#runtime, #path::#inst>; - }, - (None, true) => quote! { - #attr - pub type #config = #path::GenesisConfig<#runtime>; - }, - (_, false) => quote! { - #attr - pub type #config = #path::GenesisConfig; - }, - } -} - -fn expand_config_build_storage_call( - scrate: &TokenStream, - pallet_genesis_config: &Ident, - attr: &TokenStream, - field_name: &Ident, -) -> TokenStream { - quote! { - #attr - <#pallet_genesis_config as #scrate::traits::BuildGenesisConfig>::build(&self.#field_name); - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs b/frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs deleted file mode 100644 index 2a11e180c49e0..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/freeze_reason.rs +++ /dev/null @@ -1,68 +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_v2::parse::pallets::{PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -pub fn expand_outer_freeze_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { - let mut conversion_fns = Vec::new(); - let mut freeze_reason_variants = Vec::new(); - for decl in pallet_decls { - if let Some(_) = decl.find_part("FreezeReason") { - let variant_name = &decl.name; - let path = &decl.path; - let index = decl.index; - - conversion_fns.push(expand_conversion_fn(path, variant_name)); - - freeze_reason_variants.push(expand_variant(index, path, variant_name)); - } - } - - quote! { - /// A reason for placing a freeze on funds. - #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, - #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, - #scrate::scale_info::TypeInfo, - #scrate::RuntimeDebug, - )] - pub enum RuntimeFreezeReason { - #( #freeze_reason_variants )* - } - - #( #conversion_fns )* - } -} - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::FreezeReason> for RuntimeFreezeReason { - fn from(hr: #path::FreezeReason) -> Self { - RuntimeFreezeReason::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::FreezeReason), - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs b/frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs deleted file mode 100644 index 7f305e788c17d..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/hold_reason.rs +++ /dev/null @@ -1,68 +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_v2::parse::pallets::{PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -pub fn expand_outer_hold_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { - let mut conversion_fns = Vec::new(); - let mut hold_reason_variants = Vec::new(); - for decl in pallet_decls { - if let Some(_) = decl.find_part("HoldReason") { - let variant_name = &decl.name; - let path = &decl.path; - let index = decl.index; - - conversion_fns.push(expand_conversion_fn(path, variant_name)); - - hold_reason_variants.push(expand_variant(index, path, variant_name)); - } - } - - quote! { - /// A reason for placing a hold on funds. - #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, - #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, - #scrate::scale_info::TypeInfo, - #scrate::RuntimeDebug, - )] - pub enum RuntimeHoldReason { - #( #hold_reason_variants )* - } - - #( #conversion_fns )* - } -} - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::HoldReason> for RuntimeHoldReason { - fn from(hr: #path::HoldReason) -> Self { - RuntimeHoldReason::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::HoldReason), - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs b/frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs deleted file mode 100644 index 913328d974e47..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/inherent.rs +++ /dev/null @@ -1,252 +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_v2::parse::pallets::Pallet; -use proc_macro2::TokenStream; -use quote::quote; -use std::str::FromStr; -use syn::Ident; - -pub fn expand_outer_inherent( - runtime: &Ident, - block: &TokenStream, - unchecked_extrinsic: &TokenStream, - pallet_decls: &[Pallet], - scrate: &TokenStream, -) -> TokenStream { - let mut pallet_names = Vec::new(); - let mut pallet_attrs = Vec::new(); - let mut query_inherent_part_macros = Vec::new(); - - for pallet_decl in pallet_decls { - if pallet_decl.exists_part("Inherent") { - let name = &pallet_decl.name; - let path = &pallet_decl.path; - let attr = pallet_decl.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 - } - }); - - pallet_names.push(name); - pallet_attrs.push(attr); - query_inherent_part_macros.push(quote! { - #path::__substrate_inherent_check::is_inherent_part_defined!(#name); - }); - } - } - - quote! { - #( #query_inherent_part_macros )* - - trait InherentDataExt { - fn create_extrinsics(&self) -> - #scrate::sp_std::vec::Vec<<#block as #scrate::sp_runtime::traits::Block>::Extrinsic>; - fn check_extrinsics(&self, block: &#block) -> #scrate::inherent::CheckInherentsResult; - } - - impl InherentDataExt for #scrate::inherent::InherentData { - fn create_extrinsics(&self) -> - #scrate::sp_std::vec::Vec<<#block as #scrate::sp_runtime::traits::Block>::Extrinsic> - { - use #scrate::inherent::ProvideInherent; - - let mut inherents = #scrate::sp_std::vec::Vec::new(); - - #( - #pallet_attrs - if let Some(inherent) = #pallet_names::create_inherent(self) { - let inherent = <#unchecked_extrinsic as #scrate::sp_runtime::traits::Extrinsic>::new( - inherent.into(), - None, - ).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return \ - `Some`; qed"); - - inherents.push(inherent); - } - )* - - inherents - } - - fn check_extrinsics(&self, block: &#block) -> #scrate::inherent::CheckInherentsResult { - use #scrate::inherent::{ProvideInherent, IsFatalError}; - use #scrate::traits::{IsSubType, ExtrinsicCall}; - use #scrate::sp_runtime::traits::Block as _; - use #scrate::_private::sp_inherents::Error; - use #scrate::log; - - let mut result = #scrate::inherent::CheckInherentsResult::new(); - - // This handle assume we abort on the first fatal error. - fn handle_put_error_result(res: Result<(), Error>) { - const LOG_TARGET: &str = "runtime::inherent"; - match res { - Ok(()) => (), - Err(Error::InherentDataExists(id)) => - log::debug!( - target: LOG_TARGET, - "Some error already reported for inherent {:?}, new non fatal \ - error is ignored", - id - ), - Err(Error::FatalErrorReported) => - log::error!( - target: LOG_TARGET, - "Fatal error already reported, unexpected considering there is \ - only one fatal error", - ), - Err(_) => - log::error!( - target: LOG_TARGET, - "Unexpected error from `put_error` operation", - ), - } - } - - for xt in block.extrinsics() { - // Inherents are before any other extrinsics. - // And signed extrinsics are not inherents. - if #scrate::sp_runtime::traits::Extrinsic::is_signed(xt).unwrap_or(false) { - break - } - - let mut is_inherent = false; - - #( - #pallet_attrs - { - let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); - if let Some(call) = IsSubType::<_>::is_sub_type(call) { - if #pallet_names::is_inherent(call) { - is_inherent = true; - if let Err(e) = #pallet_names::check_inherent(call, self) { - handle_put_error_result(result.put_error( - #pallet_names::INHERENT_IDENTIFIER, &e - )); - if e.is_fatal_error() { - return result; - } - } - } - } - } - )* - - // Inherents are before any other extrinsics. - // No module marked it as inherent thus it is not. - if !is_inherent { - break - } - } - - #( - #pallet_attrs - match #pallet_names::is_inherent_required(self) { - Ok(Some(e)) => { - let found = block.extrinsics().iter().any(|xt| { - let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) - .unwrap_or(false); - - if !is_signed { - let call = < - #unchecked_extrinsic as ExtrinsicCall - >::call(xt); - if let Some(call) = IsSubType::<_>::is_sub_type(call) { - #pallet_names::is_inherent(&call) - } else { - false - } - } else { - // Signed extrinsics are not inherents. - false - } - }); - - if !found { - handle_put_error_result(result.put_error( - #pallet_names::INHERENT_IDENTIFIER, &e - )); - if e.is_fatal_error() { - return result; - } - } - }, - Ok(None) => (), - Err(e) => { - handle_put_error_result(result.put_error( - #pallet_names::INHERENT_IDENTIFIER, &e - )); - if e.is_fatal_error() { - return result; - } - }, - } - )* - - result - } - } - - impl #scrate::traits::EnsureInherentsAreFirst<#block> for #runtime { - fn ensure_inherents_are_first(block: &#block) -> Result<(), u32> { - use #scrate::inherent::ProvideInherent; - use #scrate::traits::{IsSubType, ExtrinsicCall}; - use #scrate::sp_runtime::traits::Block as _; - - let mut first_signed_observed = false; - - for (i, xt) in block.extrinsics().iter().enumerate() { - let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) - .unwrap_or(false); - - let is_inherent = if is_signed { - // Signed extrinsics are not inherents. - false - } else { - let mut is_inherent = false; - #( - #pallet_attrs - { - let call = <#unchecked_extrinsic as ExtrinsicCall>::call(xt); - if let Some(call) = IsSubType::<_>::is_sub_type(call) { - if #pallet_names::is_inherent(&call) { - is_inherent = true; - } - } - } - )* - is_inherent - }; - - if !is_inherent { - first_signed_observed = true; - } - - if first_signed_observed && is_inherent { - return Err(i as u32) - } - } - - Ok(()) - } - } - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs b/frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs deleted file mode 100644 index 94bfe276f34a1..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/lock_id.rs +++ /dev/null @@ -1,68 +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_v2::parse::pallets::{PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -pub fn expand_outer_lock_id(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { - let mut conversion_fns = Vec::new(); - let mut lock_id_variants = Vec::new(); - for decl in pallet_decls { - if let Some(_) = decl.find_part("LockId") { - let variant_name = &decl.name; - let path = &decl.path; - let index = decl.index; - - conversion_fns.push(expand_conversion_fn(path, variant_name)); - - lock_id_variants.push(expand_variant(index, path, variant_name)); - } - } - - quote! { - /// An identifier for each lock placed on funds. - #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, - #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, - #scrate::scale_info::TypeInfo, - #scrate::RuntimeDebug, - )] - pub enum RuntimeLockId { - #( #lock_id_variants )* - } - - #( #conversion_fns )* - } -} - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::LockId> for RuntimeLockId { - fn from(hr: #path::LockId) -> Self { - RuntimeLockId::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::LockId), - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs b/frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs deleted file mode 100644 index a7884d4f28767..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/metadata.rs +++ /dev/null @@ -1,258 +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_v2::parse::pallets::{PalletPath, Pallet}; -use proc_macro2::TokenStream; -use quote::quote; -use std::str::FromStr; -use syn::Ident; - -pub fn expand_runtime_metadata( - runtime: &Ident, - pallet_declarations: &[Pallet], - scrate: &TokenStream, - extrinsic: &TokenStream, - system_path: &PalletPath, -) -> TokenStream { - let pallets = pallet_declarations - .iter() - .filter_map(|pallet_declaration| { - pallet_declaration.find_part("Pallet").map(|_| { - let filtered_names: Vec<_> = pallet_declaration - .pallet_parts() - .iter() - .filter(|part| part.name() != "Pallet") - .map(|part| part.name()) - .collect(); - (pallet_declaration, filtered_names) - }) - }) - .map(|(decl, filtered_names)| { - let name = &decl.name; - let index = &decl.index; - let storage = expand_pallet_metadata_storage(&filtered_names, runtime, decl); - let calls = expand_pallet_metadata_calls(&filtered_names, runtime, decl); - let event = expand_pallet_metadata_events(&filtered_names, runtime, scrate, decl); - let constants = expand_pallet_metadata_constants(runtime, decl); - let errors = expand_pallet_metadata_errors(runtime, decl); - let docs = expand_pallet_metadata_docs(runtime, decl); - let attr = decl.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 - #scrate::metadata_ir::PalletMetadataIR { - name: stringify!(#name), - index: #index, - storage: #storage, - calls: #calls, - event: #event, - constants: #constants, - error: #errors, - docs: #docs, - } - } - }) - .collect::>(); - - quote! { - impl #runtime { - fn metadata_ir() -> #scrate::metadata_ir::MetadataIR { - // Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata. - // The function is implemented by calling `impl_runtime_apis!`. - // - // However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`. - // Rely on the `Deref` trait to differentiate between a runtime that implements - // APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!). - // - // Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function. - // `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`), - // while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`). - // - // Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!` - // when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!` - // is called. - // - // `Deref` needs a reference for resolving the function call. - let rt = #runtime; - - let ty = #scrate::scale_info::meta_type::<#extrinsic>(); - let address_ty = #scrate::scale_info::meta_type::< - <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureAddress - >(); - let call_ty = #scrate::scale_info::meta_type::< - <#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::Call - >(); - let signature_ty = #scrate::scale_info::meta_type::< - <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::Signature - >(); - let extra_ty = #scrate::scale_info::meta_type::< - <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureExtra - >(); - - #scrate::metadata_ir::MetadataIR { - pallets: #scrate::sp_std::vec![ #(#pallets),* ], - extrinsic: #scrate::metadata_ir::ExtrinsicMetadataIR { - ty, - version: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSION, - address_ty, - call_ty, - signature_ty, - extra_ty, - signed_extensions: < - < - #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata - >::SignedExtensions as #scrate::sp_runtime::traits::SignedExtension - >::metadata() - .into_iter() - .map(|meta| #scrate::metadata_ir::SignedExtensionMetadataIR { - identifier: meta.identifier, - ty: meta.ty, - additional_signed: meta.additional_signed, - }) - .collect(), - }, - 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::(), - } - } - } - - pub fn metadata() -> #scrate::metadata::RuntimeMetadataPrefixed { - // Note: this always returns the V14 version. The runtime API function - // must be deprecated. - #scrate::metadata_ir::into_v14(#runtime::metadata_ir()) - } - - pub fn metadata_at_version(version: u32) -> Option<#scrate::OpaqueMetadata> { - #scrate::metadata_ir::into_version(#runtime::metadata_ir(), version).map(|prefixed| { - #scrate::OpaqueMetadata::new(prefixed.into()) - }) - } - - pub fn metadata_versions() -> #scrate::sp_std::vec::Vec { - #scrate::metadata_ir::supported_versions() - } - } - } -} - -fn expand_pallet_metadata_storage( - filtered_names: &[&'static str], - runtime: &Ident, - decl: &Pallet, -) -> TokenStream { - if filtered_names.contains(&"Storage") { - let instance = decl.instance.as_ref().into_iter(); - let path = &decl.path; - - quote! { - Some(#path::Pallet::<#runtime #(, #path::#instance)*>::storage_metadata()) - } - } else { - quote!(None) - } -} - -fn expand_pallet_metadata_calls( - filtered_names: &[&'static str], - runtime: &Ident, - decl: &Pallet, -) -> TokenStream { - if filtered_names.contains(&"Call") { - let instance = decl.instance.as_ref().into_iter(); - let path = &decl.path; - - quote! { - Some(#path::Pallet::<#runtime #(, #path::#instance)*>::call_functions()) - } - } else { - quote!(None) - } -} - -fn expand_pallet_metadata_events( - filtered_names: &[&'static str], - runtime: &Ident, - scrate: &TokenStream, - decl: &Pallet, -) -> TokenStream { - if filtered_names.contains(&"Event") { - let path = &decl.path; - let part_is_generic = !decl - .find_part("Event") - .expect("Event part exists; qed") - .generics - .params - .is_empty(); - let pallet_event = match (decl.instance.as_ref(), 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), - }; - - quote! { - Some( - #scrate::metadata_ir::PalletEventMetadataIR { - ty: #scrate::scale_info::meta_type::<#pallet_event>() - } - ) - } - } else { - quote!(None) - } -} - -fn expand_pallet_metadata_constants(runtime: &Ident, decl: &Pallet) -> TokenStream { - let path = &decl.path; - let instance = decl.instance.as_ref().into_iter(); - - quote! { - #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_constants_metadata() - } -} - -fn expand_pallet_metadata_errors(runtime: &Ident, decl: &Pallet) -> TokenStream { - let path = &decl.path; - let instance = decl.instance.as_ref().into_iter(); - - quote! { - #path::Pallet::<#runtime #(, #path::#instance)*>::error_metadata() - } -} - -fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream { - let path = &decl.path; - let instance = decl.instance.as_ref().into_iter(); - - quote! { - #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata() - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index 1fca2be0e9aab..b88e3db1719ac 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -15,21 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod call; -mod config; -mod freeze_reason; -mod hold_reason; -mod inherent; -mod lock_id; -mod metadata; -mod origin; -mod outer_enums; -mod slash_reason; -mod unsigned; - use crate::construct_runtime_v2::Def; use crate::construct_runtime_v2::parse::pallets::{AllPalletsDeclaration, ExplicitAllPalletsDeclaration}; -use crate::construct_runtime_v2::parse::pallets::Pallet; use syn::{Ident, Result}; use quote::quote; use proc_macro2::TokenStream as TokenStream2; @@ -41,6 +28,9 @@ use std::str::FromStr; use itertools::Itertools; use cfg_expr::Predicate; +use crate::construct_runtime::expand; +use crate::construct_runtime::parse::Pallet; + /// The fixed name of the system pallet. const SYSTEM_PALLET_NAME: &str = "System"; @@ -111,30 +101,30 @@ fn construct_runtime_final_expansion( let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); let outer_event = - outer_enums::expand_outer_enum(&name, &pallets, &scrate, outer_enums::OuterEnumType::Event)?; + expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Event)?; let outer_error = - outer_enums::expand_outer_enum(&name, &pallets, &scrate, outer_enums::OuterEnumType::Error)?; + expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Error)?; - let outer_origin = origin::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?; + 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 = call::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); - let metadata = metadata::expand_runtime_metadata( + let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); + let metadata = expand::expand_runtime_metadata( &name, &pallets, &scrate, &unchecked_extrinsic, &system_pallet.path, ); - let outer_config = config::expand_outer_config(&name, &pallets, &scrate); + let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); let inherent = - inherent::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); - let validate_unsigned = unsigned::expand_outer_validate_unsigned(&name, &pallets, &scrate); - let freeze_reason = freeze_reason::expand_outer_freeze_reason(&pallets, &scrate); - let hold_reason = hold_reason::expand_outer_hold_reason(&pallets, &scrate); - let lock_id = lock_id::expand_outer_lock_id(&pallets, &scrate); - let slash_reason = slash_reason::expand_outer_slash_reason(&pallets, &scrate); + expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); + let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); + let freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate); + let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate); + let lock_id = expand::expand_outer_lock_id(&pallets, &scrate); + let slash_reason = expand::expand_outer_slash_reason(&pallets, &scrate); let integrity_test = decl_integrity_test(&scrate); let static_assertions = decl_static_assertions(&name, &pallets, &scrate); diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/origin.rs b/frame/support/procedural/src/construct_runtime_v2/expand/origin.rs deleted file mode 100644 index 1191a60f0c44b..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/origin.rs +++ /dev/null @@ -1,456 +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_v2::parse::pallets::Pallet; -use proc_macro2::TokenStream; -use quote::quote; -use std::str::FromStr; -use syn::{Generics, Ident}; -use crate::construct_runtime_v2::expand::SYSTEM_PALLET_NAME; - -pub fn expand_outer_origin( - runtime: &Ident, - system_pallet: &Pallet, - pallets: &[Pallet], - scrate: &TokenStream, -) -> syn::Result { - let mut caller_variants = TokenStream::new(); - let mut pallet_conversions = TokenStream::new(); - let mut query_origin_part_macros = Vec::new(); - - for pallet_decl in pallets.iter().filter(|pallet| pallet.name != SYSTEM_PALLET_NAME) { - if let Some(pallet_entry) = pallet_decl.find_part("Origin") { - let instance = pallet_decl.instance.as_ref(); - let index = pallet_decl.index; - let generics = &pallet_entry.generics; - let name = &pallet_decl.name; - let path = &pallet_decl.path; - - if instance.is_some() && generics.params.is_empty() { - let msg = format!( - "Instantiable pallet with no generic `Origin` cannot \ - be constructed: pallet `{}` must have generic `Origin`", - name - ); - return Err(syn::Error::new(name.span(), msg)) - } - - caller_variants.extend(expand_origin_caller_variant( - runtime, - pallet_decl, - index, - instance, - generics, - )); - pallet_conversions.extend(expand_origin_pallet_conversions( - scrate, - runtime, - pallet_decl, - instance, - generics, - )); - query_origin_part_macros.push(quote! { - #path::__substrate_origin_check::is_origin_part_defined!(#name); - }); - } - } - - let system_path = &system_pallet.path; - - let system_index = system_pallet.index; - - let system_path_name = system_path.module_name(); - - let doc_string = get_intra_doc_string( - "Origin is always created with the base filter configured in", - &system_path_name, - ); - - let doc_string_none_origin = - get_intra_doc_string("Create with system none origin and", &system_path_name); - - let doc_string_root_origin = - get_intra_doc_string("Create with system root origin and", &system_path_name); - - let doc_string_signed_origin = - get_intra_doc_string("Create with system signed origin and", &system_path_name); - - let doc_string_runtime_origin = - get_intra_doc_string("Convert to runtime origin, using as filter:", &system_path_name); - - let doc_string_runtime_origin_with_caller = get_intra_doc_string( - "Convert to runtime origin with caller being system signed or none and use filter", - &system_path_name, - ); - - Ok(quote! { - #( #query_origin_part_macros )* - - /// The runtime origin type representing the origin of a call. - /// - #[doc = #doc_string] - #[derive(Clone)] - pub struct RuntimeOrigin { - caller: OriginCaller, - filter: #scrate::sp_std::rc::Rc::RuntimeCall) -> bool>>, - } - - #[cfg(not(feature = "std"))] - impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { - fn fmt( - &self, - fmt: &mut #scrate::sp_std::fmt::Formatter, - ) -> #scrate::sp_std::result::Result<(), #scrate::sp_std::fmt::Error> { - fmt.write_str("") - } - } - - #[cfg(feature = "std")] - impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { - fn fmt( - &self, - fmt: &mut #scrate::sp_std::fmt::Formatter, - ) -> #scrate::sp_std::result::Result<(), #scrate::sp_std::fmt::Error> { - fmt.debug_struct("Origin") - .field("caller", &self.caller) - .field("filter", &"[function ptr]") - .finish() - } - } - - impl #scrate::traits::OriginTrait for RuntimeOrigin { - type Call = <#runtime as #system_path::Config>::RuntimeCall; - type PalletsOrigin = OriginCaller; - type AccountId = <#runtime as #system_path::Config>::AccountId; - - fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { - let f = self.filter.clone(); - - self.filter = #scrate::sp_std::rc::Rc::new(Box::new(move |call| { - f(call) && filter(call) - })); - } - - fn reset_filter(&mut self) { - let filter = < - <#runtime as #system_path::Config>::BaseCallFilter - as #scrate::traits::Contains<<#runtime as #system_path::Config>::RuntimeCall> - >::contains; - - self.filter = #scrate::sp_std::rc::Rc::new(Box::new(filter)); - } - - fn set_caller_from(&mut self, other: impl Into) { - self.caller = other.into().caller; - } - - fn filter_call(&self, call: &Self::Call) -> bool { - match self.caller { - // Root bypasses all filters - OriginCaller::system(#system_path::Origin::<#runtime>::Root) => true, - _ => (self.filter)(call), - } - } - - fn caller(&self) -> &Self::PalletsOrigin { - &self.caller - } - - fn into_caller(self) -> Self::PalletsOrigin { - self.caller - } - - fn try_with_caller( - mut self, - f: impl FnOnce(Self::PalletsOrigin) -> Result, - ) -> Result { - match f(self.caller) { - Ok(r) => Ok(r), - Err(caller) => { self.caller = caller; Err(self) } - } - } - - fn none() -> Self { - #system_path::RawOrigin::None.into() - } - - fn root() -> Self { - #system_path::RawOrigin::Root.into() - } - - fn signed(by: Self::AccountId) -> Self { - #system_path::RawOrigin::Signed(by).into() - } - } - - #[derive( - Clone, PartialEq, Eq, #scrate::RuntimeDebug, #scrate::codec::Encode, - #scrate::codec::Decode, #scrate::scale_info::TypeInfo, #scrate::codec::MaxEncodedLen, - )] - #[allow(non_camel_case_types)] - pub enum OriginCaller { - #[codec(index = #system_index)] - system(#system_path::Origin<#runtime>), - #caller_variants - #[allow(dead_code)] - Void(#scrate::Void) - } - - // For backwards compatibility and ease of accessing these functions. - #[allow(dead_code)] - impl RuntimeOrigin { - #[doc = #doc_string_none_origin] - pub fn none() -> Self { - ::none() - } - - #[doc = #doc_string_root_origin] - pub fn root() -> Self { - ::root() - } - - #[doc = #doc_string_signed_origin] - pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { - ::signed(by) - } - } - - impl From<#system_path::Origin<#runtime>> for OriginCaller { - fn from(x: #system_path::Origin<#runtime>) -> Self { - OriginCaller::system(x) - } - } - - impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller { - fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { - match self { - OriginCaller::system(x) => Some(x), - _ => None, - } - } - fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { - match &self { - OriginCaller::system(o) => Some(o), - _ => None, - } - } - } - - impl TryFrom for #system_path::Origin<#runtime> { - type Error = OriginCaller; - fn try_from(x: OriginCaller) - -> #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, OriginCaller> - { - if let OriginCaller::system(l) = x { - Ok(l) - } else { - Err(x) - } - } - } - - impl From<#system_path::Origin<#runtime>> for RuntimeOrigin { - - #[doc = #doc_string_runtime_origin] - fn from(x: #system_path::Origin<#runtime>) -> Self { - let o: OriginCaller = x.into(); - o.into() - } - } - - impl From for RuntimeOrigin { - fn from(x: OriginCaller) -> Self { - let mut o = RuntimeOrigin { - caller: x, - filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)), - }; - - #scrate::traits::OriginTrait::reset_filter(&mut o); - - o - } - } - - impl From for #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, RuntimeOrigin> { - /// NOTE: converting to pallet origin loses the origin filter information. - fn from(val: RuntimeOrigin) -> Self { - if let OriginCaller::system(l) = val.caller { - Ok(l) - } else { - Err(val) - } - } - } - impl From::AccountId>> for RuntimeOrigin { - #[doc = #doc_string_runtime_origin_with_caller] - fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self { - <#system_path::Origin<#runtime>>::from(x).into() - } - } - - #pallet_conversions - }) -} - -fn expand_origin_caller_variant( - runtime: &Ident, - pallet: &Pallet, - index: u8, - instance: Option<&Ident>, - generics: &Generics, -) -> TokenStream { - let part_is_generic = !generics.params.is_empty(); - let variant_name = &pallet.name; - let path = &pallet.path; - 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::Origin<#runtime, #path::#inst>), - }, - Some(inst) => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Origin<#path::#inst>), - }, - None if part_is_generic => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Origin<#runtime>), - }, - None => quote! { - #attr - #[codec(index = #index)] - #variant_name(#path::Origin), - }, - } -} - -fn expand_origin_pallet_conversions( - scrate: &TokenStream, - runtime: &Ident, - pallet: &Pallet, - instance: Option<&Ident>, - generics: &Generics, -) -> TokenStream { - let path = &pallet.path; - let variant_name = &pallet.name; - - let part_is_generic = !generics.params.is_empty(); - let pallet_origin = match instance { - Some(inst) if part_is_generic => quote!(#path::Origin<#runtime, #path::#inst>), - Some(inst) => quote!(#path::Origin<#path::#inst>), - None if part_is_generic => quote!(#path::Origin<#runtime>), - None => quote!(#path::Origin), - }; - - let doc_string = get_intra_doc_string(" Convert to runtime origin using", &path.module_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_origin> for OriginCaller { - fn from(x: #pallet_origin) -> Self { - OriginCaller::#variant_name(x) - } - } - - #attr - impl From<#pallet_origin> for RuntimeOrigin { - #[doc = #doc_string] - fn from(x: #pallet_origin) -> Self { - let x: OriginCaller = x.into(); - x.into() - } - } - - #attr - impl From for #scrate::sp_std::result::Result<#pallet_origin, RuntimeOrigin> { - /// NOTE: converting to pallet origin loses the origin filter information. - fn from(val: RuntimeOrigin) -> Self { - if let OriginCaller::#variant_name(l) = val.caller { - Ok(l) - } else { - Err(val) - } - } - } - - #attr - impl TryFrom for #pallet_origin { - type Error = OriginCaller; - fn try_from( - x: OriginCaller, - ) -> #scrate::sp_std::result::Result<#pallet_origin, OriginCaller> { - if let OriginCaller::#variant_name(l) = x { - Ok(l) - } else { - Err(x) - } - } - } - - #attr - impl<'a> TryFrom<&'a OriginCaller> for &'a #pallet_origin { - type Error = (); - fn try_from( - x: &'a OriginCaller, - ) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> { - if let OriginCaller::#variant_name(l) = x { - Ok(&l) - } else { - Err(()) - } - } - } - - #attr - impl<'a> TryFrom<&'a RuntimeOrigin> for &'a #pallet_origin { - type Error = (); - fn try_from( - x: &'a RuntimeOrigin, - ) -> #scrate::sp_std::result::Result<&'a #pallet_origin, ()> { - if let OriginCaller::#variant_name(l) = &x.caller { - Ok(&l) - } else { - Err(()) - } - } - } - } -} - -// Get the actual documentation using the doc information and system path name -fn get_intra_doc_string(doc_info: &str, system_path_name: &String) -> String { - format!(" {} [`{}::Config::BaseCallFilter`].", doc_info, system_path_name) -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs b/frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs deleted file mode 100644 index 48bcafdc1cc44..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/outer_enums.rs +++ /dev/null @@ -1,281 +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_v2::parse::pallets::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_v2/expand/slash_reason.rs b/frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs deleted file mode 100644 index 0f0bacc89a51b..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/slash_reason.rs +++ /dev/null @@ -1,68 +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_v2::parse::pallets::{PalletPath, Pallet}; -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -pub fn expand_outer_slash_reason(pallet_decls: &[Pallet], scrate: &TokenStream) -> TokenStream { - let mut conversion_fns = Vec::new(); - let mut slash_reason_variants = Vec::new(); - for decl in pallet_decls { - if let Some(_) = decl.find_part("SlashReason") { - let variant_name = &decl.name; - let path = &decl.path; - let index = decl.index; - - conversion_fns.push(expand_conversion_fn(path, variant_name)); - - slash_reason_variants.push(expand_variant(index, path, variant_name)); - } - } - - quote! { - /// A reason for slashing funds. - #[derive( - Copy, Clone, Eq, PartialEq, Ord, PartialOrd, - #scrate::codec::Encode, #scrate::codec::Decode, #scrate::codec::MaxEncodedLen, - #scrate::scale_info::TypeInfo, - #scrate::RuntimeDebug, - )] - pub enum RuntimeSlashReason { - #( #slash_reason_variants )* - } - - #( #conversion_fns )* - } -} - -fn expand_conversion_fn(path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - impl From<#path::SlashReason> for RuntimeSlashReason { - fn from(hr: #path::SlashReason) -> Self { - RuntimeSlashReason::#variant_name(hr) - } - } - } -} - -fn expand_variant(index: u8, path: &PalletPath, variant_name: &Ident) -> TokenStream { - quote! { - #[codec(index = #index)] - #variant_name(#path::SlashReason), - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs deleted file mode 100644 index dc593ad3cf1a7..0000000000000 --- a/frame/support/procedural/src/construct_runtime_v2/expand/unsigned.rs +++ /dev/null @@ -1,89 +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_v2::parse::pallets::Pallet; -use proc_macro2::TokenStream; -use quote::quote; -use std::str::FromStr; -use syn::Ident; - -pub fn expand_outer_validate_unsigned( - runtime: &Ident, - pallet_decls: &[Pallet], - scrate: &TokenStream, -) -> TokenStream { - let mut pallet_names = Vec::new(); - let mut pallet_attrs = Vec::new(); - let mut query_validate_unsigned_part_macros = Vec::new(); - - for pallet_decl in pallet_decls { - if pallet_decl.exists_part("ValidateUnsigned") { - let name = &pallet_decl.name; - let path = &pallet_decl.path; - let attr = pallet_decl.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 - } - }); - - pallet_names.push(name); - pallet_attrs.push(attr); - query_validate_unsigned_part_macros.push(quote! { - #path::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined!(#name); - }); - } - } - - quote! { - #( #query_validate_unsigned_part_macros )* - - impl #scrate::unsigned::ValidateUnsigned for #runtime { - type Call = RuntimeCall; - - fn pre_dispatch(call: &Self::Call) -> Result<(), #scrate::unsigned::TransactionValidityError> { - #[allow(unreachable_patterns)] - match call { - #( - #pallet_attrs - RuntimeCall::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), - )* - // pre-dispatch should not stop inherent extrinsics, validation should prevent - // including arbitrary (non-inherent) extrinsics to blocks. - _ => Ok(()), - } - } - - fn validate_unsigned( - #[allow(unused_variables)] - source: #scrate::unsigned::TransactionSource, - call: &Self::Call, - ) -> #scrate::unsigned::TransactionValidity { - #[allow(unreachable_patterns)] - match call { - #( - #pallet_attrs - RuntimeCall::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), - )* - _ => #scrate::unsigned::UnknownTransaction::NoUnsignedValidator.into(), - } - } - } - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index c2e9844d5b44f..df643a63439a4 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -30,6 +30,7 @@ use frame_support_procedural_tools::{ generate_crate_access, generate_crate_access_2018, generate_hidden_includes, }; use proc_macro2::TokenStream as TokenStream2; +use crate::construct_runtime::parse::Pallet; pub struct Def { pub item: syn::ItemMod, diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index cda51957c098b..25880294d0655 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -26,6 +26,11 @@ use syn::{ spanned::Spanned, token, Attribute, Error, Ident, Path, Result, Token, }; +use crate::construct_runtime::parse::PalletPartKeyword; +use crate::construct_runtime::parse::PalletPath; +use crate::construct_runtime::parse::PalletPart; +use crate::construct_runtime::parse::PalletPartNoGeneric; +use crate::construct_runtime::parse::Pallet; mod keyword { syn::custom_keyword!(Pallet); @@ -227,59 +232,6 @@ impl Parse for PalletDeclaration { } } -/// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard -/// Rust path with a few restrictions: -/// - No leading colons allowed -/// - Path segments can only consist of identifers separated by colons -#[derive(Debug, Clone)] -pub struct PalletPath { - pub inner: Path, -} - -impl PalletPath { - pub fn module_name(&self) -> String { - self.inner.segments.iter().fold(String::new(), |mut acc, segment| { - if !acc.is_empty() { - acc.push_str("::"); - } - acc.push_str(&segment.ident.to_string()); - acc - }) - } -} - -impl Parse for PalletPath { - fn parse(input: ParseStream) -> Result { - let mut res = - PalletPath { inner: Path { leading_colon: None, segments: Punctuated::new() } }; - - let lookahead = input.lookahead1(); - if lookahead.peek(Token![crate]) || - lookahead.peek(Token![self]) || - lookahead.peek(Token![super]) || - lookahead.peek(Ident) - { - let ident = input.call(Ident::parse_any)?; - res.inner.segments.push(ident.into()); - } else { - return Err(lookahead.error()) - } - - while input.peek(Token![::]) && input.peek3(Ident) { - input.parse::()?; - let ident = input.parse::()?; - res.inner.segments.push(ident.into()); - } - Ok(res) - } -} - -impl quote::ToTokens for PalletPath { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.inner.to_tokens(tokens); - } -} - /// Parse [`PalletPart`]'s from a braces enclosed list that is split by commas, e.g. /// /// `{ Call, Event }` @@ -301,160 +253,6 @@ fn parse_pallet_parts(input: ParseStream) -> Result> { Ok(pallet_parts.into_iter().collect()) } -#[derive(Debug, Clone)] -pub enum PalletPartKeyword { - Pallet(keyword::Pallet), - Call(keyword::Call), - Storage(keyword::Storage), - Event(keyword::Event), - Error(keyword::Error), - Config(keyword::Config), - Origin(keyword::Origin), - Inherent(keyword::Inherent), - ValidateUnsigned(keyword::ValidateUnsigned), - FreezeReason(keyword::FreezeReason), - HoldReason(keyword::HoldReason), - LockId(keyword::LockId), - SlashReason(keyword::SlashReason), -} - -impl Parse for PalletPartKeyword { - fn parse(input: ParseStream) -> Result { - let lookahead = input.lookahead1(); - - if lookahead.peek(keyword::Pallet) { - Ok(Self::Pallet(input.parse()?)) - } else if lookahead.peek(keyword::Call) { - Ok(Self::Call(input.parse()?)) - } else if lookahead.peek(keyword::Storage) { - 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) { - Ok(Self::Origin(input.parse()?)) - } else if lookahead.peek(keyword::Inherent) { - Ok(Self::Inherent(input.parse()?)) - } else if lookahead.peek(keyword::ValidateUnsigned) { - Ok(Self::ValidateUnsigned(input.parse()?)) - } else if lookahead.peek(keyword::FreezeReason) { - Ok(Self::FreezeReason(input.parse()?)) - } else if lookahead.peek(keyword::HoldReason) { - Ok(Self::HoldReason(input.parse()?)) - } else if lookahead.peek(keyword::LockId) { - Ok(Self::LockId(input.parse()?)) - } else if lookahead.peek(keyword::SlashReason) { - Ok(Self::SlashReason(input.parse()?)) - } else { - Err(lookahead.error()) - } - } -} - -impl PalletPartKeyword { - /// Returns the name of `Self`. - fn name(&self) -> &'static str { - match self { - Self::Pallet(_) => "Pallet", - Self::Call(_) => "Call", - Self::Storage(_) => "Storage", - Self::Event(_) => "Event", - Self::Error(_) => "Error", - Self::Config(_) => "Config", - Self::Origin(_) => "Origin", - Self::Inherent(_) => "Inherent", - Self::ValidateUnsigned(_) => "ValidateUnsigned", - Self::FreezeReason(_) => "FreezeReason", - Self::HoldReason(_) => "HoldReason", - Self::LockId(_) => "LockId", - Self::SlashReason(_) => "SlashReason", - } - } - - /// Returns `true` if this pallet part is allowed to have generic arguments. - fn allows_generic(&self) -> bool { - Self::all_generic_arg().iter().any(|n| *n == self.name()) - } - - /// Returns the names of all pallet parts that allow to have a generic argument. - fn all_generic_arg() -> &'static [&'static str] { - &["Event", "Error", "Origin", "Config"] - } -} - -impl ToTokens for PalletPartKeyword { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Self::Pallet(inner) => inner.to_tokens(tokens), - 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), - Self::ValidateUnsigned(inner) => inner.to_tokens(tokens), - Self::FreezeReason(inner) => inner.to_tokens(tokens), - Self::HoldReason(inner) => inner.to_tokens(tokens), - Self::LockId(inner) => inner.to_tokens(tokens), - Self::SlashReason(inner) => inner.to_tokens(tokens), - } - } -} - -#[derive(Debug, Clone)] -pub struct PalletPart { - pub keyword: PalletPartKeyword, - pub generics: syn::Generics, -} - -impl Parse for PalletPart { - fn parse(input: ParseStream) -> Result { - let keyword: PalletPartKeyword = input.parse()?; - - let generics: syn::Generics = input.parse()?; - if !generics.params.is_empty() && !keyword.allows_generic() { - let valid_generics = PalletPart::format_names(PalletPartKeyword::all_generic_arg()); - let msg = format!( - "`{}` is not allowed to have generics. \ - Only the following pallets are allowed to have generics: {}.", - keyword.name(), - valid_generics, - ); - return Err(syn::Error::new(keyword.span(), msg)) - } - - Ok(Self { keyword, generics }) - } -} - -impl PalletPart { - pub fn format_names(names: &[&'static str]) -> String { - let res: Vec<_> = names.iter().map(|s| format!("`{}`", s)).collect(); - res.join(", ") - } - - /// The name of this pallet part. - pub fn name(&self) -> &'static str { - self.keyword.name() - } -} - -/// The declaration of a part without its generics -#[derive(Debug, Clone)] -pub struct PalletPartNoGeneric { - keyword: PalletPartKeyword, -} - -impl Parse for PalletPartNoGeneric { - fn parse(input: ParseStream) -> Result { - Ok(Self { keyword: input.parse()? }) - } -} - /// Parse [`PalletPartNoGeneric`]'s from a braces enclosed list that is split by commas, e.g. /// /// `{ Call, Event }` @@ -476,42 +274,6 @@ fn parse_pallet_parts_no_generic(input: ParseStream) -> Result`. - pub instance: Option, - /// The pallet parts to use for the pallet. - pub pallet_parts: Vec, - /// Expressions specified inside of a #[cfg] attribute. - pub cfg_pattern: Vec, -} - -impl Pallet { - /// Get resolved pallet parts - pub fn pallet_parts(&self) -> &[PalletPart] { - &self.pallet_parts - } - - /// Find matching parts - pub fn find_part(&self, name: &str) -> Option<&PalletPart> { - self.pallet_parts.iter().find(|part| part.name() == name) - } - - /// Return whether pallet contains part - pub fn exists_part(&self, name: &str) -> bool { - self.find_part(name).is_some() - } -} - /// Result of a conversion of a declaration of pallets. /// /// # State Transitions From b7827790a689271b1cb59b1f24178dbbfe19778d Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Thu, 17 Aug 2023 20:03:48 +0530 Subject: [PATCH 10/19] Builds kitchensink as well --- bin/node/runtime/src/lib.rs | 14 +- .../procedural/src/construct_runtime/mod.rs | 8 +- .../src/construct_runtime_v2/expand/mod.rs | 307 +----------------- .../src/construct_runtime_v2/parse/pallets.rs | 44 ++- .../src/pallet/expand/tt_default_parts.rs | 50 --- 5 files changed, 39 insertions(+), 384 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4e1b6d4e8bec0..b3a70821a194e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1876,9 +1876,13 @@ impl pallet_statement::Config for Runtime { type MaxAllowedBytes = MaxAllowedBytes; } -construct_runtime!( - pub struct Runtime - { +#[frame_support::construct_runtime_v2] +mod runtime { + #[frame::runtime] + pub struct Runtime; + + #[frame::pallets] + pub struct Pallets { System: frame_system, Utility: pallet_utility, Babe: pallet_babe, @@ -1907,7 +1911,7 @@ construct_runtime!( ImOnline: pallet_im_online, AuthorityDiscovery: pallet_authority_discovery, Offences: pallet_offences, - Historical: pallet_session_historical::{Pallet}, + Historical: pallet_session_historical + Pallet, RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, Identity: pallet_identity, Society: pallet_society, @@ -1950,7 +1954,7 @@ construct_runtime!( Pov: frame_benchmarking_pallet_pov, Statement: pallet_statement, } -); +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index a186cfb38a0e8..20ffcb26b5cdc 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -496,7 +496,7 @@ fn construct_runtime_final_expansion( Ok(res) } -fn decl_all_pallets<'a>( +pub fn decl_all_pallets<'a>( runtime: &'a Ident, pallet_declarations: impl Iterator, features: &HashSet<&str>, @@ -660,7 +660,7 @@ fn decl_all_pallets<'a>( ) } -fn decl_pallet_runtime_setup( +pub fn decl_pallet_runtime_setup( runtime: &Ident, pallet_declarations: &[Pallet], scrate: &TokenStream2, @@ -752,7 +752,7 @@ fn decl_pallet_runtime_setup( ) } -fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { +pub fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { quote!( #[cfg(test)] mod __construct_runtime_integrity_test { @@ -767,7 +767,7 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { ) } -fn decl_static_assertions( +pub fn decl_static_assertions( runtime: &Ident, pallet_decls: &[Pallet], scrate: &TokenStream2, diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index b88e3db1719ac..d2b278273cb6e 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -31,6 +31,11 @@ use cfg_expr::Predicate; use crate::construct_runtime::expand; use crate::construct_runtime::parse::Pallet; +use crate::construct_runtime::decl_all_pallets; +use crate::construct_runtime::decl_pallet_runtime_setup; +use crate::construct_runtime::decl_integrity_test; +use crate::construct_runtime::decl_static_assertions; + /// The fixed name of the system pallet. const SYSTEM_PALLET_NAME: &str = "System"; @@ -206,305 +211,3 @@ fn construct_runtime_final_expansion( Ok(res) } - -fn decl_all_pallets<'a>( - runtime: &'a Ident, - pallet_declarations: impl Iterator, - features: &HashSet<&str>, -) -> TokenStream2 { - let mut types = TokenStream2::new(); - - // Every feature set to the pallet names that should be included by this feature set. - let mut features_to_names = features - .iter() - .map(|f| *f) - .powerset() - .map(|feat| (HashSet::from_iter(feat), Vec::new())) - .collect::, Vec<_>)>>(); - - for pallet_declaration in pallet_declarations { - let type_name = &pallet_declaration.name; - let pallet = &pallet_declaration.path; - let mut generics = vec![quote!(#runtime)]; - generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name))); - let mut attrs = Vec::new(); - for cfg in &pallet_declaration.cfg_pattern { - let feat = format!("#[cfg({})]\n", cfg.original()); - attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed")); - } - let type_decl = quote!( - #(#attrs)* - pub type #type_name = #pallet::Pallet <#(#generics),*>; - ); - types.extend(type_decl); - - if pallet_declaration.cfg_pattern.is_empty() { - for (_, names) in features_to_names.iter_mut() { - names.push(&pallet_declaration.name); - } - } else { - for (feature_set, names) in &mut features_to_names { - // Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the - // predicates listed in all `#[cfg]` attributes are effectively joined by `and()`, - // meaning that all of them must match in order to activate the item - let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| { - expr.eval(|pred| match pred { - Predicate::Feature(f) => feature_set.contains(f), - Predicate::Test => feature_set.contains(&"test"), - _ => false, - }) - }); - - if is_feature_active { - names.push(&pallet_declaration.name); - } - } - } - } - - // All possible features. This will be used below for the empty feature set. - let mut all_features = features_to_names - .iter() - .flat_map(|f| f.0.iter().cloned()) - .collect::>(); - let attribute_to_names = features_to_names - .into_iter() - .map(|(mut features, names)| { - // If this is the empty feature set, it needs to be changed to negate all available - // features. So, we ensure that there is some type declared when all features are not - // enabled. - if features.is_empty() { - let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter(); - let features = all_features.iter(); - let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]); - - (attr, names) - } else { - let test_cfg = features.remove("test").then_some(quote!(test)).into_iter(); - let disabled_features = all_features.difference(&features); - let features = features.iter(); - let attr = quote!(#[cfg(all( #(#test_cfg,)* #(feature = #features,)* #(not(feature = #disabled_features)),* ))]); - - (attr, names) - } - }) - .collect::>(); - - let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| { - let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types. - /// Excludes the System pallet. - pub type AllPalletsWithoutSystem = ( #(#names,)* ); - } - }); - - let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| { - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types. - pub type AllPalletsWithSystem = ( #(#names,)* ); - } - }); - - let all_pallets_without_system_reversed = attribute_to_names.iter().map(|(attr, names)| { - let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// Excludes the System pallet. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletsWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); - } - }); - - let all_pallets_with_system_reversed = attribute_to_names.iter().map(|(attr, names)| { - let names = names.iter().rev(); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletsWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithSystemReversed = ( #(#names,)* ); - } - }); - - let all_pallets_reversed_with_system_first = attribute_to_names.iter().map(|(attr, names)| { - let system = quote::format_ident!("{}", SYSTEM_PALLET_NAME); - let names = std::iter::once(&system) - .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME).cloned()); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// With the system pallet first. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletsWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); - } - }); - - quote!( - #types - - /// All pallets included in the runtime as a nested tuple of types. - #[deprecated(note = "The type definition has changed from representing all pallets \ - excluding system, in reversed order to become the representation of all pallets \ - including system pallet in regular order. For this reason it is encouraged to use \ - explicitly one of `AllPalletsWithSystem`, `AllPalletsWithoutSystem`, \ - `AllPalletsWithSystemReversed`, `AllPalletsWithoutSystemReversed`. \ - Note that the type `frame_executive::Executive` expects one of `AllPalletsWithSystem` \ - , `AllPalletsWithSystemReversed`, `AllPalletsReversedWithSystemFirst`. More details in \ - https://github.com/paritytech/substrate/pull/10043")] - pub type AllPallets = AllPalletsWithSystem; - - #( #all_pallets_with_system )* - - #( #all_pallets_without_system )* - - #( #all_pallets_with_system_reversed )* - - #( #all_pallets_without_system_reversed )* - - #( #all_pallets_reversed_with_system_first )* - ) -} - -fn decl_pallet_runtime_setup( - runtime: &Ident, - pallet_declarations: &[Pallet], - scrate: &TokenStream2, -) -> TokenStream2 { - let names = pallet_declarations.iter().map(|d| &d.name).collect::>(); - let name_strings = pallet_declarations.iter().map(|d| d.name.to_string()); - let module_names = pallet_declarations.iter().map(|d| d.path.module_name()); - let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize); - let pallet_structs = pallet_declarations - .iter() - .map(|pallet| { - let path = &pallet.path; - match pallet.instance.as_ref() { - Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>), - None => quote!(#path::Pallet<#runtime>), - } - }) - .collect::>(); - let pallet_attrs = pallet_declarations - .iter() - .map(|pallet| { - pallet.cfg_pattern.iter().fold(TokenStream2::new(), |acc, pattern| { - let attr = TokenStream2::from_str(&format!("#[cfg({})]", pattern.original())) - .expect("was successfully parsed before; qed"); - quote! { - #acc - #attr - } - }) - }) - .collect::>(); - - quote!( - /// Provides an implementation of `PalletInfo` to provide information - /// about the pallet setup in the runtime. - pub struct PalletInfo; - - impl #scrate::traits::PalletInfo for PalletInfo { - fn index() -> Option { - let type_id = #scrate::sp_std::any::TypeId::of::

(); - #( - #pallet_attrs - if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { - return Some(#indices) - } - )* - - None - } - - fn name() -> Option<&'static str> { - let type_id = #scrate::sp_std::any::TypeId::of::

(); - #( - #pallet_attrs - if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { - return Some(#name_strings) - } - )* - - None - } - - fn module_name() -> Option<&'static str> { - let type_id = #scrate::sp_std::any::TypeId::of::

(); - #( - #pallet_attrs - if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { - return Some(#module_names) - } - )* - - None - } - - fn crate_version() -> Option<#scrate::traits::CrateVersion> { - let type_id = #scrate::sp_std::any::TypeId::of::

(); - #( - #pallet_attrs - if type_id == #scrate::sp_std::any::TypeId::of::<#names>() { - return Some( - <#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version() - ) - } - )* - - None - } - } - ) -} - -fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { - quote!( - #[cfg(test)] - mod __construct_runtime_integrity_test { - use super::*; - - #[test] - pub fn runtime_integrity_tests() { - #scrate::sp_tracing::try_init_simple(); - ::integrity_test(); - } - } - ) -} - -fn decl_static_assertions( - runtime: &Ident, - pallet_decls: &[Pallet], - scrate: &TokenStream2, -) -> TokenStream2 { - let error_encoded_size_check = pallet_decls.iter().map(|decl| { - let path = &decl.path; - let assert_message = format!( - "The maximum encoded size of the error type in the `{}` pallet exceeds \ - `MAX_MODULE_ERROR_ENCODED_SIZE`", - decl.name, - ); - - quote! { - #scrate::tt_call! { - macro = [{ #path::tt_error_token }] - frame_support = [{ #scrate }] - ~~> #scrate::assert_error_encoded_size! { - path = [{ #path }] - runtime = [{ #runtime }] - assert_message = [{ #assert_message }] - } - } - } - }); - - quote! { - #(#error_encoded_size_check)* - } -} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index 25880294d0655..d2dd2d6693ed1 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -146,28 +146,26 @@ impl Parse for PalletDeclaration { let path = input.parse()?; // println!("path: {:?}", path); - // // Parse for instance. - // let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { - // let _: Token![::] = input.parse()?; - // let _: Token![<] = input.parse()?; - // let res = Some(input.parse()?); - // let _: Token![>] = input.parse()?; - // res - // } else if !(input.peek(Token![+])) && - // !input.peek(keyword::expanded) && - // !input.peek(keyword::exclude_parts) && - // !input.peek(keyword::use_parts) && - // !input.peek(Token![=]) && - // !input.peek(Token![,]) && - // !input.is_empty() - // { - // return Err(input.error( - // "Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`", - // )); - // } else { - // None - // }; - let instance = None; + // Parse for instance. + let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { + let _: Token![::] = input.parse()?; + let _: Token![<] = input.parse()?; + let res = Some(input.parse()?); + let _: Token![>] = input.parse()?; + res + } else if !(input.peek(Token![+])) && + !input.peek(keyword::exclude_parts) && + !input.peek(keyword::use_parts) && + !input.peek(Token![=]) && + !input.peek(Token![,]) && + !input.is_empty() + { + return Err(input.error( + "Unexpected tokens, expected one of `::$ident` `+`, `exclude_parts`, `use_parts`, `=`, `,`", + )); + } else { + None + }; // // Check if the pallet is fully expanded. // let (is_expanded, extra_parts) = if input.peek(keyword::expanded) { @@ -193,7 +191,7 @@ impl Parse for PalletDeclaration { !input.is_empty() { return Err(input.error( - "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", + "Unexpected tokens, expected one of `+`, `exclude_parts`, `use_parts`, `=`, `,`", )) } else { is_expanded.then_some(extra_parts) 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 19c60eafa61ad..371ec6c60ec2c 100644 --- a/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -81,56 +81,6 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) .then_some(quote::quote!(SlashReason,)); -let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); - - let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,)); - - let event_part = def.event.as_ref().map(|event| { - let gen = event.gen_kind.is_generic().then(|| quote::quote!( )); - 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 , ) - }); - - let config_part = def.genesis_config.as_ref().map(|genesis_config| { - let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!( )); - quote::quote!( Config #gen , ) - }); - - let inherent_part = def.inherent.as_ref().map(|_| quote::quote!(Inherent,)); - - let validate_unsigned_part = - def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,)); - - let freeze_reason_part = def - .composites - .iter() - .any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_))) - .then_some(quote::quote!(FreezeReason,)); - - let hold_reason_part = def - .composites - .iter() - .any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_))) - .then_some(quote::quote!(HoldReason,)); - - let lock_id_part = def - .composites - .iter() - .any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_))) - .then_some(quote::quote!(LockId,)); - - let slash_reason_part = def - .composites - .iter() - .any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_))) - .then_some(quote::quote!(SlashReason,)); - let call_part_v2 = def.call.as_ref().map(|_| quote::quote!(+ Call)); let storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage)); From b43e52cac473d88c502478fd36a63b7552c450fe Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:06:35 +0530 Subject: [PATCH 11/19] Uses syn parsing --- .../src/construct_runtime_v2/expand/mod.rs | 111 +++-- .../src/construct_runtime_v2/mod.rs | 16 +- .../src/construct_runtime_v2/parse/mod.rs | 170 +++---- .../src/construct_runtime_v2/parse/pallets.rs | 460 +++++------------- .../parse/runtime_struct.rs | 15 +- frame/support/src/lib.rs | 3 +- 6 files changed, 276 insertions(+), 499 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index d2b278273cb6e..af23f86a05f4f 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -15,61 +15,92 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::construct_runtime_v2::Def; -use crate::construct_runtime_v2::parse::pallets::{AllPalletsDeclaration, ExplicitAllPalletsDeclaration}; -use syn::{Ident, Result}; -use quote::quote; +use crate::construct_runtime_v2::{ + parse::pallets::{ + AllPalletsDeclaration, ExplicitAllPalletsDeclaration, ImplicitAllPalletsDeclaration, + }, + Def, +}; +use cfg_expr::Predicate; +use frame_support_procedural_tools::{ + generate_crate_access, generate_crate_access_2018, generate_hidden_includes, +}; use proc_macro2::TokenStream as TokenStream2; +use quote::quote; use std::collections::HashSet; -use frame_support_procedural_tools::generate_crate_access; -use frame_support_procedural_tools::generate_hidden_includes; -use frame_support_procedural_tools::generate_crate_access_2018; -use std::str::FromStr; -use itertools::Itertools; -use cfg_expr::Predicate; +use syn::{Ident, Result}; -use crate::construct_runtime::expand; -use crate::construct_runtime::parse::Pallet; +use crate::construct_runtime::{check_pallet_number, expand}; -use crate::construct_runtime::decl_all_pallets; -use crate::construct_runtime::decl_pallet_runtime_setup; -use crate::construct_runtime::decl_integrity_test; -use crate::construct_runtime::decl_static_assertions; +use crate::construct_runtime::{ + decl_all_pallets, decl_integrity_test, decl_pallet_runtime_setup, decl_static_assertions, +}; /// The fixed name of the system pallet. const SYSTEM_PALLET_NAME: &str = "System"; -pub fn expand(mut def: Def) -> proc_macro2::TokenStream { - match def.pallets { - (AllPalletsDeclaration::Implicit(decl), result) => { - result - } - (AllPalletsDeclaration::Explicit(ref decl), ref result) => { - let res = construct_runtime_final_expansion(def.runtime_struct.ident.clone(), decl.clone()); - - let res = res.unwrap_or_else(|e| e.to_compile_error()); - - let res = expander::Expander::new("construct_runtime") - .dry(std::env::var("FRAME_EXPAND").is_err()) - .verbose(true) - .write_to_out_dir(res) - .expect("Does not fail because of IO in OUT_DIR; qed"); - - res.into() - } - } +pub fn expand(def: Def) -> proc_macro2::TokenStream { + let input = def.input; + + let res = match def.pallets { + AllPalletsDeclaration::Implicit(ref decl) => + check_pallet_number(input.clone(), decl.pallet_count) + .and_then(|_| construct_runtime_implicit_to_explicit(input.into(), decl.clone())), + AllPalletsDeclaration::Explicit(ref decl) => check_pallet_number(input, decl.pallets.len()) + .and_then(|_| { + construct_runtime_final_expansion(def.runtime_struct.ident.clone(), decl.clone()) + }), + }; + + let res = res.unwrap_or_else(|e| e.to_compile_error()); + + let res = expander::Expander::new("construct_runtime") + .dry(std::env::var("FRAME_EXPAND").is_err()) + .verbose(true) + .write_to_out_dir(res) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + res.into() +} + +fn construct_runtime_implicit_to_explicit( + input: TokenStream2, + definition: ImplicitAllPalletsDeclaration, +) -> Result { + let frame_support = generate_crate_access_2018("frame-support")?; + let mut expansion = quote::quote!( + #[frame_support::construct_runtime_v2] + #input + ); + for pallet in definition.pallet_decls.iter() { + 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_default_parts_v2 }] + frame_support = [{ #frame_support }] + ~~> #frame_support::match_and_insert! { + target = [{ #expansion }] + pattern = [{ #pallet_name: #pallet_path #pallet_instance }] + } + } + ); + } + + Ok(expansion) } fn construct_runtime_final_expansion( name: Ident, definition: ExplicitAllPalletsDeclaration, ) -> Result { - let ExplicitAllPalletsDeclaration { pallets, pallets_token, .. } = definition; + let ExplicitAllPalletsDeclaration { pallets, name: pallets_name } = definition; let system_pallet = pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| { syn::Error::new( - pallets_token.span.join(), + pallets_name.span(), "`System` pallet declaration is missing. \ Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event},`", ) @@ -106,9 +137,9 @@ fn construct_runtime_final_expansion( let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); let outer_event = - expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Event)?; + expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Event)?; let outer_error = - expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::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); @@ -124,7 +155,7 @@ fn construct_runtime_final_expansion( ); let outer_config = expand::expand_outer_config(&name, &pallets, &scrate); let inherent = - expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); + expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); let freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate); let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate); diff --git a/frame/support/procedural/src/construct_runtime_v2/mod.rs b/frame/support/procedural/src/construct_runtime_v2/mod.rs index 737edc3a8cf9a..c24de0458bf8b 100644 --- a/frame/support/procedural/src/construct_runtime_v2/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/mod.rs @@ -15,21 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use proc_macro::TokenStream; pub use parse::Def; +use proc_macro::TokenStream; -mod parse; mod expand; +mod parse; -use proc_macro2::TokenStream as TokenStream2; -use quote::ToTokens; - -pub fn construct_runtime( - attrs: TokenStream, - item: TokenStream, -) -> TokenStream { - let item = syn::parse_macro_input!(item as syn::ItemMod); - match parse::Def::try_from(item) { +pub fn construct_runtime(_attrs: TokenStream, tokens: TokenStream) -> TokenStream { + let item = syn::parse_macro_input!(tokens as syn::ItemMod); + match parse::Def::try_from(item) { Ok(def) => expand::expand(def).into(), Err(e) => e.to_compile_error().into(), } diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index df643a63439a4..c5ffbebf19f70 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -15,33 +15,64 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod runtime_struct; -pub mod pallets; pub mod helper; +pub mod pallets; +pub mod runtime_struct; -use syn::spanned::Spanned; -use syn::Result; +use proc_macro2::TokenStream as TokenStream2; use quote::ToTokens; +use syn::spanned::Spanned; -use self::pallets::AllPalletsDeclaration; -use crate::construct_runtime::check_pallet_number; -use crate::construct_runtime_v2::parse::pallets::{ImplicitAllPalletsDeclaration, ExplicitAllPalletsDeclaration}; -use frame_support_procedural_tools::{ - generate_crate_access, generate_crate_access_2018, generate_hidden_includes, -}; -use proc_macro2::TokenStream as TokenStream2; -use crate::construct_runtime::parse::Pallet; +mod keyword { + syn::custom_keyword!(frame); + syn::custom_keyword!(runtime); + syn::custom_keyword!(pallets); +} + +enum RuntimeAttr { + Runtime(proc_macro2::Span), + Pallets(proc_macro2::Span), +} + +impl RuntimeAttr { + fn span(&self) -> proc_macro2::Span { + match self { + Self::Runtime(span) => *span, + Self::Pallets(span) => *span, + } + } +} + +impl syn::parse::Parse for RuntimeAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::runtime) { + Ok(RuntimeAttr::Runtime(content.parse::()?.span())) + } else if lookahead.peek(keyword::pallets) { + Ok(RuntimeAttr::Pallets(content.parse::()?.span())) + } else { + Err(lookahead.error()) + } + } +} pub struct Def { - pub item: syn::ItemMod, - pub runtime_struct: runtime_struct::RuntimeStructDef, - pub pallets: (pallets::AllPalletsDeclaration, TokenStream2), + pub input: TokenStream2, + pub item: syn::ItemMod, + pub runtime_struct: runtime_struct::RuntimeStructDef, + pub pallets: pallets::AllPalletsDeclaration, } impl Def { pub fn try_from(mut item: syn::ItemMod) -> syn::Result { - let input_main: TokenStream2 = item.to_token_stream().into(); - let item_span = item.span(); + let input: TokenStream2 = item.to_token_stream().into(); + let item_span = item.span(); let items = &mut item .content .as_mut() @@ -51,115 +82,38 @@ impl Def { })? .1; - let mut runtime_struct = None; + let mut runtime_struct = None; let mut pallets = None; - for (index, item) in items.iter_mut().enumerate() { - let runtime_attr: Option = helper::take_first_item_runtime_attr(item)?; + for item in items.iter_mut() { + let runtime_attr: Option = helper::take_first_item_runtime_attr(item)?; - match runtime_attr { + match runtime_attr { Some(RuntimeAttr::Runtime(span)) if runtime_struct.is_none() => { - let p = runtime_struct::RuntimeStructDef::try_from(span, index, item)?; + let p = runtime_struct::RuntimeStructDef::try_from(span, item)?; runtime_struct = Some(p); }, Some(RuntimeAttr::Pallets(span)) if pallets.is_none() => { - let input: TokenStream2 = item.to_token_stream().into(); - let input_copy: TokenStream2 = input_main.clone(); - let definition = syn::parse2::(input)?; - let res = match definition.clone() { - AllPalletsDeclaration::Implicit(implicit_def) => - check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()).and_then( - |_| construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def), - ), - AllPalletsDeclaration::Explicit(explicit_decl) => - check_pallet_number(input_copy.clone().into(), explicit_decl.pallets.len()) - .and_then(|_| Ok(input_copy)), - }?; - pallets = Some((definition, res)); + let p = pallets::AllPalletsDeclaration::try_from(span, item)?; + pallets = Some(p); }, - Some(attr) => { + Some(attr) => { let msg = "Invalid duplicated attribute"; return Err(syn::Error::new(attr.span(), msg)) }, - None => (), + None => (), } - } + } - let def = Def { + let def = Def { + input, item, runtime_struct: runtime_struct .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::runtime]`"))?, pallets: pallets .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::pallets]`"))?, - }; - - Ok(def) - } -} - -mod keyword { - syn::custom_keyword!(frame); - syn::custom_keyword!(runtime); - syn::custom_keyword!(pallets); -} - -enum RuntimeAttr { - Runtime(proc_macro2::Span), - Pallets(proc_macro2::Span), -} - -impl RuntimeAttr { - fn span(&self) -> proc_macro2::Span { - match self { - Self::Runtime(span) => *span, - Self::Pallets(span) => *span, - } - } -} - -impl syn::parse::Parse for RuntimeAttr { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; - let content; - syn::bracketed!(content in input); - content.parse::()?; - content.parse::()?; + }; - let lookahead = content.lookahead1(); - if lookahead.peek(keyword::runtime) { - Ok(RuntimeAttr::Runtime(content.parse::()?.span())) - }else if lookahead.peek(keyword::pallets) { - Ok(RuntimeAttr::Pallets(content.parse::()?.span())) - } else { - Err(lookahead.error()) - } - } -} - -fn construct_runtime_implicit_to_explicit( - input: TokenStream2, - definition: ImplicitAllPalletsDeclaration, -) -> Result { - let frame_support = generate_crate_access_2018("frame-support")?; - let mut expansion = quote::quote!( - #[frame_support::construct_runtime_v2] - #input - ); - for pallet in definition.pallets.iter().filter(|pallet| pallet.pallet_parts.is_none()) { - 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_default_parts_v2 }] - frame_support = [{ #frame_support }] - ~~> #frame_support::match_and_insert! { - target = [{ #expansion }] - pattern = [{ #pallet_name: #pallet_path #pallet_instance }] - } - } - ); + Ok(def) } - - Ok(expansion) } diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index d2dd2d6693ed1..5b87f747d098a 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -15,22 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support_procedural_tools::syn_ext as ext; -use proc_macro2::{Span, TokenStream}; +use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPath}; use quote::ToTokens; use std::collections::{HashMap, HashSet}; use syn::{ - ext::IdentExt, - parse::{Parse, ParseStream}, - punctuated::Punctuated, - spanned::Spanned, - token, Attribute, Error, Ident, Path, Result, Token, + punctuated::Punctuated, spanned::Spanned, token, Attribute, Error, GenericArgument, Ident, }; -use crate::construct_runtime::parse::PalletPartKeyword; -use crate::construct_runtime::parse::PalletPath; -use crate::construct_runtime::parse::PalletPart; -use crate::construct_runtime::parse::PalletPartNoGeneric; -use crate::construct_runtime::parse::Pallet; mod keyword { syn::custom_keyword!(Pallet); @@ -60,7 +50,8 @@ pub enum AllPalletsDeclaration { #[derive(Debug, Clone)] pub struct ImplicitAllPalletsDeclaration { pub name: Ident, - pub pallets: Vec, + pub pallet_decls: Vec, + pub pallet_count: usize, } /// Declaration of a runtime with all pallet having explicit declaration of parts. @@ -68,46 +59,52 @@ pub struct ImplicitAllPalletsDeclaration { pub struct ExplicitAllPalletsDeclaration { pub name: Ident, pub pallets: Vec, - pub pallets_token: token::Brace, } -impl Parse for AllPalletsDeclaration { - fn parse(input: ParseStream) -> Result { - input.parse::()?; - - // Support either `enum` or `struct`. - if input.peek(Token![struct]) { - input.parse::()?; +impl AllPalletsDeclaration { + // Todo: Check for indices and name conflicts. + pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { + let item = if let syn::Item::Struct(item) = item { + item } else { - input.parse::()?; - } + let msg = "Invalid frame::pallets, expected struct definition"; + return Err(syn::Error::new(item.span(), msg)) + }; - let name = input.parse::()?; - let pallets = - input.parse::>>()?; - let pallets_token = pallets.token; + let name = item.ident.clone(); + let mut pallet_decls = vec![]; + let mut pallets = vec![]; + + for (index, item) in item.fields.iter().enumerate() { + match item.ty.clone() { + syn::Type::Path(ref path) => { + let pallet_decl = PalletDeclaration::try_from(attr_span, index, item, path)?; + pallet_decls.push(pallet_decl); + }, + syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => { + let pallet = Pallet::try_from(attr_span, index, item, &bounds)?; + pallets.push(pallet); + }, + _ => continue, + } + } - match convert_pallets(pallets.content.inner.into_iter().collect())? { - PalletsConversion::Implicit(pallets) => - Ok(AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration { - name, - pallets, - })), - PalletsConversion::Explicit(pallets) => - Ok(AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { - name, - pallets, - pallets_token, - })), + let decl_count = pallet_decls.len(); + if decl_count > 0 { + Ok(AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration { + name, + pallet_decls, + pallet_count: decl_count.saturating_add(pallets.len()), + })) + } else { + Ok(AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { name, pallets })) } - } + } } /// 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. @@ -115,307 +112,114 @@ pub struct PalletDeclaration { /// Optional fixed index, e.g. `MyPallet ... = 3,`. pub index: Option, /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. - pub path: PalletPath, + pub path: syn::Path, /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. pub instance: Option, - /// The declared pallet parts, - /// e.g. `Some([Pallet, Call])` for `System: system::{Pallet, Call}` - /// or `None` for `System: system`. - pub pallet_parts: Option>, - /// The specified parts, either use_parts or exclude_parts. - pub specified_parts: SpecifiedParts, -} - -/// The possible declaration of pallet parts to use. -#[derive(Debug, Clone)] -pub enum SpecifiedParts { - /// Use all the pallet parts except those specified. - Exclude(Vec), - /// Use only the specified pallet parts. - Use(Vec), - /// Use the all the pallet parts. - All, -} - -impl Parse for PalletDeclaration { - fn parse(input: ParseStream) -> Result { - let attrs = input.call(Attribute::parse_outer)?; - - let name = input.parse()?; - let _: Token![:] = input.parse()?; - let path = input.parse()?; - // println!("path: {:?}", path); - - // Parse for instance. - let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { - let _: Token![::] = input.parse()?; - let _: Token![<] = input.parse()?; - let res = Some(input.parse()?); - let _: Token![>] = input.parse()?; - res - } else if !(input.peek(Token![+])) && - !input.peek(keyword::exclude_parts) && - !input.peek(keyword::use_parts) && - !input.peek(Token![=]) && - !input.peek(Token![,]) && - !input.is_empty() - { - return Err(input.error( - "Unexpected tokens, expected one of `::$ident` `+`, `exclude_parts`, `use_parts`, `=`, `,`", - )); - } else { - 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![]) - // }; - - let (is_expanded, extra_parts) = (false, vec![]); - - // Parse for explicit parts - let pallet_parts = if input.peek(Token![+]) { - let _: Token![+] = input.parse()?; - 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![=]) && - !input.peek(Token![,]) && - !input.is_empty() - { - return Err(input.error( - "Unexpected tokens, expected one of `+`, `exclude_parts`, `use_parts`, `=`, `,`", - )) - } else { - is_expanded.then_some(extra_parts) - }; - - // Parse for specified parts - // let specified_parts = if input.peek(keyword::exclude_parts) { - // let _: keyword::exclude_parts = input.parse()?; - // SpecifiedParts::Exclude(parse_pallet_parts_no_generic(input)?) - // } else if input.peek(keyword::use_parts) { - // let _: keyword::use_parts = input.parse()?; - // SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?) - // } else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() { - // return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")) - // } else { - // SpecifiedParts::All - // }; - - let specified_parts = SpecifiedParts::All; - - - // Parse for pallet index - // let index = if input.peek(Token![=]) { - // input.parse::()?; - // let index = input.parse::()?; - // let index = index.base10_parse::()?; - // Some(index) - // } else if !input.peek(Token![,]) && !input.is_empty() { - // return Err(input.error("Unexpected tokens, expected one of `=`, `,`")) - // } else { - // None - // }; - let index = None; - - Ok(Self { is_expanded, attrs, name, path, instance, pallet_parts, specified_parts, index }) - } } -/// Parse [`PalletPart`]'s from a braces enclosed list that is split by commas, e.g. -/// -/// `{ Call, Event }` -fn parse_pallet_parts(input: ParseStream) -> Result> { - // let pallet_parts: ext::Punctuated = input.parse()?; - let pallet_parts = Punctuated::::parse_separated_nonempty(&input)?; - - let mut resolved = HashSet::new(); - for part in pallet_parts.iter() { - if !resolved.insert(part.name()) { - let msg = format!( - "`{}` was already declared before. Please remove the duplicate declaration", - part.name(), - ); - return Err(Error::new(part.keyword.span(), msg)) +impl PalletDeclaration { + pub fn try_from( + attr_span: proc_macro2::Span, + index: usize, + item: &syn::Field, + path: &syn::TypePath, + ) -> syn::Result { + let name = item + .ident + .clone() + .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; + + let mut path = path.path.clone(); + + let mut instance = None; + // Todo: revisit this + if let Some(segment) = path.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) { + if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, + .. + }) = segment.arguments.clone() + { + if let Some(GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = Some(syn::Ident::new( + &arg_path.to_token_stream().to_string(), + arg_path.span(), + )); + segment.arguments = syn::PathArguments::None; + } + } } - } - Ok(pallet_parts.into_iter().collect()) -} + let index = Some(index as u8); -/// Parse [`PalletPartNoGeneric`]'s from a braces enclosed list that is split by commas, e.g. -/// -/// `{ Call, Event }` -fn parse_pallet_parts_no_generic(input: ParseStream) -> Result> { - let pallet_parts: ext::Braces> = - input.parse()?; - - let mut resolved = HashSet::new(); - for part in pallet_parts.content.inner.iter() { - if !resolved.insert(part.keyword.name()) { - let msg = format!( - "`{}` was already declared before. Please remove the duplicate declaration", - part.keyword.name(), - ); - return Err(Error::new(part.keyword.span(), msg)) - } + Ok(Self { name, path, instance, index, attrs: item.attrs.clone() }) } - - Ok(pallet_parts.content.inner.into_iter().collect()) } -/// Result of a conversion of a declaration of pallets. -/// -/// # State Transitions -/// -/// ```ignore -/// +----------+ +----------+ -/// | Implicit | -> | Explicit | -/// +----------+ +----------+ -/// ``` -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), -} - -/// Convert from the parsed pallet declaration to their final information. -/// -/// Check if all pallet have explicit declaration of their parts, if so then assign index to each -/// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number -/// incrementedly from last explicit or 0. -fn convert_pallets(pallets: Vec) -> syn::Result { - if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { - return Ok(PalletsConversion::Implicit(pallets)) - } - - let mut indices = HashMap::new(); - let mut last_index: Option = None; - let mut names = HashMap::new(); - let mut is_expanded = true; - - let pallets = pallets - .into_iter() - .map(|pallet| { - let final_index = match pallet.index { - Some(i) => i, - None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| { - let msg = "Pallet index doesn't fit into u8, index is 256"; - syn::Error::new(pallet.name.span(), msg) - })?, +impl Pallet { + pub fn try_from( + attr_span: proc_macro2::Span, + index: usize, + item: &syn::Field, + bounds: &Punctuated, + ) -> syn::Result { + let name = item + .ident + .clone() + .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; + + let mut pallet_path = None; + let mut pallet_parts = vec![]; + + for (index, bound) in bounds.into_iter().enumerate() { + if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound { + if index == 0 { + pallet_path = Some(PalletPath { inner: path.clone() }); + } else { + let pallet_part = syn::parse2::(bound.into_token_stream())?; + pallet_parts.push(pallet_part); + } + } else { + return Err(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + )) }; + } - last_index = Some(final_index); - - if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) { - let msg = format!( - "Pallet indices are conflicting: Both pallets {} and {} are at index {}", - used_pallet, pallet.name, final_index, - ); - let mut err = syn::Error::new(used_pallet.span(), &msg); - err.combine(syn::Error::new(pallet.name.span(), msg)); - return Err(err) - } - - if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { - let msg = "Two pallets with the same name!"; - - let mut err = syn::Error::new(used_pallet, &msg); - err.combine(syn::Error::new(pallet.name.span(), &msg)); - return Err(err) - } - - let mut pallet_parts = pallet.pallet_parts.expect("Checked above"); - - let available_parts = - pallet_parts.iter().map(|part| part.keyword.name()).collect::>(); - - // Check parts are correctly specified - match &pallet.specified_parts { - SpecifiedParts::Exclude(parts) | SpecifiedParts::Use(parts) => - for part in parts { - if !available_parts.contains(part.keyword.name()) { - let msg = format!( - "Invalid pallet part specified, the pallet `{}` doesn't have the \ - `{}` part. Available parts are: {}.", - pallet.name, - part.keyword.name(), - pallet_parts.iter().fold(String::new(), |fold, part| { - if fold.is_empty() { - format!("`{}`", part.keyword.name()) - } else { - format!("{}, `{}`", fold, part.keyword.name()) - } - }) - ); - return Err(syn::Error::new(part.keyword.span(), msg)) - } - }, - SpecifiedParts::All => (), - } + let mut path = pallet_path.ok_or(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + ))?; - // Set only specified parts. - match pallet.specified_parts { - SpecifiedParts::Exclude(excluded_parts) => pallet_parts.retain(|part| { - !excluded_parts - .iter() - .any(|excluded_part| excluded_part.keyword.name() == part.keyword.name()) - }), - SpecifiedParts::Use(used_parts) => pallet_parts.retain(|part| { - used_parts.iter().any(|use_part| use_part.keyword.name() == part.keyword.name()) - }), - SpecifiedParts::All => (), + let mut instance = None; + // Todo: revisit this + if let Some(segment) = path.inner.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) + { + if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, + .. + }) = segment.arguments.clone() + { + if let Some(GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = Some(syn::Ident::new( + &arg_path.to_token_stream().to_string(), + arg_path.span(), + )); + segment.arguments = syn::PathArguments::None; + } } + } - let cfg_pattern = pallet - .attrs - .iter() - .map(|attr| { - if attr.path().segments.first().map_or(false, |s| s.ident != "cfg") { - let msg = "Unsupported attribute, only #[cfg] is supported on pallet \ - declarations in `construct_runtime`"; - return Err(syn::Error::new(attr.span(), msg)) - } - - attr.parse_args_with(|input: syn::parse::ParseStream| { - // Required, otherwise the parse stream doesn't advance and will result in - // an error. - let input = input.parse::()?; - cfg_expr::Expression::parse(&input.to_string()) - .map_err(|e| syn::Error::new(attr.span(), e.to_string())) - }) - }) - .collect::>>()?; - - is_expanded &= pallet.is_expanded; + let cfg_pattern = vec![]; - Ok(Pallet { - is_expanded: pallet.is_expanded, - name: pallet.name, - index: final_index, - path: pallet.path, - instance: pallet.instance, - cfg_pattern, - pallet_parts, - }) + Ok(Pallet { + is_expanded: true, + name, + index: index as u8, + path, + instance, + cfg_pattern, + pallet_parts, }) - .collect::>>()?; - - Ok(PalletsConversion::Explicit(pallets)) + } } diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs index f47721bdd6f85..edc2d79eb5939 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_struct.rs @@ -22,21 +22,14 @@ pub struct RuntimeStructDef { } impl RuntimeStructDef { - pub fn try_from( - attr_span: proc_macro2::Span, - index: usize, - item: &mut syn::Item, - ) -> syn::Result { - let item = if let syn::Item::Struct(item) = item { + pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { + let item = if let syn::Item::Struct(item) = item { item } else { let msg = "Invalid frame::runtime, expected struct definition"; return Err(syn::Error::new(item.span(), msg)) }; - Ok(Self { - ident: item.ident.clone(), - attr_span - }) - } + Ok(Self { ident: item.ident.clone(), attr_span }) + } } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 270260cbbb12c..bc4a5ba05f623 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -499,7 +499,8 @@ pub fn debug(data: &impl sp_std::fmt::Debug) { #[doc(inline)] pub use frame_support_procedural::{ - construct_runtime, construct_runtime_v2, match_and_insert, transactional, PalletError, RuntimeDebugNoBound, + construct_runtime, construct_runtime_v2, match_and_insert, transactional, PalletError, + RuntimeDebugNoBound, }; #[doc(hidden)] From 2851003beef3c02bdc32b2508a64b42e48a370b8 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:26:37 +0530 Subject: [PATCH 12/19] Fixes build --- bin/node/runtime/src/lib.rs | 17 ++++++++--------- .../src/construct_runtime_v2/expand/mod.rs | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index b3a70821a194e..5ca8844d18a80 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -28,7 +28,6 @@ use frame_election_provider_support::{ onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight, }; use frame_support::{ - construct_runtime, dispatch::DispatchClass, instances::{Instance1, Instance2}, ord_parameter_types, @@ -1899,10 +1898,10 @@ mod runtime { Staking: pallet_staking, Session: pallet_session, Democracy: pallet_democracy, - Council: pallet_collective::, - TechnicalCommittee: pallet_collective::, + Council: pallet_collective, + TechnicalCommittee: pallet_collective, Elections: pallet_elections_phragmen, - TechnicalMembership: pallet_membership::, + TechnicalMembership: pallet_membership, Grandpa: pallet_grandpa, Treasury: pallet_treasury, AssetRate: pallet_asset_rate, @@ -1924,8 +1923,8 @@ mod runtime { Multisig: pallet_multisig, Bounties: pallet_bounties, Tips: pallet_tips, - Assets: pallet_assets::, - PoolAssets: pallet_assets::, + Assets: pallet_assets, + PoolAssets: pallet_assets, Mmr: pallet_mmr, Lottery: pallet_lottery, Nis: pallet_nis, @@ -1935,7 +1934,7 @@ mod runtime { Salary: pallet_salary, CoreFellowship: pallet_core_fellowship, TransactionStorage: pallet_transaction_storage, - VoterList: pallet_bags_list::, + VoterList: pallet_bags_list, StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, @@ -1943,10 +1942,10 @@ mod runtime { RootTesting: pallet_root_testing, ConvictionVoting: pallet_conviction_voting, Whitelist: pallet_whitelist, - AllianceMotion: pallet_collective::, + AllianceMotion: pallet_collective, Alliance: pallet_alliance, NominationPools: pallet_nomination_pools, - RankedPolls: pallet_referenda::, + RankedPolls: pallet_referenda, RankedCollective: pallet_ranked_collective, AssetConversion: pallet_asset_conversion, FastUnstake: pallet_fast_unstake, diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index af23f86a05f4f..05f55f765a1d4 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -75,7 +75,7 @@ fn construct_runtime_implicit_to_explicit( for pallet in definition.pallet_decls.iter() { let pallet_path = &pallet.path; let pallet_name = &pallet.name; - let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(::<#instance>)); + let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(<#instance>)); expansion = quote::quote!( #frame_support::tt_call! { macro = [{ #pallet_path::tt_default_parts_v2 }] From e08bbcd3cb9d6f185c098373dee2775aba6b5bcc Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:35:56 +0530 Subject: [PATCH 13/19] Removes unused keywords --- .../src/construct_runtime_v2/parse/pallets.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index 5b87f747d098a..0fd12d833dbf0 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -22,24 +22,6 @@ use syn::{ punctuated::Punctuated, spanned::Spanned, token, Attribute, Error, GenericArgument, Ident, }; -mod keyword { - syn::custom_keyword!(Pallet); - 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); - syn::custom_keyword!(ValidateUnsigned); - syn::custom_keyword!(FreezeReason); - syn::custom_keyword!(HoldReason); - syn::custom_keyword!(LockId); - syn::custom_keyword!(SlashReason); - syn::custom_keyword!(exclude_parts); - syn::custom_keyword!(use_parts); -} - #[derive(Debug, Clone)] pub enum AllPalletsDeclaration { Implicit(ImplicitAllPalletsDeclaration), From 7d8efaf4c8e4cb456c74a91aaa66dab463e74f6d Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:46:16 +0530 Subject: [PATCH 14/19] Restructures a bit --- .../src/construct_runtime_v2/parse/mod.rs | 1 + .../src/construct_runtime_v2/parse/pallet.rs | 92 +++++++++++++++++++ .../src/construct_runtime_v2/parse/pallets.rs | 73 +-------------- 3 files changed, 95 insertions(+), 71 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index c5ffbebf19f70..f27aa6d89e42c 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -16,6 +16,7 @@ // limitations under the License. pub mod helper; +pub mod pallet; pub mod pallets; pub mod runtime_struct; diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs new file mode 100644 index 0000000000000..a56e21879b142 --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs @@ -0,0 +1,92 @@ +// 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::parse::Pallet; +use crate::construct_runtime::parse::PalletPart; +use crate::construct_runtime::parse::PalletPath; +use syn::{punctuated::Punctuated, Error, token}; +use quote::ToTokens; +use syn::spanned::Spanned; + +impl Pallet { + pub fn try_from( + attr_span: proc_macro2::Span, + index: usize, + item: &syn::Field, + bounds: &Punctuated, + ) -> syn::Result { + let name = item + .ident + .clone() + .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; + + let mut pallet_path = None; + let mut pallet_parts = vec![]; + + for (index, bound) in bounds.into_iter().enumerate() { + if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound { + if index == 0 { + pallet_path = Some(PalletPath { inner: path.clone() }); + } else { + let pallet_part = syn::parse2::(bound.into_token_stream())?; + pallet_parts.push(pallet_part); + } + } else { + return Err(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + )) + }; + } + + let mut path = pallet_path.ok_or(Error::new( + attr_span, + "Invalid pallet declaration, expected a path or a trait object", + ))?; + + let mut instance = None; + // Todo: revisit this + if let Some(segment) = path.inner.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) + { + if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, + .. + }) = segment.arguments.clone() + { + if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = Some(syn::Ident::new( + &arg_path.to_token_stream().to_string(), + arg_path.span(), + )); + segment.arguments = syn::PathArguments::None; + } + } + } + + let cfg_pattern = vec![]; + + Ok(Pallet { + is_expanded: true, + name, + index: index as u8, + path, + instance, + cfg_pattern, + pallet_parts, + }) + } +} \ No newline at end of file diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index 0fd12d833dbf0..cce92bd2fad83 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -15,11 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPath}; +use crate::construct_runtime::parse::Pallet; use quote::ToTokens; use std::collections::{HashMap, HashSet}; use syn::{ - punctuated::Punctuated, spanned::Spanned, token, Attribute, Error, GenericArgument, Ident, + spanned::Spanned, Attribute, Error, GenericArgument, Ident, }; #[derive(Debug, Clone)] @@ -136,72 +136,3 @@ impl PalletDeclaration { Ok(Self { name, path, instance, index, attrs: item.attrs.clone() }) } } - -impl Pallet { - pub fn try_from( - attr_span: proc_macro2::Span, - index: usize, - item: &syn::Field, - bounds: &Punctuated, - ) -> syn::Result { - let name = item - .ident - .clone() - .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; - - let mut pallet_path = None; - let mut pallet_parts = vec![]; - - for (index, bound) in bounds.into_iter().enumerate() { - if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound { - if index == 0 { - pallet_path = Some(PalletPath { inner: path.clone() }); - } else { - let pallet_part = syn::parse2::(bound.into_token_stream())?; - pallet_parts.push(pallet_part); - } - } else { - return Err(Error::new( - attr_span, - "Invalid pallet declaration, expected a path or a trait object", - )) - }; - } - - let mut path = pallet_path.ok_or(Error::new( - attr_span, - "Invalid pallet declaration, expected a path or a trait object", - ))?; - - let mut instance = None; - // Todo: revisit this - if let Some(segment) = path.inner.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) - { - if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - args, - .. - }) = segment.arguments.clone() - { - if let Some(GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { - instance = Some(syn::Ident::new( - &arg_path.to_token_stream().to_string(), - arg_path.span(), - )); - segment.arguments = syn::PathArguments::None; - } - } - } - - let cfg_pattern = vec![]; - - Ok(Pallet { - is_expanded: true, - name, - index: index as u8, - path, - instance, - cfg_pattern, - pallet_parts, - }) - } -} From 8e93f74b055af8381473156a1781b759b263b0c1 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:50:26 +0530 Subject: [PATCH 15/19] Restructures a bit more --- .../src/construct_runtime_v2/parse/mod.rs | 1 + .../construct_runtime_v2/parse/pallet_decl.rs | 73 +++++++++++++++++++ .../src/construct_runtime_v2/parse/pallets.rs | 57 +-------------- 3 files changed, 76 insertions(+), 55 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index f27aa6d89e42c..992c63d89a258 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -16,6 +16,7 @@ // limitations under the License. pub mod helper; +pub mod pallet_decl; pub mod pallet; pub mod pallets; pub mod runtime_struct; diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs new file mode 100644 index 0000000000000..be688b1eaa49a --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs @@ -0,0 +1,73 @@ +// 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 syn::{Attribute, Ident, Error}; +use quote::ToTokens; +use syn::spanned::Spanned; + +/// The declaration of a pallet. +#[derive(Debug, Clone)] +pub struct PalletDeclaration { + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Optional attributes tagged right above a pallet declaration. + pub attrs: Vec, + /// Optional fixed index, e.g. `MyPallet ... = 3,`. + pub index: Option, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: syn::Path, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, +} + +impl PalletDeclaration { + pub fn try_from( + attr_span: proc_macro2::Span, + index: usize, + item: &syn::Field, + path: &syn::TypePath, + ) -> syn::Result { + let name = item + .ident + .clone() + .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; + + let mut path = path.path.clone(); + + let mut instance = None; + // Todo: revisit this + if let Some(segment) = path.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) { + if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, + .. + }) = segment.arguments.clone() + { + if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { + instance = Some(syn::Ident::new( + &arg_path.to_token_stream().to_string(), + arg_path.span(), + )); + segment.arguments = syn::PathArguments::None; + } + } + } + + let index = Some(index as u8); + + Ok(Self { name, path, instance, index, attrs: item.attrs.clone() }) + } +} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index cce92bd2fad83..3b618454cbfab 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -16,10 +16,10 @@ // limitations under the License. use crate::construct_runtime::parse::Pallet; -use quote::ToTokens; +use crate::construct_runtime_v2::parse::pallet_decl::PalletDeclaration; use std::collections::{HashMap, HashSet}; use syn::{ - spanned::Spanned, Attribute, Error, GenericArgument, Ident, + spanned::Spanned, Ident, }; #[derive(Debug, Clone)] @@ -83,56 +83,3 @@ impl AllPalletsDeclaration { } } } - -/// The declaration of a pallet. -#[derive(Debug, Clone)] -pub struct PalletDeclaration { - /// The name of the pallet, e.g.`System` in `System: frame_system`. - pub name: Ident, - /// Optional attributes tagged right above a pallet declaration. - pub attrs: Vec, - /// Optional fixed index, e.g. `MyPallet ... = 3,`. - pub index: Option, - /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. - pub path: syn::Path, - /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. - pub instance: Option, -} - -impl PalletDeclaration { - pub fn try_from( - attr_span: proc_macro2::Span, - index: usize, - item: &syn::Field, - path: &syn::TypePath, - ) -> syn::Result { - let name = item - .ident - .clone() - .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; - - let mut path = path.path.clone(); - - let mut instance = None; - // Todo: revisit this - if let Some(segment) = path.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) { - if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - args, - .. - }) = segment.arguments.clone() - { - if let Some(GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() { - instance = Some(syn::Ident::new( - &arg_path.to_token_stream().to_string(), - arg_path.span(), - )); - segment.arguments = syn::PathArguments::None; - } - } - } - - let index = Some(index as u8); - - Ok(Self { name, path, instance, index, attrs: item.attrs.clone() }) - } -} From 528e90f9e6314fcf78d5f4dab91d6a7248fa1c60 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:51:08 +0530 Subject: [PATCH 16/19] Fmt --- .../procedural/src/construct_runtime_v2/parse/mod.rs | 2 +- .../procedural/src/construct_runtime_v2/parse/pallet.rs | 9 +++------ .../src/construct_runtime_v2/parse/pallet_decl.rs | 3 +-- .../procedural/src/construct_runtime_v2/parse/pallets.rs | 9 ++++----- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index 992c63d89a258..4269fa7e84248 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -16,8 +16,8 @@ // limitations under the License. pub mod helper; -pub mod pallet_decl; pub mod pallet; +pub mod pallet_decl; pub mod pallets; pub mod runtime_struct; diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs index a56e21879b142..6822d74b17d31 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs @@ -15,12 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::construct_runtime::parse::Pallet; -use crate::construct_runtime::parse::PalletPart; -use crate::construct_runtime::parse::PalletPath; -use syn::{punctuated::Punctuated, Error, token}; +use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPath}; use quote::ToTokens; -use syn::spanned::Spanned; +use syn::{punctuated::Punctuated, spanned::Spanned, token, Error}; impl Pallet { pub fn try_from( @@ -89,4 +86,4 @@ impl Pallet { pallet_parts, }) } -} \ No newline at end of file +} diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs index be688b1eaa49a..57bff26b2082a 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs @@ -15,9 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use syn::{Attribute, Ident, Error}; use quote::ToTokens; -use syn::spanned::Spanned; +use syn::{spanned::Spanned, Attribute, Error, Ident}; /// The declaration of a pallet. #[derive(Debug, Clone)] diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index 3b618454cbfab..dce4ca695ac0e 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -15,12 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::construct_runtime::parse::Pallet; -use crate::construct_runtime_v2::parse::pallet_decl::PalletDeclaration; -use std::collections::{HashMap, HashSet}; -use syn::{ - spanned::Spanned, Ident, +use crate::{ + construct_runtime::parse::Pallet, construct_runtime_v2::parse::pallet_decl::PalletDeclaration, }; +use std::collections::{HashMap, HashSet}; +use syn::{spanned::Spanned, Ident}; #[derive(Debug, Clone)] pub enum AllPalletsDeclaration { From 98a06121f54d3e3c7b4193818691e2007a549b38 Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 17:52:41 +0530 Subject: [PATCH 17/19] Adds ability to specify pallet_index --- bin/node-template/runtime/src/lib.rs | 1 + .../src/construct_runtime_v2/parse/pallet.rs | 74 ++++++++++++++++++- .../construct_runtime_v2/parse/pallet_decl.rs | 2 +- .../src/construct_runtime_v2/parse/pallets.rs | 34 ++++++++- 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 59c993f26af2c..6adeb79feac27 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -294,6 +294,7 @@ mod runtime { TransactionPayment: pallet_transaction_payment, Sudo: pallet_sudo, // Include the custom logic from the pallet-template in the runtime. + #[frame::pallet_index(8)] TemplateModule: pallet_template, } } diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs index 6822d74b17d31..85ec494a2afec 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs @@ -19,11 +19,71 @@ use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPath}; use quote::ToTokens; use syn::{punctuated::Punctuated, spanned::Spanned, token, Error}; +mod keyword { + syn::custom_keyword!(frame); + syn::custom_keyword!(pallet_index); +} + +enum PalletAttr { + PalletIndex(proc_macro2::Span, u8), +} + +impl PalletAttr { + fn span(&self) -> proc_macro2::Span { + match self { + Self::PalletIndex(span, _) => *span, + } + } +} + +impl syn::parse::Parse for PalletAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + content.parse::()?; + + let lookahead = content.lookahead1(); + if lookahead.peek(keyword::pallet_index) { + let _ = content.parse::(); + let pallet_index_content; + syn::parenthesized!(pallet_index_content in content); + let pallet_index = pallet_index_content.parse::()?; + if !pallet_index.suffix().is_empty() { + let msg = "Number literal must not have a suffix"; + return Err(syn::Error::new(pallet_index.span(), msg)) + } + Ok(PalletAttr::PalletIndex(pallet_index.span(), pallet_index.base10_parse()?)) + } else { + Err(lookahead.error()) + } + } +} + +fn take_first_item_pallet_attr( + item: &mut syn::Field, +) -> syn::Result> +where + Attr: syn::parse::Parse, +{ + let attrs = &mut item.attrs; + + if let Some(index) = attrs.iter().position(|attr| { + attr.path().segments.first().map_or(false, |segment| segment.ident == "frame") + }) { + let runtime_attr = attrs.remove(index); + Ok(Some(syn::parse2(runtime_attr.into_token_stream())?)) + } else { + Ok(None) + } +} + impl Pallet { pub fn try_from( attr_span: proc_macro2::Span, - index: usize, - item: &syn::Field, + index: u8, + item: &mut syn::Field, bounds: &Punctuated, ) -> syn::Result { let name = item @@ -31,6 +91,14 @@ impl Pallet { .clone() .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; + let mut pallet_index = index; + + while let Some(pallet_attr) = take_first_item_pallet_attr::(item)? { + match pallet_attr { + PalletAttr::PalletIndex(_, index) => pallet_index = index, + } + } + let mut pallet_path = None; let mut pallet_parts = vec![]; @@ -79,7 +147,7 @@ impl Pallet { Ok(Pallet { is_expanded: true, name, - index: index as u8, + index: pallet_index, path, instance, cfg_pattern, diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs index 57bff26b2082a..4245a7b40e8b0 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet_decl.rs @@ -37,7 +37,7 @@ impl PalletDeclaration { pub fn try_from( attr_span: proc_macro2::Span, index: usize, - item: &syn::Field, + item: &mut syn::Field, path: &syn::TypePath, ) -> syn::Result { let name = item diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index dce4ca695ac0e..8634933c37f30 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -19,7 +19,7 @@ use crate::{ construct_runtime::parse::Pallet, construct_runtime_v2::parse::pallet_decl::PalletDeclaration, }; use std::collections::{HashMap, HashSet}; -use syn::{spanned::Spanned, Ident}; +use syn::{spanned::Spanned, Ident, Error}; #[derive(Debug, Clone)] pub enum AllPalletsDeclaration { @@ -43,7 +43,6 @@ pub struct ExplicitAllPalletsDeclaration { } impl AllPalletsDeclaration { - // Todo: Check for indices and name conflicts. pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result { let item = if let syn::Item::Struct(item) = item { item @@ -53,17 +52,44 @@ impl AllPalletsDeclaration { }; let name = item.ident.clone(); + + let mut indices = HashMap::new(); + let mut names = HashMap::new(); + + let mut last_index: Option = None; + let mut pallet_decls = vec![]; let mut pallets = vec![]; - for (index, item) in item.fields.iter().enumerate() { + for (index, item) in item.fields.iter_mut().enumerate() { match item.ty.clone() { syn::Type::Path(ref path) => { let pallet_decl = PalletDeclaration::try_from(attr_span, index, item, path)?; pallet_decls.push(pallet_decl); }, syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => { - let pallet = Pallet::try_from(attr_span, index, item, &bounds)?; + let index_u8: u8 = index.try_into().map_err(|_| Error::new(attr_span, "Invalid pallet index, cannot fit in u8"))?; + let pallet = Pallet::try_from(attr_span, last_index.unwrap_or(index_u8), item, &bounds)?; + + if let Some(used_pallet) = indices.insert(pallet.index, pallet.name.clone()) { + let msg = format!( + "Pallet indices are conflicting: Both pallets {} and {} are at index {}", + used_pallet, pallet.name, pallet.index, + ); + let mut err = syn::Error::new(used_pallet.span(), &msg); + err.combine(syn::Error::new(pallet.name.span(), msg)); + return Err(err) + } + + if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { + let msg = "Two pallets with the same name!"; + + let mut err = syn::Error::new(used_pallet, &msg); + err.combine(syn::Error::new(pallet.name.span(), &msg)); + return Err(err) + } + + last_index = Some(pallet.index); pallets.push(pallet); }, _ => continue, From 0b4ab5b37ef482f1be9323e81b437f6444a0560a Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 18:12:18 +0530 Subject: [PATCH 18/19] Adds ability to disable call --- bin/node-template/runtime/src/lib.rs | 1 + .../procedural/src/construct_runtime/parse.rs | 2 +- .../src/construct_runtime_v2/parse/pallet.rs | 27 ++++++++++++++++--- .../src/construct_runtime_v2/parse/pallets.rs | 19 ++++++++----- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 6adeb79feac27..3a6e2a44b31cd 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -295,6 +295,7 @@ mod runtime { Sudo: pallet_sudo, // Include the custom logic from the pallet-template in the runtime. #[frame::pallet_index(8)] + #[frame::disable_call] TemplateModule: pallet_template, } } diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index b407b897e4106..4973092787511 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -391,7 +391,7 @@ fn parse_pallet_parts(input: ParseStream) -> Result> { Ok(pallet_parts.content.inner.into_iter().collect()) } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum PalletPartKeyword { Pallet(keyword::Pallet), Call(keyword::Call), diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs index 85ec494a2afec..27522578c7fb8 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallet.rs @@ -15,23 +15,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPath}; +use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPartKeyword, PalletPath}; use quote::ToTokens; use syn::{punctuated::Punctuated, spanned::Spanned, token, Error}; mod keyword { syn::custom_keyword!(frame); syn::custom_keyword!(pallet_index); + syn::custom_keyword!(disable_call); } enum PalletAttr { PalletIndex(proc_macro2::Span, u8), + DisableCall(proc_macro2::Span), } impl PalletAttr { fn span(&self) -> proc_macro2::Span { match self { Self::PalletIndex(span, _) => *span, + Self::DisableCall(span) => *span, } } } @@ -55,15 +58,15 @@ impl syn::parse::Parse for PalletAttr { return Err(syn::Error::new(pallet_index.span(), msg)) } Ok(PalletAttr::PalletIndex(pallet_index.span(), pallet_index.base10_parse()?)) + } else if lookahead.peek(keyword::disable_call) { + Ok(PalletAttr::DisableCall(content.parse::()?.span())) } else { Err(lookahead.error()) } } } -fn take_first_item_pallet_attr( - item: &mut syn::Field, -) -> syn::Result> +fn take_first_item_pallet_attr(item: &mut syn::Field) -> syn::Result> where Attr: syn::parse::Parse, { @@ -92,10 +95,12 @@ impl Pallet { .ok_or(Error::new(attr_span, "Invalid pallet declaration, expected a named field"))?; let mut pallet_index = index; + let mut disable_call = false; while let Some(pallet_attr) = take_first_item_pallet_attr::(item)? { match pallet_attr { PalletAttr::PalletIndex(_, index) => pallet_index = index, + PalletAttr::DisableCall(_) => disable_call = true, } } @@ -142,6 +147,20 @@ impl Pallet { } } + if disable_call { + pallet_parts = + pallet_parts + .into_iter() + .filter(|part| { + if let PalletPartKeyword::Call(_) = part.keyword { + false + } else { + true + } + }) + .collect(); + } + let cfg_pattern = vec![]; Ok(Pallet { diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs index 8634933c37f30..19e27a6567d71 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/pallets.rs @@ -19,7 +19,7 @@ use crate::{ construct_runtime::parse::Pallet, construct_runtime_v2::parse::pallet_decl::PalletDeclaration, }; use std::collections::{HashMap, HashSet}; -use syn::{spanned::Spanned, Ident, Error}; +use syn::{spanned::Spanned, Ident}; #[derive(Debug, Clone)] pub enum AllPalletsDeclaration { @@ -52,7 +52,7 @@ impl AllPalletsDeclaration { }; let name = item.ident.clone(); - + let mut indices = HashMap::new(); let mut names = HashMap::new(); @@ -68,8 +68,14 @@ impl AllPalletsDeclaration { pallet_decls.push(pallet_decl); }, syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => { - let index_u8: u8 = index.try_into().map_err(|_| Error::new(attr_span, "Invalid pallet index, cannot fit in u8"))?; - let pallet = Pallet::try_from(attr_span, last_index.unwrap_or(index_u8), item, &bounds)?; + let current_index = match last_index { + Some(index) => index.checked_add(1).ok_or_else(|| { + let msg = "Pallet index doesn't fit into u8, index is 256"; + syn::Error::new(name.span(), msg) + }), + None => Ok(0), + }?; + let pallet = Pallet::try_from(attr_span, current_index, item, &bounds)?; if let Some(used_pallet) = indices.insert(pallet.index, pallet.name.clone()) { let msg = format!( @@ -81,9 +87,10 @@ impl AllPalletsDeclaration { return Err(err) } - if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { + if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) + { let msg = "Two pallets with the same name!"; - + let mut err = syn::Error::new(used_pallet, &msg); err.combine(syn::Error::new(pallet.name.span(), &msg)); return Err(err) From bd7ef5a5eef4b2d252c4c856ba65815c932fe22c Mon Sep 17 00:00:00 2001 From: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Date: Fri, 18 Aug 2023 18:58:59 +0530 Subject: [PATCH 19/19] Adds runtime types --- bin/node-template/runtime/src/lib.rs | 10 +++ .../procedural/src/construct_runtime/parse.rs | 2 +- .../src/construct_runtime_v2/expand/mod.rs | 67 +++++++++++++++--- .../src/construct_runtime_v2/parse/mod.rs | 57 ++++++++++----- .../parse/runtime_types.rs | 70 +++++++++++++++++++ 5 files changed, 177 insertions(+), 29 deletions(-) create mode 100644 frame/support/procedural/src/construct_runtime_v2/parse/runtime_types.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 3a6e2a44b31cd..b2863a2deb7cb 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -285,6 +285,16 @@ mod runtime { pub struct Runtime; #[frame::pallets] + #[frame::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId + )] pub struct Pallets { System: frame_system, Timestamp: pallet_timestamp, diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 4973092787511..b407b897e4106 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -391,7 +391,7 @@ fn parse_pallet_parts(input: ParseStream) -> Result> { Ok(pallet_parts.content.inner.into_iter().collect()) } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum PalletPartKeyword { Pallet(keyword::Pallet), Call(keyword::Call), diff --git a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs index 05f55f765a1d4..e0953b5f2b4c3 100644 --- a/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/expand/mod.rs @@ -36,6 +36,8 @@ use crate::construct_runtime::{ decl_all_pallets, decl_integrity_test, decl_pallet_runtime_setup, decl_static_assertions, }; +use super::parse::runtime_types::RuntimeType; + /// The fixed name of the system pallet. const SYSTEM_PALLET_NAME: &str = "System"; @@ -48,7 +50,11 @@ pub fn expand(def: Def) -> proc_macro2::TokenStream { .and_then(|_| construct_runtime_implicit_to_explicit(input.into(), decl.clone())), AllPalletsDeclaration::Explicit(ref decl) => check_pallet_number(input, decl.pallets.len()) .and_then(|_| { - construct_runtime_final_expansion(def.runtime_struct.ident.clone(), decl.clone()) + construct_runtime_final_expansion( + def.runtime_struct.ident.clone(), + decl.clone(), + def.runtime_types.clone(), + ) }), }; @@ -94,6 +100,7 @@ fn construct_runtime_implicit_to_explicit( fn construct_runtime_final_expansion( name: Ident, definition: ExplicitAllPalletsDeclaration, + runtime_types: Vec, ) -> Result { let ExplicitAllPalletsDeclaration { pallets, name: pallets_name } = definition; @@ -136,16 +143,58 @@ fn construct_runtime_final_expansion( let block = quote!(<#name as #frame_system::Config>::Block); let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic); - 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 mut dispatch = quote!(); + let mut outer_event = quote!(); + let mut outer_error = quote!(); + let mut outer_origin = quote!(); + let mut freeze_reason = quote!(); + let mut hold_reason = quote!(); + let mut slash_reason = quote!(); + let mut lock_id = quote!(); + + for runtime_type in runtime_types.iter() { + match runtime_type { + RuntimeType::RuntimeCall(_) => { + dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); + }, + RuntimeType::RuntimeEvent(_) => { + outer_event = expand::expand_outer_enum( + &name, + &pallets, + &scrate, + expand::OuterEnumType::Event, + )?; + }, + RuntimeType::RuntimeError(_) => { + outer_error = expand::expand_outer_enum( + &name, + &pallets, + &scrate, + expand::OuterEnumType::Error, + )?; + }, + RuntimeType::RuntimeOrigin(_) => { + outer_origin = + expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?; + }, + RuntimeType::RuntimeFreezeReason(_) => { + freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate); + }, + RuntimeType::RuntimeHoldReason(_) => { + hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate); + }, + RuntimeType::RuntimeSlashReason(_) => { + slash_reason = expand::expand_outer_slash_reason(&pallets, &scrate); + }, + RuntimeType::RuntimeLockId(_) => { + lock_id = expand::expand_outer_lock_id(&pallets, &scrate); + }, + } + } - 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, @@ -157,10 +206,6 @@ fn construct_runtime_final_expansion( let inherent = expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate); let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate); - let freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate); - let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate); - let lock_id = expand::expand_outer_lock_id(&pallets, &scrate); - let slash_reason = expand::expand_outer_slash_reason(&pallets, &scrate); let integrity_test = decl_integrity_test(&scrate); let static_assertions = decl_static_assertions(&name, &pallets, &scrate); diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs index 4269fa7e84248..af871b1d5601a 100644 --- a/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs +++ b/frame/support/procedural/src/construct_runtime_v2/parse/mod.rs @@ -20,20 +20,26 @@ pub mod pallet; pub mod pallet_decl; pub mod pallets; pub mod runtime_struct; +pub mod runtime_types; use proc_macro2::TokenStream as TokenStream2; use quote::ToTokens; -use syn::spanned::Spanned; +use syn::{spanned::Spanned, Token}; + +use frame_support_procedural_tools::syn_ext as ext; +use runtime_types::RuntimeType; mod keyword { syn::custom_keyword!(frame); syn::custom_keyword!(runtime); syn::custom_keyword!(pallets); + syn::custom_keyword!(derive); } enum RuntimeAttr { Runtime(proc_macro2::Span), Pallets(proc_macro2::Span), + Derive(proc_macro2::Span, Vec), } impl RuntimeAttr { @@ -41,6 +47,7 @@ impl RuntimeAttr { match self { Self::Runtime(span) => *span, Self::Pallets(span) => *span, + Self::Derive(span, _) => *span, } } } @@ -58,6 +65,14 @@ impl syn::parse::Parse for RuntimeAttr { Ok(RuntimeAttr::Runtime(content.parse::()?.span())) } else if lookahead.peek(keyword::pallets) { Ok(RuntimeAttr::Pallets(content.parse::()?.span())) + } else if lookahead.peek(keyword::derive) { + let _ = content.parse::(); + let derive_content; + syn::parenthesized!(derive_content in content); + let runtime_types = + derive_content.parse::>()?; + let runtime_types = runtime_types.inner.into_iter().collect(); + Ok(RuntimeAttr::Derive(derive_content.span(), runtime_types)) } else { Err(lookahead.error()) } @@ -69,6 +84,7 @@ pub struct Def { pub item: syn::ItemMod, pub runtime_struct: runtime_struct::RuntimeStructDef, pub pallets: pallets::AllPalletsDeclaration, + pub runtime_types: Vec, } impl Def { @@ -86,24 +102,29 @@ impl Def { let mut runtime_struct = None; let mut pallets = None; + let mut runtime_types = None; for item in items.iter_mut() { - let runtime_attr: Option = helper::take_first_item_runtime_attr(item)?; - - match runtime_attr { - Some(RuntimeAttr::Runtime(span)) if runtime_struct.is_none() => { - let p = runtime_struct::RuntimeStructDef::try_from(span, item)?; - runtime_struct = Some(p); - }, - Some(RuntimeAttr::Pallets(span)) if pallets.is_none() => { - let p = pallets::AllPalletsDeclaration::try_from(span, item)?; - pallets = Some(p); - }, - Some(attr) => { - let msg = "Invalid duplicated attribute"; - return Err(syn::Error::new(attr.span(), msg)) - }, - None => (), + while let Some(runtime_attr) = + helper::take_first_item_runtime_attr::(item)? + { + match runtime_attr { + RuntimeAttr::Runtime(span) if runtime_struct.is_none() => { + let p = runtime_struct::RuntimeStructDef::try_from(span, item)?; + runtime_struct = Some(p); + }, + RuntimeAttr::Pallets(span) if pallets.is_none() => { + let p = pallets::AllPalletsDeclaration::try_from(span, item)?; + pallets = Some(p); + }, + RuntimeAttr::Derive(_, types) if runtime_types.is_none() => { + runtime_types = Some(types); + }, + attr => { + let msg = "Invalid duplicated attribute"; + return Err(syn::Error::new(attr.span(), msg)) + }, + } } } @@ -114,6 +135,8 @@ impl Def { .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::runtime]`"))?, pallets: pallets .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::pallets]`"))?, + runtime_types: runtime_types + .ok_or_else(|| syn::Error::new(item_span, "Missing `#[frame::runtime_types]`"))?, }; Ok(def) diff --git a/frame/support/procedural/src/construct_runtime_v2/parse/runtime_types.rs b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_types.rs new file mode 100644 index 0000000000000..a645ade54a40b --- /dev/null +++ b/frame/support/procedural/src/construct_runtime_v2/parse/runtime_types.rs @@ -0,0 +1,70 @@ +// 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 syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +mod keyword { + syn::custom_keyword!(RuntimeCall); + syn::custom_keyword!(RuntimeEvent); + syn::custom_keyword!(RuntimeError); + syn::custom_keyword!(RuntimeOrigin); + syn::custom_keyword!(RuntimeFreezeReason); + syn::custom_keyword!(RuntimeHoldReason); + syn::custom_keyword!(RuntimeSlashReason); + syn::custom_keyword!(RuntimeLockId); +} + +#[derive(Debug, Clone, PartialEq)] +pub enum RuntimeType { + RuntimeCall(keyword::RuntimeCall), + RuntimeEvent(keyword::RuntimeEvent), + RuntimeError(keyword::RuntimeError), + RuntimeOrigin(keyword::RuntimeOrigin), + RuntimeFreezeReason(keyword::RuntimeFreezeReason), + RuntimeHoldReason(keyword::RuntimeHoldReason), + RuntimeSlashReason(keyword::RuntimeSlashReason), + RuntimeLockId(keyword::RuntimeLockId), +} + +impl Parse for RuntimeType { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::RuntimeCall) { + Ok(Self::RuntimeCall(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeEvent) { + Ok(Self::RuntimeEvent(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeError) { + Ok(Self::RuntimeError(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeOrigin) { + Ok(Self::RuntimeOrigin(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeFreezeReason) { + Ok(Self::RuntimeFreezeReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeHoldReason) { + Ok(Self::RuntimeHoldReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeSlashReason) { + Ok(Self::RuntimeSlashReason(input.parse()?)) + } else if lookahead.peek(keyword::RuntimeLockId) { + Ok(Self::RuntimeLockId(input.parse()?)) + } else { + Err(lookahead.error()) + } + } +}