From 7e8baee5bddb3e7f6f4b19b8ffd4ef2a1b8f45f0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 18:05:05 +0300 Subject: [PATCH 01/46] metadata-ir: Introduce PalletAssociatedTypeMetadata Signed-off-by: Alexandru Vasile --- substrate/primitives/metadata-ir/src/types.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index b05f26ff55d4..9001d4c034e9 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -127,6 +127,8 @@ pub struct PalletMetadataIR { pub constants: Vec>, /// Pallet error metadata. pub error: Option>, + /// Config's trait associated types. + pub associated_types: Vec>, /// Define the index of the pallet, this index will be used for the encoding of pallet event, /// call and origin variants. pub index: u8, @@ -145,6 +147,7 @@ impl IntoPortable for PalletMetadataIR { event: self.event.map(|event| event.into_portable(registry)), constants: registry.map_into_portable(self.constants), error: self.error.map(|error| error.into_portable(registry)), + associated_types: registry.map_into_portable(self.associated_types), index: self.index, docs: registry.map_into_portable(self.docs), } @@ -188,6 +191,29 @@ impl IntoPortable for ExtrinsicMetadataIR { } } +/// Metadata of a pallet's associated type. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletAssociatedTypeMetadataIR { + /// The name of the associated type. + pub name: T::String, + /// The type of the associated type. + pub ty: T::Type, + /// The documentation of the associated type. + pub docs: Vec, +} + +impl IntoPortable for PalletAssociatedTypeMetadataIR { + type Output = PalletAssociatedTypeMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletAssociatedTypeMetadataIR { + name: self.name.into_portable(registry), + ty: registry.register_type(&self.ty), + docs: registry.map_into_portable(self.docs), + } + } +} + /// Metadata of an extrinsic's signed extension. #[derive(Clone, PartialEq, Eq, Encode, Debug)] pub struct SignedExtensionMetadataIR { From 1c12f1520605ae32454ca8ab6f480ce794285f65 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 18:11:11 +0300 Subject: [PATCH 02/46] frame/config: Add associated types to parsed config Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/config.rs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 6febaac9ffa3..d4b6169e018c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -55,6 +55,8 @@ pub struct ConfigDef { pub has_instance: bool, /// Const associated type. pub consts_metadata: Vec, + /// Associated types metadata. + pub associated_types_metadata: Vec, /// Whether the trait has the associated type `Event`, note that those bounds are /// checked: /// * `IsType::RuntimeEvent` @@ -70,6 +72,23 @@ pub struct ConfigDef { pub default_sub_trait: Option, } +/// Input definition for an associated type in pallet config. +pub struct AssociatedTypeMetadataDef { + /// Name of the associated type. + pub ident: syn::Ident, + /// The doc associated. + pub doc: Vec, +} + +impl From<&syn::TraitItemType> for AssociatedTypeMetadataDef { + fn from(trait_ty: &syn::TraitItemType) -> Self { + let ident = trait_ty.ident.clone(); + let doc = get_doc_literals(&trait_ty.attrs); + + Self { ident, doc } + } +} + /// Input definition for a constant in pallet config. pub struct ConstMetadataDef { /// Name of the associated type. @@ -366,6 +385,7 @@ impl ConfigDef { let mut has_event_type = false; let mut consts_metadata = vec![]; + let mut associated_types_metadata = vec![]; let mut default_sub_trait = if enable_default { Some(DefaultTrait { items: Default::default(), @@ -405,7 +425,7 @@ impl ConfigDef { if !enable_default { return Err(syn::Error::new( pallet_attr._bracket.span.join(), - "`#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` \ + "`#[pallet::no_default]` can only be used if `#[pallet::config(with_default)]` \ has been specified" )) } @@ -437,6 +457,12 @@ impl ConfigDef { } } + if !is_event && !already_constant { + if let syn::TraitItem::Type(ref ty) = trait_item { + associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); + } + } + if !already_no_default && enable_default { default_sub_trait .as_mut() @@ -479,6 +505,7 @@ impl ConfigDef { index, has_instance, consts_metadata, + associated_types_metadata, has_event_type, where_clause, default_sub_trait, From 20b22d8d314df7dfb6590f6d54857190231b77c2 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 18:14:29 +0300 Subject: [PATCH 03/46] frame/expand: Implement associated types expansion Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/expand/config.rs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 5cf4035a8f8b..7e67aae93410 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -95,3 +95,48 @@ Consequently, a runtime that wants to include this pallet must implement this tr _ => Default::default(), } } + +/// Generate the metadata for the associated types of the config trait. +/// +/// Implements the `pallet_associated_types_metadata` function for the pallet. +pub fn expand_config_metadata(def: &mut Def) -> proc_macro2::TokenStream { + let frame_support = &def.frame_support; + let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site()); + let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site()); + let pallet_ident = &def.pallet_struct.pallet; + let trait_use_gen = &def.trait_use_generics(proc_macro2::Span::call_site()); + + let mut where_clauses = vec![&def.config.where_clause]; + where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause)); + let completed_where_clause = super::merge_where_clauses(&where_clauses); + + let types = def.config.associated_types_metadata.iter().map(|metadata| { + let ident = &metadata.ident; + let ident_str = format!("{}", ident); + + let no_docs = vec![]; + let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &metadata.doc }; + + quote::quote!({ + #frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR { + name: #ident_str, + ty: #frame_support::__private::scale_info::meta_type::< + <::#ident + >(), + docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], + } + }) + }); + + quote::quote!( + impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause { + + #[doc(hidden)] + pub fn pallet_associated_types_metadata() + -> #frame_support::__private::sp_std::vec::Vec<#frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR> + { + #frame_support::__private::sp_std::vec![ #( #types ),* ] + } + } + ) +} From 350efce92491f6cb21e641526e45cba339d2fa35 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 18:17:37 +0300 Subject: [PATCH 04/46] frame/expand: Use provided cfgs for the associated types Signed-off-by: Alexandru Vasile --- .../support/procedural/src/pallet/expand/config.rs | 2 ++ .../support/procedural/src/pallet/parse/config.rs | 7 +++++-- .../frame/support/procedural/tools/src/lib.rs | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 7e67aae93410..1921922781fe 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -113,11 +113,13 @@ pub fn expand_config_metadata(def: &mut Def) -> proc_macro2::TokenStream { let types = def.config.associated_types_metadata.iter().map(|metadata| { let ident = &metadata.ident; let ident_str = format!("{}", ident); + let cfgs = &metadata.cfg; let no_docs = vec![]; let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &metadata.doc }; quote::quote!({ + #( #cfgs ) * #frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR { name: #ident_str, ty: #frame_support::__private::scale_info::meta_type::< diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index d4b6169e018c..f92f69c7a1d6 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -16,7 +16,7 @@ // limitations under the License. use super::helper; -use frame_support_procedural_tools::{get_doc_literals, is_using_frame_crate}; +use frame_support_procedural_tools::{get_cfg_attributes, get_doc_literals, is_using_frame_crate}; use quote::ToTokens; use syn::{spanned::Spanned, token, Token}; @@ -78,14 +78,17 @@ pub struct AssociatedTypeMetadataDef { pub ident: syn::Ident, /// The doc associated. pub doc: Vec, + /// The cfg associated. + pub cfg: Vec, } impl From<&syn::TraitItemType> for AssociatedTypeMetadataDef { fn from(trait_ty: &syn::TraitItemType) -> Self { let ident = trait_ty.ident.clone(); let doc = get_doc_literals(&trait_ty.attrs); + let cfg = get_cfg_attributes(&trait_ty.attrs); - Self { ident, doc } + Self { ident, doc, cfg } } } diff --git a/substrate/frame/support/procedural/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index ea53335a88fd..d1d7efaab01d 100644 --- a/substrate/frame/support/procedural/tools/src/lib.rs +++ b/substrate/frame/support/procedural/tools/src/lib.rs @@ -181,3 +181,17 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { }) .collect() } + +/// Return all cfg attributes literals found. +pub fn get_cfg_attributes(attrs: &[syn::Attribute]) -> Vec { + attrs + .iter() + .filter_map(|attr| { + if let syn::Meta::List(meta) = &attr.meta { + meta.path.get_ident().filter(|ident| *ident == "cfg").map(|_| attr.clone()) + } else { + None + } + }) + .collect() +} From 3e97971d0b4840553dbc731d8f27737e130f4411 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 18:33:25 +0300 Subject: [PATCH 05/46] frame/construct_runtime: Extract associated types from pallet config Signed-off-by: Alexandru Vasile --- .../src/construct_runtime/expand/metadata.rs | 11 +++++++++++ .../support/procedural/src/pallet/expand/config.rs | 4 ++-- .../frame/support/procedural/src/pallet/expand/mod.rs | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index daef1b171617..cbefd9601701 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -49,6 +49,7 @@ pub fn expand_runtime_metadata( 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 associated_types = expand_pallet_metadata_associated_types(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())) @@ -70,6 +71,7 @@ pub fn expand_runtime_metadata( constants: #constants, error: #errors, docs: #docs, + associated_types: #associated_types, } } }) @@ -256,3 +258,12 @@ fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream { #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata() } } + +fn expand_pallet_metadata_associated_types(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_associated_types_metadata() + } +} diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 1921922781fe..6b79c4b8b25a 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -99,7 +99,7 @@ Consequently, a runtime that wants to include this pallet must implement this tr /// Generate the metadata for the associated types of the config trait. /// /// Implements the `pallet_associated_types_metadata` function for the pallet. -pub fn expand_config_metadata(def: &mut Def) -> proc_macro2::TokenStream { +pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream { let frame_support = &def.frame_support; let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site()); let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site()); @@ -123,7 +123,7 @@ pub fn expand_config_metadata(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR { name: #ident_str, ty: #frame_support::__private::scale_info::meta_type::< - <::#ident + ::#ident >(), docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], } diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 067839c28463..3f9b50f79c0c 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -60,6 +60,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let constants = constants::expand_constants(&mut def); let pallet_struct = pallet_struct::expand_pallet_struct(&mut def); let config = config::expand_config(&mut def); + let associated_types = config::expand_config_metadata(&def); let call = call::expand_call(&mut def); let tasks = tasks::expand_tasks(&mut def); let error = error::expand_error(&mut def); @@ -101,6 +102,7 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*] #constants #pallet_struct #config + #associated_types #call #tasks #error From 5d8021eb1b58d605e77bb16427092933525092bb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 19:30:44 +0300 Subject: [PATCH 06/46] frame/pallet: Introduce `config(without_metadata)` Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/config.rs | 4 +- .../procedural/src/pallet/parse/mod.rs | 60 ++++++++++++++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index f92f69c7a1d6..5c11bf8dbcaf 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -36,6 +36,7 @@ mod keyword { syn::custom_keyword!(no_default); syn::custom_keyword!(no_default_bounds); syn::custom_keyword!(constant); + syn::custom_keyword!(without_metadata); } #[derive(Default)] @@ -348,6 +349,7 @@ impl ConfigDef { index: usize, item: &mut syn::Item, enable_default: bool, + without_metadata: bool, ) -> syn::Result { let syn::Item::Trait(item) = item else { let msg = "Invalid pallet::config, expected trait definition"; @@ -460,7 +462,7 @@ impl ConfigDef { } } - if !is_event && !already_constant { + if !without_metadata && !is_event && !already_constant { if let syn::TraitItem::Type(ref ty) = trait_item { associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); } diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index f55b166c7917..fe709bf89ce8 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -43,6 +43,7 @@ pub mod tests; use composite::{keyword::CompositeKeyword, CompositeDef}; use frame_support_procedural_tools::generate_access_from_frame_or_crate; use quote::ToTokens; +use std::collections::HashSet; use syn::spanned::Spanned; /// Parsed definition of a pallet. @@ -109,12 +110,13 @@ impl Def { let pallet_attr: Option = helper::take_first_item_pallet_attr(item)?; match pallet_attr { - Some(PalletAttr::Config(_, with_default)) if config.is_none() => + Some(PalletAttr::Config{ with_default, without_metadata, ..}) if config.is_none() => config = Some(config::ConfigDef::try_from( &frame_system, index, item, with_default, + without_metadata, )?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; @@ -548,6 +550,7 @@ mod keyword { syn::custom_keyword!(event); syn::custom_keyword!(config); syn::custom_keyword!(with_default); + syn::custom_keyword!(without_metadata); syn::custom_keyword!(hooks); syn::custom_keyword!(inherent); syn::custom_keyword!(error); @@ -561,10 +564,35 @@ mod keyword { syn::custom_keyword!(composite_enum); } +/// The possible values for the `#[pallet::config]` attribute. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum ConfigValue { + /// `#[pallet::config(with_default)]` + WithDefault(keyword::with_default), + /// `#[pallet::config(without_metadata)]` + WithoutMetadata(keyword::without_metadata), +} + +impl syn::parse::Parse for ConfigValue { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + if input.peek(keyword::with_default) { + Ok(ConfigValue::WithDefault(input.parse()?)) + } else if input.peek(keyword::without_metadata) { + Ok(ConfigValue::WithoutMetadata(input.parse()?)) + } else { + Err(input.error("expected `with_default` or `without_metadata`")) + } + } +} + /// Parse attributes for item in pallet module /// syntax must be `pallet::` (e.g. `#[pallet::config]`) enum PalletAttr { - Config(proc_macro2::Span, bool), + Config { + span: proc_macro2::Span, + with_default: bool, + without_metadata: bool, + }, Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), /// A `#[pallet::call]` with optional attributes to specialize the behaviour. @@ -626,7 +654,7 @@ enum PalletAttr { impl PalletAttr { fn span(&self) -> proc_macro2::Span { match self { - Self::Config(span, _) => *span, + Self::Config { span, .. } => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, Self::Tasks(span) => *span, @@ -661,13 +689,31 @@ impl syn::parse::Parse for PalletAttr { let lookahead = content.lookahead1(); if lookahead.peek(keyword::config) { let span = content.parse::()?.span(); - let with_default = content.peek(syn::token::Paren); - if with_default { + if content.peek(syn::token::Paren) { let inside_config; + + // Parse (with_default, without_metadata) attributes. let _paren = syn::parenthesized!(inside_config in content); - inside_config.parse::()?; + + let fields: syn::punctuated::Punctuated = + inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?; + let config_values = fields.iter().collect::>(); + + let with_default = + config_values.iter().any(|v| matches!(v, ConfigValue::WithDefault(_))); + let without_metadata = + config_values.iter().any(|v| matches!(v, ConfigValue::WithoutMetadata(_))); + + // Check for duplicated attributes. + let config_set = config_values.iter().collect::>(); + if config_set.len() != config_values.len() { + return Err(syn::Error::new(span, "Invalid duplicated attribute")) + } + + Ok(PalletAttr::Config { span, with_default, without_metadata }) + } else { + Ok(PalletAttr::Config { span, with_default: false, without_metadata: false }) } - Ok(PalletAttr::Config(span, with_default)) } else if lookahead.peek(keyword::pallet) { Ok(PalletAttr::Pallet(content.parse::()?.span())) } else if lookahead.peek(keyword::hooks) { From 5679244aa99794ef415a17992f2c237ee1f40440 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 19:42:50 +0300 Subject: [PATCH 07/46] frame/pallet: Introduce `#[pallet::include_metadata]` for associated types Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/config.rs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 5c11bf8dbcaf..65b2b195e94c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -36,7 +36,7 @@ mod keyword { syn::custom_keyword!(no_default); syn::custom_keyword!(no_default_bounds); syn::custom_keyword!(constant); - syn::custom_keyword!(without_metadata); + syn::custom_keyword!(include_metadata); } #[derive(Default)] @@ -167,6 +167,8 @@ pub enum PalletAttrType { NoBounds(keyword::no_default_bounds), #[peek(keyword::constant, name = "constant")] Constant(keyword::constant), + #[peek(keyword::include_metadata, name = "include_metadata")] + IncludeMetadata(keyword::include_metadata), } /// Parsing for `#[pallet::X]` @@ -349,7 +351,7 @@ impl ConfigDef { index: usize, item: &mut syn::Item, enable_default: bool, - without_metadata: bool, + enable_associated_metadata: bool, ) -> syn::Result { let syn::Item::Trait(item) = item else { let msg = "Invalid pallet::config, expected trait definition"; @@ -406,6 +408,7 @@ impl ConfigDef { let mut already_no_default = false; let mut already_constant = false; let mut already_no_default_bounds = false; + let mut already_collected_associated_type = false; while let Ok(Some(pallet_attr)) = helper::take_first_item_pallet_attr::(trait_item) @@ -426,6 +429,31 @@ impl ConfigDef { trait_item.span(), "Invalid #[pallet::constant] in #[pallet::config], expected type item", )), + (PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { + if is_event { + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Invalid #[pallet::include_metadata] in `type RuntimeEvent`, \ + expected type item. The associated type `RuntimeEvent` is already collected.", + )) + } + + if already_constant { + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Invalid #[pallet::include_metadata] in #[pallet::constant], \ + expected type item. Pallet constant's metadata is already collected.", + )) + } + + already_collected_associated_type = true; + associated_types_metadata.push(AssociatedTypeMetadataDef::from(typ)); + } + (PalletAttrType::IncludeMetadata(_), _) => + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Invalid #[pallet::include_metadata] in #[pallet::config], expected type item", + )), (PalletAttrType::NoDefault(_), _) => { if !enable_default { return Err(syn::Error::new( @@ -462,7 +490,7 @@ impl ConfigDef { } } - if !without_metadata && !is_event && !already_constant { + if !already_collected_associated_type && enable_associated_metadata { if let syn::TraitItem::Type(ref ty) = trait_item { associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); } From 958611ef5a5a5a73ca51878bce4a6e0b1b111740 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 20:13:15 +0300 Subject: [PATCH 08/46] frame/pallet: Include associated type iff bounds contain TypeInfo Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/config.rs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 65b2b195e94c..2f8a0923b6c5 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -18,7 +18,7 @@ use super::helper; use frame_support_procedural_tools::{get_cfg_attributes, get_doc_literals, is_using_frame_crate}; use quote::ToTokens; -use syn::{spanned::Spanned, token, Token}; +use syn::{spanned::Spanned, token, Token, TraitItemType}; /// List of additional token to be used for parsing. mod keyword { @@ -345,6 +345,23 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS .collect() } +/// Check that the trait item requires the `TypeInfo` bound (or similar). +fn contains_type_info_bound(ty: &TraitItemType) -> bool { + const KNOWN_TYPE_INFO_BOUNDS: &[&str] = &[ + // Explicit TypeInfo trait. + "TypeInfo", + // Implicit known substrate traits that implement type info. + // Note: Aim to keep this list as small as possible. + "Parameter", + ]; + + ty.bounds.iter().any(|bound| { + let syn::TypeParamBound::Trait(bound) = bound else { return false }; + + KNOWN_TYPE_INFO_BOUNDS.iter().any(|known| bound.path.is_ident(known)) + }) +} + impl ConfigDef { pub fn try_from( frame_system: &syn::Path, @@ -429,6 +446,9 @@ impl ConfigDef { trait_item.span(), "Invalid #[pallet::constant] in #[pallet::config], expected type item", )), + // Pallet developer has explicitly requested to include metadata for this associated type. + // + // They must provide a type item that implements `TypeInfo`. (PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { if is_event { return Err(syn::Error::new( @@ -490,9 +510,17 @@ impl ConfigDef { } } - if !already_collected_associated_type && enable_associated_metadata { + // Metadata of associated types is collected by default, iff the associated type + // implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound. + if !already_collected_associated_type && + enable_associated_metadata && + !is_event && !already_constant + { if let syn::TraitItem::Type(ref ty) = trait_item { - associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); + // Collect the metadata of the associated type if it implements `TypeInfo`. + if contains_type_info_bound(ty) { + associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); + } } } From 7f26b67a7b33dc78c9fc2572a073e77bf14b2610 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 7 Aug 2024 20:13:37 +0300 Subject: [PATCH 09/46] frame/pallet: Proper flag for metdata collection Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index fe709bf89ce8..bf933bc820f3 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -116,7 +116,7 @@ impl Def { index, item, with_default, - without_metadata, + !without_metadata, )?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; From cc001f389f80abbdf511b911c2fd04007f1eedcb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 11:05:10 +0300 Subject: [PATCH 10/46] frame/tests/ui: Fix type in test Signed-off-by: Alexandru Vasile --- .../tests/pallet_ui/no_default_but_missing_with_default.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr index e8df28a3046f..1b066bbe9fb8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr @@ -1,4 +1,4 @@ -error: `#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` has been specified +error: `#[pallet::no_default]` can only be used if `#[pallet::config(with_default)]` has been specified --> tests/pallet_ui/no_default_but_missing_with_default.rs:26:4 | 26 | #[pallet::no_default] From b2803e2f2f785702de70e0825274eeffdd014d46 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 11:12:19 +0300 Subject: [PATCH 11/46] frame/tests/ui: Check config without metadata Signed-off-by: Alexandru Vasile --- .../pallet_ui/pass/config_without_metadata.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs new file mode 100644 index 000000000000..9304b2ccc9bf --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs @@ -0,0 +1,32 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(without_metadata)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(_); +} + +fn main() {} From 94007d8c3189d5781db5ffe9d31d54cdc8a56cbd Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 11:12:34 +0300 Subject: [PATCH 12/46] frame/tests/ui: Check config with multiple attributes Signed-off-by: Alexandru Vasile --- .../pallet_ui/pass/config_multiple_attr.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs new file mode 100644 index 000000000000..1eee25b333e4 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs @@ -0,0 +1,32 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(with_default, without_metadata)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(_); +} + +fn main() {} From 75d26971b5e5520fbf8937a74665f1f1018e32c8 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 11:50:00 +0300 Subject: [PATCH 13/46] frame/tests/ui: Add negative test for duplicate attributes in config Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/mod.rs | 5 ++- .../tests/pallet_ui/config_duplicate_attr.rs | 39 +++++++++++++++++++ .../pallet_ui/config_duplicate_attr.stderr | 5 +++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index bf933bc820f3..6f5a599b08ee 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -707,7 +707,10 @@ impl syn::parse::Parse for PalletAttr { // Check for duplicated attributes. let config_set = config_values.iter().collect::>(); if config_set.len() != config_values.len() { - return Err(syn::Error::new(span, "Invalid duplicated attribute")) + return Err(syn::Error::new( + span, + "Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates.", + )); } Ok(PalletAttr::Config { span, with_default, without_metadata }) diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs new file mode 100644 index 000000000000..3d7b4f87d22c --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config(with_default, without_metadata, without_metadata)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr new file mode 100644 index 000000000000..7217aa370ed5 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr @@ -0,0 +1,5 @@ +error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates. + --> tests/pallet_ui/config_duplicate_attr.rs:23:12 + | +23 | #[pallet::config(with_default, without_metadata, without_metadata)] + | ^^^^^^ From ebcb4a0aa5e6c65d17f15d49262bb4b4b3482964 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 11:53:49 +0300 Subject: [PATCH 14/46] frame/tests/ui: Add negative test for collecting metadata from constants Signed-off-by: Alexandru Vasile --- .../pallet_ui/config_metadata_on_constants.rs | 40 +++++++++++++++++++ .../config_metadata_on_constants.stderr | 5 +++ 2 files changed, 45 insertions(+) create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs new file mode 100644 index 000000000000..a4ff02aeb1cd --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + #[pallet::constant] + #[pallet::include_metadata] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr new file mode 100644 index 000000000000..ac27bfe89a08 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr @@ -0,0 +1,5 @@ +error: Invalid #[pallet::include_metadata] in #[pallet::constant], expected type item. Pallet constant's metadata is already collected. + --> tests/pallet_ui/config_metadata_on_constants.rs:26:10 + | +26 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ From 51150217bf9cf8869a141e1cfe5f2dcd063e6594 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 11:58:52 +0300 Subject: [PATCH 15/46] frame/tests/ui: Add negative test for metadata collection on events Signed-off-by: Alexandru Vasile --- .../pallet_ui/config_metadata_on_events.rs | 43 +++++++++++++++++++ .../config_metadata_on_events.stderr | 5 +++ 2 files changed, 48 insertions(+) create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs new file mode 100644 index 000000000000..d91f86771bf6 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs @@ -0,0 +1,43 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config { + #[pallet::no_default_bounds] + #[pallet::include_metadata] + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr new file mode 100644 index 000000000000..0c79929bca37 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr @@ -0,0 +1,5 @@ +error: Invalid #[pallet::include_metadata] in `type RuntimeEvent`, expected type item. The associated type `RuntimeEvent` is already collected. + --> tests/pallet_ui/config_metadata_on_events.rs:26:4 + | +26 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ From aba029a471f26dd5e1c4286104eb53029ceafd15 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:07:25 +0300 Subject: [PATCH 16/46] frame/tests: Check PalletAssociatedTypeMetadataIR collection Signed-off-by: Alexandru Vasile --- .../tests/pallet_associated_types_metadata.rs | 269 ++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 substrate/frame/support/test/tests/pallet_associated_types_metadata.rs diff --git a/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs new file mode 100644 index 000000000000..9de5d79ad34c --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs @@ -0,0 +1,269 @@ +// 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::{derive_impl, traits::ConstU32}; +use scale_info::meta_type; +use sp_metadata_ir::PalletAssociatedTypeMetadataIR; + +pub type BlockNumber = u64; +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +/// Pallet without collectable associated types. +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + // Runtime events already propagated to the metadata. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Constants are already propagated. + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::event] + pub enum Event { + TestEvent, + } +} + +/// Pallet with default collectable associated types. +#[frame_support::pallet] +pub mod pallet2 { + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + // Runtime events already propagated to the metadata. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Constants are already propagated. + #[pallet::constant] + type MyGetParam2: Get; + + // Associated type included by default, because it requires TypeInfo bound. + /// Nonce doc. + type Nonce: TypeInfo; + + // Associated type included by default, because it requires + // Parameter bound (indirect TypeInfo). + type AccountData: Parameter; + + // Associated type without metadata bounds, not included. + type NotIncluded: From; + } + + #[pallet::event] + pub enum Event { + TestEvent, + } +} + +/// Pallet with implicit collectable associated types. +#[frame_support::pallet] +pub mod pallet3 { + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + // Associated types are not collected by default. + #[pallet::config(without_metadata)] + pub trait Config: frame_system::Config { + // Runtime events already propagated to the metadata. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Constants are already propagated. + #[pallet::constant] + type MyGetParam2: Get; + + // Explicitly include associated types. + #[pallet::include_metadata] + type Nonce: TypeInfo; + + type AccountData: Parameter; + + type NotIncluded: From; + } + + #[pallet::event] + pub enum Event { + TestEvent, + } +} + +impl pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MyGetParam2 = ConstU32<10>; +} + +impl pallet2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MyGetParam2 = ConstU32<10>; + type Nonce = u64; + type AccountData = u16; + type NotIncluded = u8; +} + +impl pallet3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MyGetParam2 = ConstU32<10>; + type Nonce = u64; + type AccountData = u16; + type NotIncluded = u8; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type Nonce = u64; + type RuntimeCall = RuntimeCall; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +frame_support::construct_runtime!( + pub enum Runtime + { + System: frame_system, + Example: pallet, + DefaultInclusion: pallet2, + ExplicitInclusion: pallet3, + } +); + +#[test] +fn associated_types_metadata() { + fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } + } + + let ir = Runtime::metadata_ir(); + + // No associated types to collect. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "Example").unwrap(); + pretty_assertions::assert_eq!(pallet.associated_types, vec![]); + + // Collect by default types that implement TypeInfo or Parameter. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "DefaultInclusion").unwrap(); + pretty_assertions::assert_eq!( + pallet.associated_types, + vec![ + PalletAssociatedTypeMetadataIR { + name: "Nonce", + ty: meta_type::(), + docs: maybe_docs(vec![" Nonce doc."]), + }, + PalletAssociatedTypeMetadataIR { + name: "AccountData", + ty: meta_type::(), + docs: vec![], + } + ] + ); + + // Explicitly include associated types. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "ExplicitInclusion").unwrap(); + pretty_assertions::assert_eq!( + pallet.associated_types, + vec![PalletAssociatedTypeMetadataIR { + name: "Nonce", + ty: meta_type::(), + docs: vec![], + }] + ); + + // Check system pallet. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "System").unwrap(); + pretty_assertions::assert_eq!( + pallet.associated_types, + vec![ + PalletAssociatedTypeMetadataIR { + name: "RuntimeCall", + ty: meta_type::(), + docs: maybe_docs(vec![" The aggregated `RuntimeCall` type."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Nonce", + ty: meta_type::(), + docs: maybe_docs(vec![" This stores the number of previous transactions associated with a sender account."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Hash", + ty: meta_type::(), + docs: maybe_docs(vec![" The output of the `Hashing` function."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Hashing", + ty: meta_type::(), + docs: maybe_docs(vec![" The hashing system (algorithm) being used in the runtime (e.g. Blake2)."]), + }, + PalletAssociatedTypeMetadataIR { + name: "AccountId", + ty: meta_type::(), + docs: maybe_docs(vec![" The user account identifier type for the runtime."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Block", + ty: meta_type::(), + docs: maybe_docs(vec![ + " The Block type used by the runtime. This is used by `construct_runtime` to retrieve the", + " extrinsics or other block specific data as needed.", + ]), + }, + PalletAssociatedTypeMetadataIR { + name: "AccountData", + ty: meta_type::<()>(), + docs: maybe_docs(vec![ + " Data to be associated with an account (other than nonce/transaction counter, which this", + " pallet does regardless).", + ]), + }, + ] + ); +} From 6502c830889275418dc3392881aa52ce0da96dcf Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:27:56 +0300 Subject: [PATCH 17/46] frame/support: Add documentation Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/lib.rs | 9 +++ substrate/frame/support/src/lib.rs | 62 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index ef99faee86ae..05f6333cd275 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -955,6 +955,15 @@ pub fn event(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// +/// Documentation for this macro can be found at `frame_support::pallet_macros::include_metadata`. +#[proc_macro_attribute] +pub fn include_metadata(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// /// --- /// diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index bd571571ee24..2d882dd224f5 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1556,6 +1556,57 @@ pub mod pallet_macros { /// * [`frame_support::derive_impl`]. /// * [`#[pallet::no_default]`](`no_default`) /// * [`#[pallet::no_default_bounds]`](`no_default_bounds`) + /// + /// ## Optional: `without_metadata` + /// + /// By default, the associated types of the `Config` trait that require the `TypeInfo` or + /// `Parameter` bounds are included in the metadata of the pallet. Please note that the + /// `RuntimeEvent` and constants are already included in the metadata. + /// + /// The optional `without_metadata` argument can be used to exclude these associated types + /// from the metadata collection. + /// + /// Furthermore, the `without_metadata` argument can be used in combination with the + /// [`#[pallet::include_metadata]`](`include_metadata`) attribute to selectively include + /// only certain associated types in the metadata collection. + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # use core::fmt::Debug; + /// # use frame_support::traits::Contains; + /// # + /// # pub trait SomeMoreComplexBound {} + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::config(with_default, without_metadata)] // <- with_default and without_metadata are optional + /// pub trait Config: frame_system::Config { + /// /// The overarching event type. + /// #[pallet::no_default_bounds] // Default with bounds is not supported for RuntimeEvent + /// type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// + /// /// A simple type. + /// // Type that would have been included in metadata, but is now excluded. + /// type SimpleType: From + TypeInfo; + /// + /// // The `pallet::include_metadata` is used to selectively include this type in metadata. + /// #[pallet::include_metadata] + /// type SelectivelyInclude: From + TypeInfo; + /// } + /// + /// #[pallet::event] + /// pub enum Event { + /// SomeEvent(u16, u32), + /// } + /// } + /// ``` + /// + /// For more information, see: + /// * [`#[pallet::include_metadata]`](`include_metadata`) pub use frame_support_procedural::config; /// Allows defining an enum that gets composed as an aggregate enum by `construct_runtime`. @@ -1935,6 +1986,17 @@ pub mod pallet_macros { /// `Member`, available in [`frame_support::pallet_prelude`]. pub use frame_support_procedural::event; + /// Selectively includes associated types in the metadata. + /// + /// The optional attribute allows you to selectively include associated types in the + /// metadata. This can be attached to trait items that implement `TypeInfo`. + /// + /// By default all collectable associated types are included in the metadata. + /// + /// This attribute can be used in combination with the + /// [`#[pallet::config(without_metadata)]`](`config`). + pub use frame_support_procedural::include_metadata; + /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. /// /// In slightly simplified terms, this macro declares the set of "transactions" of a From e9571cbdd505ebfb57c567c988245c97413ae621 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:33:52 +0300 Subject: [PATCH 18/46] Add PRdoc Signed-off-by: Alexandru Vasile --- prdoc/pr_5274.prdoc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 prdoc/pr_5274.prdoc diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc new file mode 100644 index 000000000000..44c7085ef9d7 --- /dev/null +++ b/prdoc/pr_5274.prdoc @@ -0,0 +1,24 @@ +title: Enrich metadata IR with associated types of config traits + +doc: + - audience: Runtime Dev + description: | + This feature is part of the upcoming metadata V16. The associated types of the `Config` trait that require the `TypeInfo` + or `Parameter` bounds are included in the metadata of the pallet. The metadata is not yet exposed to the end-user, however + the metadata intermediate representation (IR) contains these types. + + Developers can opt out of metadata collection of the associated types by specifying `without_metadata` optional attribute + to the `#[pallet::config]`. + + Furthermore, the `without_metadata` argument can be used in combination with the newly added `#[pallet::include_metadata]` + attribute to selectively include only certain associated types in the metadata collection. + +crates: + - name: frame-support-procedural + bump: minor + - name: frame-support-procedural-tools + bump: minor + - name: sp-metadata-ir + bump: minor + - name: pallet-assets + bump: minor \ No newline at end of file From 7429eb7102518da7f74390b2b67ac5fa0d0c6a3f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:48:35 +0300 Subject: [PATCH 19/46] Update prdoc Signed-off-by: Alexandru Vasile --- prdoc/pr_5274.prdoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc index 44c7085ef9d7..f3ec67da4a42 100644 --- a/prdoc/pr_5274.prdoc +++ b/prdoc/pr_5274.prdoc @@ -15,10 +15,10 @@ doc: crates: - name: frame-support-procedural - bump: minor + bump: patch - name: frame-support-procedural-tools - bump: minor + bump: patch - name: sp-metadata-ir - bump: minor + bump: patch - name: pallet-assets - bump: minor \ No newline at end of file + bump: patch From 8a0c138490971761e52b74bf729686b7c5eff84c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:48:51 +0300 Subject: [PATCH 20/46] prdoc: Remove unneeded crate Signed-off-by: Alexandru Vasile --- prdoc/pr_5274.prdoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc index f3ec67da4a42..85f7d1cc2862 100644 --- a/prdoc/pr_5274.prdoc +++ b/prdoc/pr_5274.prdoc @@ -20,5 +20,3 @@ crates: bump: patch - name: sp-metadata-ir bump: patch - - name: pallet-assets - bump: patch From c6c1800fca82bb2003097f86811e9f53aefb5df2 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:49:23 +0300 Subject: [PATCH 21/46] prdoc: Include frame-support Signed-off-by: Alexandru Vasile --- prdoc/pr_5274.prdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc index 85f7d1cc2862..304e3e3f779e 100644 --- a/prdoc/pr_5274.prdoc +++ b/prdoc/pr_5274.prdoc @@ -14,6 +14,8 @@ doc: attribute to selectively include only certain associated types in the metadata collection. crates: + - name: frame-support + bump: patch - name: frame-support-procedural bump: patch - name: frame-support-procedural-tools From 90c100c0c67c0d273613292093f574040d923fcd Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 8 Aug 2024 13:57:45 +0300 Subject: [PATCH 22/46] Prupdate Signed-off-by: Alexandru Vasile --- prdoc/pr_5274.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc index 304e3e3f779e..fb76ce661b4e 100644 --- a/prdoc/pr_5274.prdoc +++ b/prdoc/pr_5274.prdoc @@ -21,4 +21,4 @@ crates: - name: frame-support-procedural-tools bump: patch - name: sp-metadata-ir - bump: patch + bump: major From f703e4debebc402884edeb95a0fdf4a90a1245c5 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:53:35 +0300 Subject: [PATCH 23/46] Update substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- .../test/tests/pallet_ui/config_metadata_on_constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs index a4ff02aeb1cd..5452479b76e7 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs @@ -23,7 +23,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { #[pallet::constant] - #[pallet::include_metadata] + #[pallet::include_metadata] type MyGetParam2: Get; } From fbd36bc6f624be0e867652aee00ba961071370f7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:53:43 +0300 Subject: [PATCH 24/46] Update substrate/frame/support/procedural/src/pallet/expand/config.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- substrate/frame/support/procedural/src/pallet/expand/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 6b79c4b8b25a..07c48a556005 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -112,7 +112,7 @@ pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream { let types = def.config.associated_types_metadata.iter().map(|metadata| { let ident = &metadata.ident; - let ident_str = format!("{}", ident); + let ident_str = ident.to_string(); let cfgs = &metadata.cfg; let no_docs = vec![]; From 6be9ef3fe09c14d11fce7b0c773bab8e99cbe6c7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:54:18 +0300 Subject: [PATCH 25/46] Update substrate/frame/support/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- substrate/frame/support/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 232e52b267be..c8a7a39681b7 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1566,8 +1566,7 @@ pub mod pallet_macros { /// ## Optional: `without_metadata` /// /// By default, the associated types of the `Config` trait that require the `TypeInfo` or - /// `Parameter` bounds are included in the metadata of the pallet. Please note that the - /// `RuntimeEvent` and constants are already included in the metadata. + /// `Parameter` bounds are included in the metadata of the pallet. /// /// The optional `without_metadata` argument can be used to exclude these associated types /// from the metadata collection. From c9b0e2a7d3975b27ac67e2506dd9a9c4e7a9c123 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 1 Oct 2024 18:21:21 +0300 Subject: [PATCH 26/46] frame/parse: Include duplicates in error message Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/mod.rs | 32 ++++++++++++------- .../pallet_ui/config_duplicate_attr.stderr | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 5a7ccf0e5c64..5ff7281311ca 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -43,7 +43,7 @@ pub mod tests; use composite::{keyword::CompositeKeyword, CompositeDef}; use frame_support_procedural_tools::generate_access_from_frame_or_crate; use quote::ToTokens; -use std::collections::HashSet; +use std::collections::HashMap; use syn::spanned::Spanned; /// Parsed definition of a pallet. @@ -698,18 +698,26 @@ impl syn::parse::Parse for PalletAttr { inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?; let config_values = fields.iter().collect::>(); - let with_default = - config_values.iter().any(|v| matches!(v, ConfigValue::WithDefault(_))); + let frequencies = config_values.iter().fold(HashMap::new(), |mut map, val| { + let string_name = match val { + ConfigValue::WithDefault(_) => "with_default", + ConfigValue::WithoutMetadata(_) => "without_metadata", + } + .to_string(); + map.entry(string_name).and_modify(|frq| *frq += 1).or_insert(1); + map + }); + let with_default = frequencies.get("with_default").copied().unwrap_or(0) > 0; let without_metadata = - config_values.iter().any(|v| matches!(v, ConfigValue::WithoutMetadata(_))); - - // Check for duplicated attributes. - let config_set = config_values.iter().collect::>(); - if config_set.len() != config_values.len() { - return Err(syn::Error::new( - span, - "Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates.", - )); + frequencies.get("without_metadata").copied().unwrap_or(0) > 0; + + let duplicates = frequencies + .into_iter() + .filter_map(|(name, frq)| if frq > 1 { Some(name) } else { None }) + .collect::>(); + if !duplicates.is_empty() { + let msg = format!("Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: {}.", duplicates.join(", ")); + return Err(syn::Error::new(span, msg)); } Ok(PalletAttr::Config { span, with_default, without_metadata }) diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr index 7217aa370ed5..0fdbd94dc816 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr @@ -1,4 +1,4 @@ -error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates. +error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_metadata. --> tests/pallet_ui/config_duplicate_attr.rs:23:12 | 23 | #[pallet::config(with_default, without_metadata, without_metadata)] From 0382d322d7ec98db16e01b1b9389ccfee00869b7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 1 Oct 2024 18:25:27 +0300 Subject: [PATCH 27/46] frame/parse: Change parsing with lookahead Signed-off-by: Alexandru Vasile --- .../frame/support/procedural/src/pallet/parse/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 5ff7281311ca..02aa7f7843e2 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -574,10 +574,12 @@ enum ConfigValue { impl syn::parse::Parse for ConfigValue { fn parse(input: syn::parse::ParseStream) -> syn::Result { - if input.peek(keyword::with_default) { - Ok(ConfigValue::WithDefault(input.parse()?)) + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::with_default) { + input.parse().map(ConfigValue::WithDefault) } else if input.peek(keyword::without_metadata) { - Ok(ConfigValue::WithoutMetadata(input.parse()?)) + input.parse().map(ConfigValue::WithoutMetadata) } else { Err(input.error("expected `with_default` or `without_metadata`")) } From e52ba1dedbf45f27ee02f5ce13e33d798e3aa0b4 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 1 Oct 2024 18:30:46 +0300 Subject: [PATCH 28/46] frame/lib: Remove links to include_metadata Signed-off-by: Alexandru Vasile --- substrate/frame/support/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index c8a7a39681b7..41dcc9d3257d 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1609,9 +1609,6 @@ pub mod pallet_macros { /// } /// } /// ``` - /// - /// For more information, see: - /// * [`#[pallet::include_metadata]`](`include_metadata`) pub use frame_support_procedural::config; /// Allows defining an enum that gets composed as an aggregate enum by `construct_runtime`. From 45f86ebe1714f0c09da78eac7fbcc44acef21eaf Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 1 Oct 2024 19:06:14 +0300 Subject: [PATCH 29/46] pallet/parse: Collect associated metadata while taking constants into account Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/config.rs | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 713c58f201f8..d85480731d3c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -427,7 +427,7 @@ impl ConfigDef { let mut already_no_default = false; let mut already_constant = false; let mut already_no_default_bounds = false; - let mut already_collected_associated_type = false; + let mut already_collected_associated_type = None; while let Ok(Some(pallet_attr)) = helper::take_first_item_pallet_attr::(trait_item) @@ -452,23 +452,7 @@ impl ConfigDef { // // They must provide a type item that implements `TypeInfo`. (PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { - if is_event { - return Err(syn::Error::new( - pallet_attr._bracket.span.join(), - "Invalid #[pallet::include_metadata] in `type RuntimeEvent`, \ - expected type item. The associated type `RuntimeEvent` is already collected.", - )) - } - - if already_constant { - return Err(syn::Error::new( - pallet_attr._bracket.span.join(), - "Invalid #[pallet::include_metadata] in #[pallet::constant], \ - expected type item. Pallet constant's metadata is already collected.", - )) - } - - already_collected_associated_type = true; + already_collected_associated_type = Some(pallet_attr._bracket.span.join()); associated_types_metadata.push(AssociatedTypeMetadataDef::from(typ)); } (PalletAttrType::IncludeMetadata(_), _) => @@ -512,16 +496,32 @@ impl ConfigDef { } } - // Metadata of associated types is collected by default, iff the associated type - // implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound. - if !already_collected_associated_type && - enable_associated_metadata && - !is_event && !already_constant - { - if let syn::TraitItem::Type(ref ty) = trait_item { - // Collect the metadata of the associated type if it implements `TypeInfo`. - if contains_type_info_bound(ty) { - associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); + if let Some(span) = already_collected_associated_type { + // Events and constants are already propagated to the metadata + if is_event { + return Err(syn::Error::new( + span, + "Invalid #[pallet::include_metadata] in `type RuntimeEvent`, \ + expected type item. The associated type `RuntimeEvent` is already collected.", + )) + } + + if already_constant { + return Err(syn::Error::new( + span, + "Invalid #[pallet::include_metadata] in #[pallet::constant], \ + expected type item. Pallet constant's metadata is already collected.", + )) + } + } else { + // Metadata of associated types is collected by default, if the associated type + // implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound. + if enable_associated_metadata && !is_event && !already_constant { + if let syn::TraitItem::Type(ref ty) = trait_item { + // Collect the metadata of the associated type if it implements `TypeInfo`. + if contains_type_info_bound(ty) { + associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); + } } } } From fb8b2d4de1f1cfae35a501085987f41f8af621d0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 1 Oct 2024 19:17:35 +0300 Subject: [PATCH 30/46] pallet/parse: Reverse enable metadata flag to disable metadata Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/config.rs | 4 ++-- substrate/frame/support/procedural/src/pallet/parse/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index d85480731d3c..444e324844c4 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -370,7 +370,7 @@ impl ConfigDef { index: usize, item: &mut syn::Item, enable_default: bool, - enable_associated_metadata: bool, + disable_associated_metadata: bool, ) -> syn::Result { let syn::Item::Trait(item) = item else { let msg = "Invalid pallet::config, expected trait definition"; @@ -516,7 +516,7 @@ impl ConfigDef { } else { // Metadata of associated types is collected by default, if the associated type // implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound. - if enable_associated_metadata && !is_event && !already_constant { + if !disable_associated_metadata && !is_event && !already_constant { if let syn::TraitItem::Type(ref ty) = trait_item { // Collect the metadata of the associated type if it implements `TypeInfo`. if contains_type_info_bound(ty) { diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 02aa7f7843e2..8f12fe7bdc93 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -115,7 +115,7 @@ impl Def { index, item, with_default, - !without_metadata, + without_metadata, )?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; From d4e597db27fa281ae9adb42235d21179e55c33f6 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 4 Oct 2024 13:19:36 +0300 Subject: [PATCH 31/46] tests/pallet_ui: Adjust for new space in errors Signed-off-by: Alexandru Vasile --- .../test/tests/pallet_ui/config_metadata_on_constants.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr index ac27bfe89a08..427365c0f2bf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr @@ -1,5 +1,5 @@ error: Invalid #[pallet::include_metadata] in #[pallet::constant], expected type item. Pallet constant's metadata is already collected. --> tests/pallet_ui/config_metadata_on_constants.rs:26:10 | -26 | #[pallet::include_metadata] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +26 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ From a453595323655c2b24a7c46872b6a1d48fbe3095 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 4 Oct 2024 14:06:21 +0300 Subject: [PATCH 32/46] construct-ui/tests: Adjust testing to new format Signed-off-by: Alexandru Vasile --- .../deprecated_where_block.stderr | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index 59e36775d464..55b19ac1a652 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -711,6 +711,31 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0599]: the function or associated item `pallet_associated_types_metadata` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | From cf6749bad8a20d40af6f668aee6def526d6033ec Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:35:06 +0300 Subject: [PATCH 33/46] Update substrate/frame/support/procedural/src/pallet/parse/config.rs Co-authored-by: Guillaume Thiolliere --- substrate/frame/support/procedural/src/pallet/parse/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 444e324844c4..1dffd86ba4cf 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -509,8 +509,8 @@ impl ConfigDef { if already_constant { return Err(syn::Error::new( span, - "Invalid #[pallet::include_metadata] in #[pallet::constant], \ - expected type item. Pallet constant's metadata is already collected.", + "Invalid #[pallet::include_metadata]: conflict with #[pallet::constant], \ + Pallet constant already collect the metadata for the type.", )) } } else { From 54e6d2af9d0cd7077945bfb38897dad127228d0e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:35:19 +0300 Subject: [PATCH 34/46] Update substrate/frame/support/procedural/src/pallet/parse/config.rs Co-authored-by: Guillaume Thiolliere --- substrate/frame/support/procedural/src/pallet/parse/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 1dffd86ba4cf..21a7823e174c 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -501,8 +501,8 @@ impl ConfigDef { if is_event { return Err(syn::Error::new( span, - "Invalid #[pallet::include_metadata] in `type RuntimeEvent`, \ - expected type item. The associated type `RuntimeEvent` is already collected.", + "Invalid #[pallet::include_metadata] for `type RuntimeEvent`, \ + The associated type `RuntimeEvent` is already collected in the metadata.", )) } From 610bdc29cf659f7865b8c708a48085ce9b75348b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 10 Oct 2024 08:38:07 +0300 Subject: [PATCH 35/46] frame/pallet: Adjust error messages Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/config.rs | 4 ++-- .../test/tests/pallet_ui/config_metadata_on_constants.stderr | 2 +- .../test/tests/pallet_ui/config_metadata_on_events.stderr | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 21a7823e174c..f5da34814a64 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -501,7 +501,7 @@ impl ConfigDef { if is_event { return Err(syn::Error::new( span, - "Invalid #[pallet::include_metadata] for `type RuntimeEvent`, \ + "Invalid #[pallet::include_metadata] for `type RuntimeEvent`. \ The associated type `RuntimeEvent` is already collected in the metadata.", )) } @@ -509,7 +509,7 @@ impl ConfigDef { if already_constant { return Err(syn::Error::new( span, - "Invalid #[pallet::include_metadata]: conflict with #[pallet::constant], \ + "Invalid #[pallet::include_metadata]: conflict with #[pallet::constant]. \ Pallet constant already collect the metadata for the type.", )) } diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr index 427365c0f2bf..eb943158f38a 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr @@ -1,4 +1,4 @@ -error: Invalid #[pallet::include_metadata] in #[pallet::constant], expected type item. Pallet constant's metadata is already collected. +error: Invalid #[pallet::include_metadata]: conflict with #[pallet::constant]. Pallet constant already collect the metadata for the type. --> tests/pallet_ui/config_metadata_on_constants.rs:26:10 | 26 | #[pallet::include_metadata] diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr index 0c79929bca37..15132ccce04c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr @@ -1,4 +1,4 @@ -error: Invalid #[pallet::include_metadata] in `type RuntimeEvent`, expected type item. The associated type `RuntimeEvent` is already collected. +error: Invalid #[pallet::include_metadata] for `type RuntimeEvent`. The associated type `RuntimeEvent` is already collected in the metadata. --> tests/pallet_ui/config_metadata_on_events.rs:26:4 | 26 | #[pallet::include_metadata] From b18a2f90aba25780cdb026bbb88bf09c11e9ebcb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 10 Oct 2024 08:54:14 +0300 Subject: [PATCH 36/46] pallet/expand: Use associated type span for better errors Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/expand/config.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 07c48a556005..0a583f1359ba 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -112,13 +112,14 @@ pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream { let types = def.config.associated_types_metadata.iter().map(|metadata| { let ident = &metadata.ident; + let span = ident.span(); let ident_str = ident.to_string(); let cfgs = &metadata.cfg; let no_docs = vec![]; let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &metadata.doc }; - quote::quote!({ + quote::quote_spanned!(span => { #( #cfgs ) * #frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR { name: #ident_str, From 678944a58058563479b5f116ee020109535c82de Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 10 Oct 2024 08:55:08 +0300 Subject: [PATCH 37/46] pallet/parse: Use lookahead properly Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 8f12fe7bdc93..574c0bba14b7 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -578,10 +578,10 @@ impl syn::parse::Parse for ConfigValue { if lookahead.peek(keyword::with_default) { input.parse().map(ConfigValue::WithDefault) - } else if input.peek(keyword::without_metadata) { + } else if lookahead.peek(keyword::without_metadata) { input.parse().map(ConfigValue::WithoutMetadata) } else { - Err(input.error("expected `with_default` or `without_metadata`")) + Err(lookahead.error()) } } } From d43743cb0d81389e5dcbe0acbdce825b0e9e1d4b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 10 Oct 2024 13:23:41 +0300 Subject: [PATCH 38/46] tests/pallet_ui: Add include metadata for nonscale type info Signed-off-by: Alexandru Vasile --- .../config_metadata_non_type_info.rs | 42 +++++++++++++++++++ .../config_metadata_non_type_info.stderr | 14 +++++++ 2 files changed, 56 insertions(+) create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs new file mode 100644 index 000000000000..38c3870ba735 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs @@ -0,0 +1,42 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + + #[pallet::include_metadata] + type MyNonScaleTypeInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr new file mode 100644 index 000000000000..9771c6f5f15c --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `::MyNonScaleTypeInfo: TypeInfo` is not satisfied + --> tests/pallet_ui/config_metadata_non_type_info.rs:29:8 + | +29 | type MyNonScaleTypeInfo; + | ^^^^^^^^^^^^^^^^^^ the trait `TypeInfo` is not implemented for `::MyNonScaleTypeInfo` + | +note: required by a bound in `meta_type` + --> $CARGO/scale-info-2.11.3/src/lib.rs + | + | pub fn meta_type() -> MetaType + | --------- required by a bound in this function + | where + | T: ?Sized + TypeInfo + 'static, + | ^^^^^^^^ required by this bound in `meta_type` From 0928d78b145b3eedeef82c3505fb2f992a86f464 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 10 Oct 2024 13:25:22 +0300 Subject: [PATCH 39/46] frame/support: Rename #[without_metadata] -> Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/mod.rs | 32 +++++++++++-------- substrate/frame/support/src/lib.rs | 16 +++++----- .../tests/pallet_associated_types_metadata.rs | 2 +- .../tests/pallet_ui/config_duplicate_attr.rs | 2 +- .../pallet_ui/config_duplicate_attr.stderr | 4 +-- .../pallet_ui/pass/config_multiple_attr.rs | 2 +- .../pallet_ui/pass/config_without_metadata.rs | 2 +- 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 574c0bba14b7..21b433ac9195 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -109,13 +109,13 @@ impl Def { let pallet_attr: Option = helper::take_first_item_pallet_attr(item)?; match pallet_attr { - Some(PalletAttr::Config{ with_default, without_metadata, ..}) if config.is_none() => + Some(PalletAttr::Config{ with_default, without_automatic_metadata, ..}) if config.is_none() => config = Some(config::ConfigDef::try_from( &frame_system, index, item, with_default, - without_metadata, + without_automatic_metadata, )?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; @@ -549,7 +549,7 @@ mod keyword { syn::custom_keyword!(event); syn::custom_keyword!(config); syn::custom_keyword!(with_default); - syn::custom_keyword!(without_metadata); + syn::custom_keyword!(without_automatic_metadata); syn::custom_keyword!(hooks); syn::custom_keyword!(inherent); syn::custom_keyword!(error); @@ -568,8 +568,8 @@ mod keyword { enum ConfigValue { /// `#[pallet::config(with_default)]` WithDefault(keyword::with_default), - /// `#[pallet::config(without_metadata)]` - WithoutMetadata(keyword::without_metadata), + /// `#[pallet::config(without_automatic_metadata)]` + WithoutMetadata(keyword::without_automatic_metadata), } impl syn::parse::Parse for ConfigValue { @@ -578,8 +578,8 @@ impl syn::parse::Parse for ConfigValue { if lookahead.peek(keyword::with_default) { input.parse().map(ConfigValue::WithDefault) - } else if lookahead.peek(keyword::without_metadata) { - input.parse().map(ConfigValue::WithoutMetadata) + } else if lookahead.peek(keyword::without_automatic_metadata) { + input.parse().map(ConfigValue::WithoutAutomaticMetadata) } else { Err(lookahead.error()) } @@ -592,7 +592,7 @@ enum PalletAttr { Config { span: proc_macro2::Span, with_default: bool, - without_metadata: bool, + without_automatic_metadata: bool, }, Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), @@ -693,7 +693,7 @@ impl syn::parse::Parse for PalletAttr { if content.peek(syn::token::Paren) { let inside_config; - // Parse (with_default, without_metadata) attributes. + // Parse (with_default, without_automatic_metadata) attributes. let _paren = syn::parenthesized!(inside_config in content); let fields: syn::punctuated::Punctuated = @@ -703,15 +703,15 @@ impl syn::parse::Parse for PalletAttr { let frequencies = config_values.iter().fold(HashMap::new(), |mut map, val| { let string_name = match val { ConfigValue::WithDefault(_) => "with_default", - ConfigValue::WithoutMetadata(_) => "without_metadata", + ConfigValue::WithoutAutomaticMetadata(_) => "without_automatic_metadata", } .to_string(); map.entry(string_name).and_modify(|frq| *frq += 1).or_insert(1); map }); let with_default = frequencies.get("with_default").copied().unwrap_or(0) > 0; - let without_metadata = - frequencies.get("without_metadata").copied().unwrap_or(0) > 0; + let without_automatic_metadata = + frequencies.get("without_automatic_metadata").copied().unwrap_or(0) > 0; let duplicates = frequencies .into_iter() @@ -722,9 +722,13 @@ impl syn::parse::Parse for PalletAttr { return Err(syn::Error::new(span, msg)); } - Ok(PalletAttr::Config { span, with_default, without_metadata }) + Ok(PalletAttr::Config { span, with_default, without_automatic_metadata }) } else { - Ok(PalletAttr::Config { span, with_default: false, without_metadata: false }) + Ok(PalletAttr::Config { + span, + with_default: false, + without_automatic_metadata: false, + }) } } else if lookahead.peek(keyword::pallet) { Ok(PalletAttr::Pallet(content.parse::()?.span())) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 2460cf3baed5..5087b1b6e29b 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1563,17 +1563,17 @@ pub mod pallet_macros { /// * [`#[pallet::no_default]`](`no_default`) /// * [`#[pallet::no_default_bounds]`](`no_default_bounds`) /// - /// ## Optional: `without_metadata` + /// ## Optional: `without_automatic_metadata` /// /// By default, the associated types of the `Config` trait that require the `TypeInfo` or /// `Parameter` bounds are included in the metadata of the pallet. /// - /// The optional `without_metadata` argument can be used to exclude these associated types - /// from the metadata collection. + /// The optional `without_automatic_metadata` argument can be used to exclude these + /// associated types from the metadata collection. /// - /// Furthermore, the `without_metadata` argument can be used in combination with the - /// [`#[pallet::include_metadata]`](`include_metadata`) attribute to selectively include - /// only certain associated types in the metadata collection. + /// Furthermore, the `without_automatic_metadata` argument can be used in combination with + /// the [`#[pallet::include_metadata]`](`include_metadata`) attribute to selectively + /// include only certain associated types in the metadata collection. /// /// ``` /// #[frame_support::pallet] @@ -1588,7 +1588,7 @@ pub mod pallet_macros { /// #[pallet::pallet] /// pub struct Pallet(_); /// - /// #[pallet::config(with_default, without_metadata)] // <- with_default and without_metadata are optional + /// #[pallet::config(with_default, without_automatic_metadata)] // <- with_default and without_automatic_metadata are optional /// pub trait Config: frame_system::Config { /// /// The overarching event type. /// #[pallet::no_default_bounds] // Default with bounds is not supported for RuntimeEvent @@ -2014,7 +2014,7 @@ pub mod pallet_macros { /// By default all collectable associated types are included in the metadata. /// /// This attribute can be used in combination with the - /// [`#[pallet::config(without_metadata)]`](`config`). + /// [`#[pallet::config(without_automatic_metadata)]`](`config`). pub use frame_support_procedural::include_metadata; /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. diff --git a/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs index 9de5d79ad34c..a2b916f54c5e 100644 --- a/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs +++ b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs @@ -92,7 +92,7 @@ pub mod pallet3 { pub struct Pallet(_); // Associated types are not collected by default. - #[pallet::config(without_metadata)] + #[pallet::config(without_automatic_metadata)] pub trait Config: frame_system::Config { // Runtime events already propagated to the metadata. type RuntimeEvent: From> + IsType<::RuntimeEvent>; diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs index 3d7b4f87d22c..f58e11b02261 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs @@ -20,7 +20,7 @@ mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - #[pallet::config(with_default, without_metadata, without_metadata)] + #[pallet::config(with_default, without_automatic_metadata, without_automatic_metadata)] pub trait Config: frame_system::Config { #[pallet::constant] type MyGetParam2: Get; diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr index 0fdbd94dc816..46326bde0559 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr @@ -1,5 +1,5 @@ -error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_metadata. +error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata. --> tests/pallet_ui/config_duplicate_attr.rs:23:12 | -23 | #[pallet::config(with_default, without_metadata, without_metadata)] +23 | #[pallet::config(with_default, without_automatic_metadata, without_automatic_metadata)] | ^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs index 1eee25b333e4..c016c52181cf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs @@ -19,7 +19,7 @@ mod pallet { use frame_support::pallet_prelude::*; - #[pallet::config(with_default, without_metadata)] + #[pallet::config(with_default, without_automatic_metadata)] pub trait Config: frame_system::Config { #[pallet::constant] type MyGetParam2: Get; diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs index 9304b2ccc9bf..c9f5244d7345 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs @@ -19,7 +19,7 @@ mod pallet { use frame_support::pallet_prelude::*; - #[pallet::config(without_metadata)] + #[pallet::config(without_automatic_metadata)] pub trait Config: frame_system::Config { #[pallet::constant] type MyGetParam2: Get; From 8fd0180ab3326b7a852d6874a164f8dc3b5d45ed Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 10 Oct 2024 13:46:17 +0300 Subject: [PATCH 40/46] frame/support: Rename WithoutAutomaticMetadata variant Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 21b433ac9195..ccb3287f94ca 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -569,7 +569,7 @@ enum ConfigValue { /// `#[pallet::config(with_default)]` WithDefault(keyword::with_default), /// `#[pallet::config(without_automatic_metadata)]` - WithoutMetadata(keyword::without_automatic_metadata), + WithoutAutomaticMetadata(keyword::without_automatic_metadata), } impl syn::parse::Parse for ConfigValue { From ac08308bed1fad32cb775ae561d21d86919a16dc Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 11 Oct 2024 12:17:00 +0000 Subject: [PATCH 41/46] frame/support: Better error msg for invalid #[include_metadata] Signed-off-by: Alexandru Vasile --- .../support/procedural/src/pallet/parse/config.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index f5da34814a64..3b778de8c615 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -453,7 +453,7 @@ impl ConfigDef { // They must provide a type item that implements `TypeInfo`. (PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { already_collected_associated_type = Some(pallet_attr._bracket.span.join()); - associated_types_metadata.push(AssociatedTypeMetadataDef::from(typ)); + associated_types_metadata.push(AssociatedTypeMetadataDef::from(AssociatedTypeMetadataDef::from(typ))); } (PalletAttrType::IncludeMetadata(_), _) => return Err(syn::Error::new( @@ -513,6 +513,17 @@ impl ConfigDef { Pallet constant already collect the metadata for the type.", )) } + + if let syn::TraitItem::Type(ref ty) = trait_item { + if !contains_type_info_bound(ty) { + let msg = format!( + "Invalid #[pallet::include_metadata] in #[pallet::config], collected type `{}` \ + does not implement `scale::TypeInfo`", + ty.ident, + ); + return Err(syn::Error::new(span, msg)); + } + } } else { // Metadata of associated types is collected by default, if the associated type // implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound. From 1296dc28b6e4af2c2ff9823b5b97d2a61e324075 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 11 Oct 2024 12:39:17 +0000 Subject: [PATCH 42/46] pallet_ui/tests: Update error message Signed-off-by: Alexandru Vasile --- .../config_metadata_non_type_info.stderr | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr index 9771c6f5f15c..c899b88adc4c 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr @@ -1,14 +1,5 @@ -error[E0277]: the trait bound `::MyNonScaleTypeInfo: TypeInfo` is not satisfied - --> tests/pallet_ui/config_metadata_non_type_info.rs:29:8 +error: Invalid #[pallet::include_metadata] in #[pallet::config], collected type `MyNonScaleTypeInfo` does not implement `scale::TypeInfo` + --> tests/pallet_ui/config_metadata_non_type_info.rs:28:4 | -29 | type MyNonScaleTypeInfo; - | ^^^^^^^^^^^^^^^^^^ the trait `TypeInfo` is not implemented for `::MyNonScaleTypeInfo` - | -note: required by a bound in `meta_type` - --> $CARGO/scale-info-2.11.3/src/lib.rs - | - | pub fn meta_type() -> MetaType - | --------- required by a bound in this function - | where - | T: ?Sized + TypeInfo + 'static, - | ^^^^^^^^ required by this bound in `meta_type` +28 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ From b125a1e49ac8a883458c4106679c5ea8aa457692 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 15 Oct 2024 16:32:51 +0300 Subject: [PATCH 43/46] frame/support: Detect #[include_metadata] duplicates Signed-off-by: Alexandru Vasile --- .../frame/support/procedural/src/pallet/parse/config.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 3b778de8c615..c4e4bdada250 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -452,6 +452,12 @@ impl ConfigDef { // // They must provide a type item that implements `TypeInfo`. (PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { + if already_collected_associated_type.is_some() { + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Duplicate #[pallet::include_metadata] attribute not allowed.", + )); + } already_collected_associated_type = Some(pallet_attr._bracket.span.join()); associated_types_metadata.push(AssociatedTypeMetadataDef::from(AssociatedTypeMetadataDef::from(typ))); } From 39a9d4b45fb97f1d5de5f058e516dc0bb2deb374 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 15 Oct 2024 16:38:17 +0300 Subject: [PATCH 44/46] frame/support: Improve TypeInfo detection Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index c4e4bdada250..3f22402583e4 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -360,7 +360,9 @@ fn contains_type_info_bound(ty: &TraitItemType) -> bool { ty.bounds.iter().any(|bound| { let syn::TypeParamBound::Trait(bound) = bound else { return false }; - KNOWN_TYPE_INFO_BOUNDS.iter().any(|known| bound.path.is_ident(known)) + KNOWN_TYPE_INFO_BOUNDS + .iter() + .any(|known| bound.path.segments.last().map_or(false, |last| last.ident == *known)) }) } From ac92bc6739b47e0a1df909dac8033d84f2a66f68 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 15 Oct 2024 16:50:14 +0300 Subject: [PATCH 45/46] frame/support: Simplify duplicate detection logic Signed-off-by: Alexandru Vasile --- .../procedural/src/pallet/parse/mod.rs | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index ccb3287f94ca..5036f691690f 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -43,7 +43,6 @@ pub mod tests; use composite::{keyword::CompositeKeyword, CompositeDef}; use frame_support_procedural_tools::generate_access_from_frame_or_crate; use quote::ToTokens; -use std::collections::HashMap; use syn::spanned::Spanned; /// Parsed definition of a pallet. @@ -700,26 +699,29 @@ impl syn::parse::Parse for PalletAttr { inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?; let config_values = fields.iter().collect::>(); - let frequencies = config_values.iter().fold(HashMap::new(), |mut map, val| { - let string_name = match val { - ConfigValue::WithDefault(_) => "with_default", - ConfigValue::WithoutAutomaticMetadata(_) => "without_automatic_metadata", + let mut with_default = false; + let mut without_automatic_metadata = false; + for config in config_values { + match config { + ConfigValue::WithDefault(_) => { + if with_default { + return Err(syn::Error::new( + span, + "Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: with_default.", + )); + } + with_default = true; + }, + ConfigValue::WithoutAutomaticMetadata(_) => { + if without_automatic_metadata { + return Err(syn::Error::new( + span, + "Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata.", + )); + } + without_automatic_metadata = true; + }, } - .to_string(); - map.entry(string_name).and_modify(|frq| *frq += 1).or_insert(1); - map - }); - let with_default = frequencies.get("with_default").copied().unwrap_or(0) > 0; - let without_automatic_metadata = - frequencies.get("without_automatic_metadata").copied().unwrap_or(0) > 0; - - let duplicates = frequencies - .into_iter() - .filter_map(|(name, frq)| if frq > 1 { Some(name) } else { None }) - .collect::>(); - if !duplicates.is_empty() { - let msg = format!("Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: {}.", duplicates.join(", ")); - return Err(syn::Error::new(span, msg)); } Ok(PalletAttr::Config { span, with_default, without_automatic_metadata }) From e96b36d314d5dac7c3df685f81ed620aa3d1f1cd Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 15 Oct 2024 18:03:13 +0300 Subject: [PATCH 46/46] frame/support: Rename error for explicit types Signed-off-by: Alexandru Vasile --- substrate/frame/support/procedural/src/pallet/parse/config.rs | 2 +- .../test/tests/pallet_ui/config_metadata_non_type_info.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 3f22402583e4..6b6dcc802e2e 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -526,7 +526,7 @@ impl ConfigDef { if !contains_type_info_bound(ty) { let msg = format!( "Invalid #[pallet::include_metadata] in #[pallet::config], collected type `{}` \ - does not implement `scale::TypeInfo`", + does not implement `TypeInfo` or `Parameter`", ty.ident, ); return Err(syn::Error::new(span, msg)); diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr index c899b88adc4c..362e97e8bb92 100644 --- a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr @@ -1,4 +1,4 @@ -error: Invalid #[pallet::include_metadata] in #[pallet::config], collected type `MyNonScaleTypeInfo` does not implement `scale::TypeInfo` +error: Invalid #[pallet::include_metadata] in #[pallet::config], collected type `MyNonScaleTypeInfo` does not implement `TypeInfo` or `Parameter` --> tests/pallet_ui/config_metadata_non_type_info.rs:28:4 | 28 | #[pallet::include_metadata]