diff --git a/Cargo.lock b/Cargo.lock index 1002d1c894e16..c1f9ef0886c5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "11.0.0-rc6" +version = "12.0.0-rc6" dependencies = [ "parity-scale-codec", "serde", @@ -1636,6 +1636,7 @@ dependencies = [ name = "frame-support-test" version = "2.0.0-rc6" dependencies = [ + "frame-metadata", "frame-support", "parity-scale-codec", "pretty_assertions", diff --git a/frame/metadata/Cargo.toml b/frame/metadata/Cargo.toml index 2a00ecd85d120..2980eb1cf496d 100644 --- a/frame/metadata/Cargo.toml +++ b/frame/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frame-metadata" -version = "11.0.0-rc6" +version = "12.0.0-rc6" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" diff --git a/frame/metadata/src/lib.rs b/frame/metadata/src/lib.rs index c0eeb76b6f976..109f33f420191 100644 --- a/frame/metadata/src/lib.rs +++ b/frame/metadata/src/lib.rs @@ -362,8 +362,10 @@ pub enum RuntimeMetadata { V9(RuntimeMetadataDeprecated), /// Version 10 for runtime metadata. No longer used. V10(RuntimeMetadataDeprecated), - /// Version 11 for runtime metadata. - V11(RuntimeMetadataV11), + /// Version 11 for runtime metadata. No longer used. + V11(RuntimeMetadataDeprecated), + /// Version 12 for runtime metadata. + V12(RuntimeMetadataV12), } /// Enum that should fail. @@ -387,7 +389,7 @@ impl Decode for RuntimeMetadataDeprecated { /// The metadata of a runtime. #[derive(Eq, Encode, PartialEq, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, Serialize))] -pub struct RuntimeMetadataV11 { +pub struct RuntimeMetadataV12 { /// Metadata of all the modules. pub modules: DecodeDifferentArray, /// Metadata of the extrinsic. @@ -395,7 +397,7 @@ pub struct RuntimeMetadataV11 { } /// The latest version of the metadata. -pub type RuntimeMetadataLastVersion = RuntimeMetadataV11; +pub type RuntimeMetadataLastVersion = RuntimeMetadataV12; /// All metadata about an runtime module. #[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] @@ -407,6 +409,9 @@ pub struct ModuleMetadata { pub event: ODFnA, pub constants: DFnA, pub errors: DFnA, + /// Define the index of the module, this index will be used for the encoding of module event, + /// call and origin variants. + pub index: u8, } type ODFnA = Option>; @@ -420,6 +425,6 @@ impl Into for RuntimeMetadataPrefixed { impl Into for RuntimeMetadataLastVersion { fn into(self) -> RuntimeMetadataPrefixed { - RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V11(self)) + RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V12(self)) } } diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 3024c7d6d0d05..c91131005972b 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -438,6 +438,25 @@ impl Module { } } + /// Helper to migrate scheduler when the pallet origin type has changed. + pub fn migrate_origin + codec::Decode>() { + Agenda::::translate::< + Vec::Call, T::BlockNumber, OldOrigin, T::AccountId>>>, _ + >(|_, agenda| Some( + agenda + .into_iter() + .map(|schedule| schedule.map(|schedule| Scheduled { + maybe_id: schedule.maybe_id, + priority: schedule.priority, + call: schedule.call, + maybe_periodic: schedule.maybe_periodic, + origin: schedule.origin.into(), + _phantom: Default::default(), + })) + .collect::>() + )); + } + fn do_schedule( when: DispatchTime, maybe_periodic: Option>, @@ -632,6 +651,7 @@ mod tests { traits::{BlakeTwo256, IdentityLookup}, }; use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy}; + use substrate_test_utils::assert_eq_uvec; use crate as scheduler; mod logger { @@ -1161,8 +1181,6 @@ mod tests { #[test] fn migration_to_v2_works() { - use substrate_test_utils::assert_eq_uvec; - new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); @@ -1264,4 +1282,118 @@ mod tests { assert_eq!(StorageVersion::get(), Releases::V2); }); } + + #[test] + fn test_migrate_origin() { + new_test_ext().execute_with(|| { + for i in 0..3u64 { + let k = i.twox_64_concat(); + let old: Vec>> = vec![ + Some(Scheduled { + maybe_id: None, + priority: i as u8 + 10, + call: Call::Logger(logger::Call::log(96, 100)), + origin: 3u32, + maybe_periodic: None, + _phantom: Default::default(), + }), + None, + Some(Scheduled { + maybe_id: Some(b"test".to_vec()), + priority: 123, + origin: 2u32, + call: Call::Logger(logger::Call::log(69, 1000)), + maybe_periodic: Some((456u64, 10)), + _phantom: Default::default(), + }), + ]; + frame_support::migration::put_storage_value( + b"Scheduler", + b"Agenda", + &k, + old, + ); + } + + impl Into for u32 { + fn into(self) -> OriginCaller { + match self { + 3u32 => system::RawOrigin::Root.into(), + 2u32 => system::RawOrigin::None.into(), + _ => unreachable!("test make no use of it"), + } + } + } + + Scheduler::migrate_origin::(); + + assert_eq_uvec!(Agenda::::iter().collect::>(), vec![ + ( + 0, + vec![ + Some(ScheduledV2::<_, _, OriginCaller, u64> { + maybe_id: None, + priority: 10, + call: Call::Logger(logger::Call::log(96, 100)), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(logger::Call::log(69, 1000)), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ]), + ( + 1, + vec![ + Some(ScheduledV2 { + maybe_id: None, + priority: 11, + call: Call::Logger(logger::Call::log(96, 100)), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(logger::Call::log(69, 1000)), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ), + ( + 2, + vec![ + Some(ScheduledV2 { + maybe_id: None, + priority: 12, + call: Call::Logger(logger::Call::log(96, 100)), + maybe_periodic: None, + origin: system::RawOrigin::Root.into(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV2 { + maybe_id: Some(b"test".to_vec()), + priority: 123, + call: Call::Logger(logger::Call::log(69, 1000)), + maybe_periodic: Some((456u64, 10)), + origin: system::RawOrigin::None.into(), + _phantom: PhantomData::::default(), + }), + ] + ) + ]); + }); + } } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index dc1286d84e968..8eb86980a50ea 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = "0.4" serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] } -frame-metadata = { version = "11.0.0-rc6", default-features = false, path = "../metadata" } +frame-metadata = { version = "12.0.0-rc6", default-features = false, path = "../metadata" } sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } sp-io = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 867b6a72f4586..c51582fdd05a1 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -19,15 +19,86 @@ mod parse; use frame_support_procedural_tools::syn_ext as ext; use frame_support_procedural_tools::{generate_crate_access, generate_hidden_includes}; -use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection}; +use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection, ModulePart}; use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{TokenStream as TokenStream2}; use quote::quote; use syn::{Ident, Result, TypePath}; +use std::collections::HashMap; /// The fixed name of the system module. const SYSTEM_MODULE_NAME: &str = "System"; +/// The complete definition of a module with the resulting fixed index. +#[derive(Debug, Clone)] +pub struct Module { + pub name: Ident, + pub index: u8, + pub module: Ident, + pub instance: Option, + pub module_parts: Vec, +} + +impl Module { + /// Get resolved module parts + fn module_parts(&self) -> &[ModulePart] { + &self.module_parts + } + + /// Find matching parts + fn find_part(&self, name: &str) -> Option<&ModulePart> { + self.module_parts.iter().find(|part| part.name() == name) + } + + /// Return whether module contains part + fn exists_part(&self, name: &str) -> bool { + self.find_part(name).is_some() + } +} + +/// Convert from the parsed module to their final information. +/// Assign index to each modules using same rules as rust for fieldless enum. +/// I.e. implicit are assigned number incrementedly from last explicit or 0. +fn complete_modules(decl: impl Iterator) -> syn::Result> { + let mut indices = HashMap::new(); + let mut last_index: Option = None; + + decl + .map(|module| { + let final_index = match module.index { + Some(i) => i, + None => last_index.map_or(Some(0), |i| i.checked_add(1)) + .ok_or_else(|| { + let msg = "Module index doesn't fit into u8, index is 256"; + syn::Error::new(module.name.span(), msg) + })?, + }; + + last_index = Some(final_index); + + if let Some(used_module) = indices.insert(final_index, module.name.clone()) { + let msg = format!( + "Module indices are conflicting: Both modules {} and {} are at index {}", + used_module, + module.name, + final_index, + ); + let mut err = syn::Error::new(used_module.span(), &msg); + err.combine(syn::Error::new(module.name.span(), msg)); + return Err(err); + } + + Ok(Module { + name: module.name, + index: final_index, + module: module.module, + instance: module.instance, + module_parts: module.module_parts, + }) + }) + .collect() +} + pub fn construct_runtime(input: TokenStream) -> TokenStream { let definition = syn::parse_macro_input!(input as RuntimeDefinition); construct_runtime_parsed(definition) @@ -52,19 +123,16 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result>(); - - // Assert we have system module declared - let system_module = match find_system_module(modules.iter()) { - Some(sm) => sm, - None => { - return Err(syn::Error::new( - modules_token.span, - "`System` module declaration is missing. \ - Please add this line: `System: frame_system::{Module, Call, Storage, Config, Event},`", - )) - } - }; + let modules = complete_modules(modules.into_iter())?; + + let system_module = modules.iter() + .find(|decl| decl.name == SYSTEM_MODULE_NAME) + .ok_or_else(|| syn::Error::new( + modules_token.span, + "`System` module declaration is missing. \ + Please add this line: `System: frame_system::{Module, Call, Storage, Config, Event},`", + ))?; + let hidden_crate_name = "construct_runtime"; let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support"); @@ -79,7 +147,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result Result( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations @@ -154,7 +222,7 @@ fn decl_validate_unsigned<'a>( fn decl_outer_inherent<'a>( block: &'a syn::TypePath, unchecked_extrinsic: &'a syn::TypePath, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations.filter_map(|module_declaration| { @@ -178,7 +246,7 @@ fn decl_outer_inherent<'a>( fn decl_outer_config<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations @@ -216,7 +284,7 @@ fn decl_outer_config<'a>( fn decl_runtime_metadata<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, extrinsic: &TypePath, ) -> TokenStream2 { @@ -240,7 +308,12 @@ fn decl_runtime_metadata<'a>( .as_ref() .map(|name| quote!(<#name>)) .into_iter(); - quote!(#module::Module #(#instance)* as #name with #(#filtered_names)* ,) + + let index = module_declaration.index; + + quote!( + #module::Module #(#instance)* as #name { index #index } with #(#filtered_names)*, + ) }); quote!( #scrate::impl_runtime_metadata!{ @@ -252,7 +325,7 @@ fn decl_runtime_metadata<'a>( fn decl_outer_dispatch<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> TokenStream2 { let modules_tokens = module_declarations @@ -260,8 +333,10 @@ fn decl_outer_dispatch<'a>( .map(|module_declaration| { let module = &module_declaration.module; let name = &module_declaration.name; - quote!(#module::#name) + let index = module_declaration.index.to_string(); + quote!(#[codec(index = #index)] #module::#name) }); + quote!( #scrate::impl_outer_dispatch! { pub enum Call for #runtime where origin: Origin { @@ -273,12 +348,12 @@ fn decl_outer_dispatch<'a>( fn decl_outer_origin<'a>( runtime_name: &'a Ident, - module_declarations: impl Iterator, - system_name: &'a Ident, + modules_except_system: impl Iterator, + system_module: &'a Module, scrate: &'a TokenStream2, ) -> syn::Result { let mut modules_tokens = TokenStream2::new(); - for module_declaration in module_declarations { + for module_declaration in modules_except_system { match module_declaration.find_part("Origin") { Some(module_entry) => { let module = &module_declaration.module; @@ -292,16 +367,23 @@ fn decl_outer_origin<'a>( ); return Err(syn::Error::new(module_declaration.name.span(), msg)); } - let tokens = quote!(#module #instance #generics ,); + let index = module_declaration.index.to_string(); + let tokens = quote!(#[codec(index = #index)] #module #instance #generics,); modules_tokens.extend(tokens); } None => {} } } + let system_name = &system_module.module; + let system_index = system_module.index.to_string(); + Ok(quote!( #scrate::impl_outer_origin! { - pub enum Origin for #runtime_name where system = #system_name { + pub enum Origin for #runtime_name where + system = #system_name, + system_index = #system_index + { #modules_tokens } } @@ -310,7 +392,7 @@ fn decl_outer_origin<'a>( fn decl_outer_event<'a>( runtime_name: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, scrate: &'a TokenStream2, ) -> syn::Result { let mut modules_tokens = TokenStream2::new(); @@ -328,7 +410,9 @@ fn decl_outer_event<'a>( ); return Err(syn::Error::new(module_declaration.name.span(), msg)); } - let tokens = quote!(#module #instance #generics ,); + + let index = module_declaration.index.to_string(); + let tokens = quote!(#[codec(index = #index)] #module #instance #generics,); modules_tokens.extend(tokens); } None => {} @@ -346,7 +430,7 @@ fn decl_outer_event<'a>( fn decl_all_modules<'a>( runtime: &'a Ident, - module_declarations: impl Iterator, + module_declarations: impl Iterator, ) -> TokenStream2 { let mut types = TokenStream2::new(); let mut names = Vec::new(); @@ -379,13 +463,14 @@ fn decl_all_modules<'a>( } fn decl_pallet_runtime_setup( - module_declarations: &[ModuleDeclaration], + module_declarations: &[Module], scrate: &TokenStream2, ) -> TokenStream2 { let names = module_declarations.iter().map(|d| &d.name); let names2 = module_declarations.iter().map(|d| &d.name); let name_strings = module_declarations.iter().map(|d| d.name.to_string()); - let indices = 0..module_declarations.len(); + let indices = module_declarations.iter() + .map(|module| module.index as usize); quote!( /// Provides an implementation of `PalletInfo` to provide information @@ -418,14 +503,6 @@ fn decl_pallet_runtime_setup( ) } -fn find_system_module<'a>( - mut module_declarations: impl Iterator, -) -> Option<&'a Ident> { - module_declarations - .find(|decl| decl.name == SYSTEM_MODULE_NAME) - .map(|decl| &decl.module) -} - fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { quote!( #[cfg(test)] diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index c8481480baac5..4a45044d67f25 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -149,9 +149,11 @@ impl Parse for WhereDefinition { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ModuleDeclaration { pub name: Ident, + /// Optional fixed index (e.g. `MyPallet ... = 3,`) + pub index: Option, pub module: Ident, pub instance: Option, pub module_parts: Vec, @@ -175,32 +177,27 @@ impl Parse for ModuleDeclaration { let _: Token![::] = input.parse()?; let module_parts = parse_module_parts(input)?; + let index = if input.peek(Token![=]) { + input.parse::()?; + let index = input.parse::()?; + let index = index.base10_parse::()?; + Some(index) + } else { + None + }; + let parsed = Self { name, module, instance, module_parts, + index, }; Ok(parsed) } } -impl ModuleDeclaration { - /// Get resolved module parts - pub fn module_parts(&self) -> &[ModulePart] { - &self.module_parts - } - - pub fn find_part(&self, name: &str) -> Option<&ModulePart> { - self.module_parts.iter().find(|part| part.name() == name) - } - - pub fn exists_part(&self, name: &str) -> bool { - self.find_part(name).is_some() - } -} - /// Parse [`ModulePart`]'s from a braces enclosed list that is split by commas, e.g. /// /// `{ Call, Event }` diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 060882d1123bf..bf87bd552fd06 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -252,13 +252,13 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// NodeBlock = runtime::Block, /// UncheckedExtrinsic = UncheckedExtrinsic /// { -/// System: system::{Module, Call, Event, Config}, -/// Test: test::{Module, Call}, -/// Test2: test_with_long_module::{Module}, +/// System: system::{Module, Call, Event, Config} = 0, +/// Test: test::{Module, Call} = 1, +/// Test2: test_with_long_module::{Module, Event}, /// /// // Module with instances /// Test3_Instance1: test3::::{Module, Call, Storage, Event, Config, Origin}, -/// Test3_DefaultInstance: test3::{Module, Call, Storage, Event, Config, Origin}, +/// Test3_DefaultInstance: test3::{Module, Call, Storage, Event, Config, Origin} = 4, /// } /// ) /// ``` @@ -279,6 +279,18 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// - `Inherent` - If the module provides/can check inherents. /// - `ValidateUnsigned` - If the module validates unsigned extrinsics. /// +/// `= $n` is an optional part allowing to define at which index the module variants in +/// `OriginCaller`, `Call` and `Event` are encoded, and to define the ModuleToIndex value. +/// +/// if `= $n` is not given, then index is resolved same as fieldless enum in Rust +/// (i.e. incrementedly from previous index): +/// ```nocompile +/// module1 .. = 2, +/// module2 .., // Here module2 is given index 3 +/// module3 .. = 0, +/// module4 .., // Here module4 is given index 1 +/// ``` +/// /// # Note /// /// The population of the genesis storage depends on the order of modules. So, if one of your diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index ca0a78d730b7c..02e03ec6e6d6d 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -1911,7 +1911,7 @@ macro_rules! impl_outer_dispatch { $(#[$attr:meta])* pub enum $call_type:ident for $runtime:ident where origin: $origin:ty { $( - $module:ident::$camelcase:ident, + $( #[codec(index = $index:tt)] )? $module:ident::$camelcase:ident, )* } ) => { @@ -1924,6 +1924,7 @@ macro_rules! impl_outer_dispatch { )] pub enum $call_type { $( + $( #[codec(index = $index)] )? $camelcase ( $crate::dispatch::CallableCallFor<$camelcase, $runtime> ) ,)* } diff --git a/frame/support/src/event.rs b/frame/support/src/event.rs index 1184b379f4446..0f889f97f40a0 100644 --- a/frame/support/src/event.rs +++ b/frame/support/src/event.rs @@ -346,7 +346,7 @@ macro_rules! impl_outer_event { $name; $runtime; Modules { $( $rest_events )* }; - ; + {}; ); }; // Generic + Instance @@ -355,17 +355,17 @@ macro_rules! impl_outer_event { $name:ident; $runtime:ident; Modules { - $module:ident $instance:ident, + $( #[codec(index = $index:tt)] )? $module:ident $instance:ident, $( $rest_event_generic_instance:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + { $( $parsed:tt )* }; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; Modules { $( $rest_event_generic_instance )* }; - $( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event<$runtime>{ $instance },; + { $( $parsed )* $module::Event<$runtime>{ $instance } index { $( $index )? }, }; ); }; // Instance @@ -374,17 +374,17 @@ macro_rules! impl_outer_event { $name:ident; $runtime:ident; Modules { - $module:ident $instance:ident, + $( #[codec(index = $index:tt)] )? $module:ident $instance:ident, $( $rest_event_instance:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + { $( $parsed:tt )* }; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; Modules { $( $rest_event_instance )* }; - $( $module_name::Event $( <$generic_param> )* $( { $generic_instance } )?, )* $module::Event { $instance },; + { $( $parsed )* $module::Event { $instance } index { $( $index )? }, }; ); }; // Generic @@ -393,17 +393,17 @@ macro_rules! impl_outer_event { $name:ident; $runtime:ident; Modules { - $module:ident, + $( #[codec(index = $index:tt)] )? $module:ident, $( $rest_event_generic:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + { $( $parsed:tt )* }; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; Modules { $( $rest_event_generic )* }; - $( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event<$runtime>,; + { $( $parsed )* $module::Event<$runtime> index { $( $index )? }, }; ); }; // No Generic and no Instance @@ -412,17 +412,17 @@ macro_rules! impl_outer_event { $name:ident; $runtime:ident; Modules { - $module:ident, + $( #[codec(index = $index:tt)] )? $module:ident, $( $rest_event_no_generic_no_instance:tt )* }; - $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + { $( $parsed:tt )* }; ) => { $crate::impl_outer_event!( $( #[$attr] )*; $name; $runtime; Modules { $( $rest_event_no_generic_no_instance )* }; - $( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event,; + { $( $parsed )* $module::Event index { $( $index )? }, }; ); }; @@ -432,7 +432,14 @@ macro_rules! impl_outer_event { $name:ident; $runtime:ident; Modules {}; - $( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*; + { + $( + $module_name:ident::Event + $( <$generic_param:ident> )? + $( { $generic_instance:ident } )? + index { $( $index:tt )? }, + )* + }; ) => { $crate::paste::item! { #[derive( @@ -445,6 +452,7 @@ macro_rules! impl_outer_event { #[allow(non_camel_case_types)] pub enum $name { $( + $( #[codec(index = $index)] )? [< $module_name $(_ $generic_instance )? >]( $module_name::Event < $( $generic_param )? $(, $module_name::$generic_instance )? > ), @@ -697,7 +705,7 @@ mod tests { pub enum TestEventSystemRenamed for TestRuntime2 { system_renamed, event_module, - event_module2, + #[codec(index = "5")] event_module2, event_module3, } } @@ -796,4 +804,22 @@ mod tests { fn outer_event_metadata() { assert_eq!(EXPECTED_METADATA, TestRuntime::outer_event_metadata()); } + + #[test] + fn test_codec() { + let runtime_1_event_module_2 = TestEvent::event_module2( + event_module2::Event::::TestEvent(3) + ); + assert_eq!(runtime_1_event_module_2.encode()[0], 2); + + let runtime_2_event_module_2 = TestEventSystemRenamed::event_module2( + event_module2::Event::::TestEvent(3) + ); + assert_eq!(runtime_2_event_module_2.encode()[0], 5); + + let runtime_2_event_module_3 = TestEventSystemRenamed::event_module3( + event_module3::Event::HiEvent + ); + assert_eq!(runtime_2_event_module_3.encode()[0], 3); + } } diff --git a/frame/support/src/metadata.rs b/frame/support/src/metadata.rs index 8d3b5fb527af7..9ae1d6ce663d5 100644 --- a/frame/support/src/metadata.rs +++ b/frame/support/src/metadata.rs @@ -51,9 +51,9 @@ pub use frame_metadata::{ /// struct Runtime; /// frame_support::impl_runtime_metadata! { /// for Runtime with modules where Extrinsic = UncheckedExtrinsic -/// module0::Module as Module0 with, -/// module1::Module as Module1 with, -/// module2::Module as Module2 with Storage, +/// module0::Module as Module0 { index 0 } with, +/// module1::Module as Module1 { index 1 } with, +/// module2::Module as Module2 { index 2 } with Storage, /// }; /// ``` /// @@ -91,13 +91,17 @@ macro_rules! __runtime_modules_to_metadata { ( $runtime: ident; $( $metadata:expr ),*; - $mod:ident::$module:ident $( < $instance:ident > )? as $name:ident $(with)+ $($kw:ident)*, + $mod:ident::$module:ident $( < $instance:ident > )? as $name:ident + { index $index:tt } + $(with)+ $($kw:ident)* + , $( $rest:tt )* ) => { $crate::__runtime_modules_to_metadata!( $runtime; $( $metadata, )* $crate::metadata::ModuleMetadata { name: $crate::metadata::DecodeDifferent::Encode(stringify!($name)), + index: $index, storage: $crate::__runtime_modules_to_metadata_calls_storage!( $mod, $module $( <$instance> )?, $runtime, $(with $kw)* ), @@ -449,9 +453,9 @@ mod tests { impl_runtime_metadata!( for TestRuntime with modules where Extrinsic = TestExtrinsic - system::Module as System with Event, - event_module::Module as Module with Event Call, - event_module2::Module as Module2 with Event Storage Call, + system::Module as System { index 0 } with Event, + event_module::Module as Module { index 1 } with Event Call, + event_module2::Module as Module2 { index 2 } with Event Storage Call, ); struct ConstantBlockNumberByteGetter; @@ -481,6 +485,7 @@ mod tests { modules: DecodeDifferent::Encode(&[ ModuleMetadata { name: DecodeDifferent::Encode("System"), + index: 0, storage: None, calls: None, event: Some(DecodeDifferent::Encode( @@ -524,6 +529,7 @@ mod tests { }, ModuleMetadata { name: DecodeDifferent::Encode("Module"), + index: 1, storage: None, calls: Some( DecodeDifferent::Encode(FnEncode(|| &[ @@ -559,6 +565,7 @@ mod tests { }, ModuleMetadata { name: DecodeDifferent::Encode("Module2"), + index: 2, storage: Some(DecodeDifferent::Encode( FnEncode(|| StorageMetadata { prefix: DecodeDifferent::Encode("TestStorage"), diff --git a/frame/support/src/origin.rs b/frame/support/src/origin.rs index df75f8dc65645..e4052337a0141 100644 --- a/frame/support/src/origin.rs +++ b/frame/support/src/origin.rs @@ -41,7 +41,10 @@ macro_rules! impl_outer_origin { ( $(#[$attr:meta])* - pub enum $name:ident for $runtime:ident where system = $system:ident { + pub enum $name:ident for $runtime:ident where + system = $system:ident + $(, system_index = $system_index:tt)? + { $( $rest_with_system:tt )* } ) => { @@ -52,6 +55,7 @@ macro_rules! impl_outer_origin { [< $name Caller >]; $runtime; $system; + system_index { $( $system_index )? }; Modules { $( $rest_with_system )* }; ); } @@ -64,8 +68,9 @@ macro_rules! impl_outer_origin { $caller_name:ident; $runtime:ident; $system:ident; + system_index { $( $system_index:tt )? }; Modules { - $module:ident $instance:ident + $( #[codec(index = $index:tt)] )? $module:ident $instance:ident $(, $( $rest_module:tt )* )? }; $( $parsed:tt )* @@ -76,8 +81,9 @@ macro_rules! impl_outer_origin { $caller_name; $runtime; $system; + system_index { $( $system_index )? }; Modules { $( $( $rest_module )* )? }; - $( $parsed )* $module <$runtime> { $instance }, + $( $parsed )* $module <$runtime> { $instance } index { $( $index )? }, ); }; @@ -88,8 +94,9 @@ macro_rules! impl_outer_origin { $caller_name:ident; $runtime:ident; $system:ident; + system_index { $( $system_index:tt )? }; Modules { - $module:ident $instance:ident + $( #[codec(index = $index:tt )] )? $module:ident $instance:ident $(, $rest_module:tt )* }; $( $parsed:tt )* @@ -100,8 +107,9 @@ macro_rules! impl_outer_origin { $caller_name; $runtime; $system; + system_index { $( $system_index )? }; Modules { $( $rest_module )* }; - $( $parsed )* $module { $instance }, + $( $parsed )* $module { $instance } index { $( $index )? }, ); }; @@ -112,8 +120,9 @@ macro_rules! impl_outer_origin { $caller_name:ident; $runtime:ident; $system:ident; + system_index { $( $system_index:tt )? }; Modules { - $module:ident + $( #[codec(index = $index:tt )] )? $module:ident $(, $( $rest_module:tt )* )? }; $( $parsed:tt )* @@ -124,8 +133,9 @@ macro_rules! impl_outer_origin { $caller_name; $runtime; $system; + system_index { $( $system_index )? }; Modules { $( $( $rest_module )* )? }; - $( $parsed )* $module <$runtime>, + $( $parsed )* $module <$runtime> index { $( $index )? }, ); }; @@ -136,8 +146,9 @@ macro_rules! impl_outer_origin { $caller_name:ident; $runtime:ident; $system:ident; + system_index { $( $system_index:tt )? }; Modules { - $module:ident + $( #[codec(index = $index:tt )] )? $module:ident $(, $( $rest_module:tt )* )? }; $( $parsed:tt )* @@ -148,8 +159,9 @@ macro_rules! impl_outer_origin { $caller_name; $runtime; $system; + system_index { $( $system_index )? }; Modules { $( $( $rest_module )* )? }; - $( $parsed )* $module, + $( $parsed )* $module index { $( $index )? }, ); }; @@ -160,8 +172,14 @@ macro_rules! impl_outer_origin { $caller_name:ident; $runtime:ident; $system:ident; + system_index { $( $system_index:tt )? }; Modules { }; - $( $module:ident $( < $generic:ident > )? $( { $generic_instance:ident } )? ,)* + $( + $module:ident + $( < $generic:ident > )? + $( { $generic_instance:ident } )? + index { $( $index:tt )? }, + )* ) => { // WARNING: All instance must hold the filter `frame_system::Trait::BaseCallFilter`, except // when caller is system Root. One can use `OriginTrait::reset_filter` to do so. @@ -233,8 +251,10 @@ macro_rules! impl_outer_origin { $(#[$attr])* #[allow(non_camel_case_types)] pub enum $caller_name { + $( #[codec(index = $system_index)] )? system($system::Origin<$runtime>), $( + $( #[codec(index = $index)] )? [< $module $( _ $generic_instance )? >] ($module::Origin < $( $generic, )? $( $module::$generic_instance )? > ), )* @@ -442,6 +462,13 @@ mod tests { pub enum OriginEmpty for TestRuntime where system = frame_system {} ); + impl_outer_origin!( + pub enum OriginIndices for TestRuntime where system = frame_system, system_index = "11" { + origin_with_generic, + #[codec(index = "10")] origin_without_generic, + } + ); + #[test] fn test_default_filter() { assert_eq!(OriginWithSystem::root().filter_call(&0), true); @@ -472,4 +499,20 @@ mod tests { assert_eq!(origin.filter_call(&0), true); assert_eq!(origin.filter_call(&1), false); } + + #[test] + fn test_codec() { + use codec::Encode; + assert_eq!(OriginIndices::root().caller.encode()[0], 11); + let without_generic_variant = OriginIndicesCaller::origin_without_generic( + origin_without_generic::Origin + ); + assert_eq!(without_generic_variant.encode()[0], 10); + + assert_eq!(OriginWithoutSystem::root().caller.encode()[0], 0); + let without_generic_variant = OriginWithoutSystemCaller::origin_without_generic( + origin_without_generic::Origin + ); + assert_eq!(without_generic_variant.encode()[0], 1); + } } diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index 7c839e4462ad1..e516bf8a65f6a 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -24,6 +24,7 @@ sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../../pri trybuild = "1.0.33" pretty_assertions = "0.6.1" rustversion = "1.0.0" +frame-metadata = { version = "12.0.0-rc6", default-features = false, path = "../../metadata" } [features] default = ["std"] diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index 5596943031148..9a17e44dbef4c 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -50,6 +50,17 @@ mod module1 { } } + #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode)] + pub struct Origin(pub core::marker::PhantomData::<(T, I)>); + + frame_support::decl_event! { + pub enum Event where + ::AccountId + { + A(AccountId), + } + } + frame_support::decl_error! { pub enum Error for Module, I: Instance> { Something @@ -81,6 +92,15 @@ mod module2 { } } + #[derive(Clone, PartialEq, Eq, Debug, codec::Encode, codec::Decode)] + pub struct Origin; + + frame_support::decl_event! { + pub enum Event { + A, + } + } + frame_support::decl_error! { pub enum Error for Module { Something @@ -92,8 +112,7 @@ mod module2 { } } -impl module1::Trait for Runtime {} -impl module1::Trait for Runtime {} +impl module1::Trait for Runtime {} impl module2::Trait for Runtime {} pub type Signature = sr25519::Signature; @@ -118,10 +137,17 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: system::{Module, Call, Event}, - Module1_1: module1::::{Module, Call, Storage}, - Module2: module2::{Module, Call, Storage}, - Module1_2: module1::::{Module, Call, Storage}, + System: system::{Module, Call, Event, Origin} = 30, + Module1_1: module1::::{Module, Call, Storage, Event, Origin}, + Module2: module2::{Module, Call, Storage, Event, Origin}, + Module1_2: module1::::{Module, Call, Storage, Event, Origin}, + Module1_3: module1::::{Module, Storage} = 6, + Module1_4: module1::::{Module, Call} = 3, + Module1_5: module1::::{Module, Event}, + Module1_6: module1::::{Module, Call, Storage, Event, Origin} = 1, + Module1_7: module1::::{Module, Call, Storage, Event, Origin}, + Module1_8: module1::::{Module, Call, Storage, Event, Origin} = 12, + Module1_9: module1::::{Module, Call, Storage, Event, Origin}, } ); @@ -130,27 +156,47 @@ pub type Block = generic::Block; pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; #[test] -fn check_module1_1_error_type() { +fn check_modules_error_type() { assert_eq!( Module1_1::fail(system::Origin::::Root.into()), - Err(DispatchError::Module { index: 1, error: 0, message: Some("Something") }), + Err(DispatchError::Module { index: 31, error: 0, message: Some("Something") }), + ); + assert_eq!( + Module2::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 32, error: 0, message: Some("Something") }), ); -} - -#[test] -fn check_module1_2_error_type() { assert_eq!( Module1_2::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 33, error: 0, message: Some("Something") }), + ); + assert_eq!( + Module1_3::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 6, error: 0, message: Some("Something") }), + ); + assert_eq!( + Module1_4::fail(system::Origin::::Root.into()), Err(DispatchError::Module { index: 3, error: 0, message: Some("Something") }), ); -} - -#[test] -fn check_module2_error_type() { assert_eq!( - Module2::fail(system::Origin::::Root.into()), + Module1_5::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 4, error: 0, message: Some("Something") }), + ); + assert_eq!( + Module1_6::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 1, error: 0, message: Some("Something") }), + ); + assert_eq!( + Module1_7::fail(system::Origin::::Root.into()), Err(DispatchError::Module { index: 2, error: 0, message: Some("Something") }), ); + assert_eq!( + Module1_8::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 12, error: 0, message: Some("Something") }), + ); + assert_eq!( + Module1_9::fail(system::Origin::::Root.into()), + Err(DispatchError::Module { index: 13, error: 0, message: Some("Something") }), + ); } #[test] @@ -159,14 +205,340 @@ fn integrity_test_works() { assert_eq!(INTEGRITY_TEST_EXEC.with(|i| *i.borrow()), 1); } +#[test] +fn origin_codec() { + use codec::Encode; + + let origin = OriginCaller::system(system::RawOrigin::None); + assert_eq!(origin.encode()[0], 30); + + let origin = OriginCaller::module1_Instance1(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 31); + + let origin = OriginCaller::module2(module2::Origin); + assert_eq!(origin.encode()[0], 32); + + let origin = OriginCaller::module1_Instance2(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 33); + + let origin = OriginCaller::module1_Instance6(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 1); + + let origin = OriginCaller::module1_Instance7(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 2); + + let origin = OriginCaller::module1_Instance8(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 12); + + let origin = OriginCaller::module1_Instance9(module1::Origin(Default::default())); + assert_eq!(origin.encode()[0], 13); +} + +#[test] +fn event_codec() { + use codec::Encode; + + let event = system::Event::::ExtrinsicSuccess; + assert_eq!(Event::from(event).encode()[0], 30); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 31); + + let event = module2::Event::A; + assert_eq!(Event::from(event).encode()[0], 32); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 33); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 4); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 1); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 2); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 12); + + let event = module1::Event::::A(Default::default()); + assert_eq!(Event::from(event).encode()[0], 13); +} + +#[test] +fn call_codec() { + use codec::Encode; + assert_eq!(Call::System(system::Call::noop()).encode()[0], 30); + assert_eq!(Call::Module1_1(module1::Call::fail()).encode()[0], 31); + assert_eq!(Call::Module2(module2::Call::fail()).encode()[0], 32); + assert_eq!(Call::Module1_2(module1::Call::fail()).encode()[0], 33); + assert_eq!(Call::Module1_4(module1::Call::fail()).encode()[0], 3); + assert_eq!(Call::Module1_6(module1::Call::fail()).encode()[0], 1); + assert_eq!(Call::Module1_7(module1::Call::fail()).encode()[0], 2); + assert_eq!(Call::Module1_8(module1::Call::fail()).encode()[0], 12); + assert_eq!(Call::Module1_9(module1::Call::fail()).encode()[0], 13); +} + +#[test] +fn test_metadata() { + use frame_metadata::*; + let expected_metadata: RuntimeMetadataLastVersion = RuntimeMetadataLastVersion { + modules: DecodeDifferent::Encode(&[ + ModuleMetadata { + name: DecodeDifferent::Encode("System"), + storage: None, + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("noop"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[ + EventMetadata { + name: DecodeDifferent::Encode("ExtrinsicSuccess"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }, + EventMetadata { + name: DecodeDifferent::Encode("ExtrinsicFailed"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }, + EventMetadata { + name: DecodeDifferent::Encode("Ignore"), + arguments: DecodeDifferent::Encode(&["BlockNumber"]), + documentation: DecodeDifferent::Encode(&[]), + }, + ]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 30, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_1"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance1Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[ + FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }, + ]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 31, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module2"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[ + FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }, + ]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[ + EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }, + ]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 32, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_2"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance2Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 33, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_3"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance3Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: None, + event: None, + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 6, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_4"), + storage: None, + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: None, + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 3, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_5"), + storage: None, + calls: None, + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 4, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_6"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance6Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 1, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_7"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance7Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 2, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_8"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance8Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 12, + }, + ModuleMetadata { + name: DecodeDifferent::Encode("Module1_9"), + storage: Some(DecodeDifferent::Encode(FnEncode(|| StorageMetadata { + prefix: DecodeDifferent::Encode("Instance9Module"), + entries: DecodeDifferent::Encode(&[]), + }))), + calls: Some(DecodeDifferent::Encode(FnEncode(|| &[FunctionMetadata { + name: DecodeDifferent::Encode("fail"), + arguments: DecodeDifferent::Encode(&[]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + event: Some(DecodeDifferent::Encode(FnEncode(|| &[EventMetadata { + name: DecodeDifferent::Encode("A"), + arguments: DecodeDifferent::Encode(&["AccountId"]), + documentation: DecodeDifferent::Encode(&[]), + }]))), + constants: DecodeDifferent::Encode(FnEncode(|| &[])), + errors: DecodeDifferent::Encode(FnEncode(|| &[])), + index: 13, + }, + ]), + extrinsic: ExtrinsicMetadata { + version: 4, + signed_extensions: vec![DecodeDifferent::Encode("UnitSignedExtension")], + }, + }; + pretty_assertions::assert_eq!(Runtime::metadata().1, RuntimeMetadata::V12(expected_metadata)); +} + #[test] fn pallet_in_runtime_is_correct() { - assert_eq!(PalletInfo::index::().unwrap(), 0); + assert_eq!(PalletInfo::index::().unwrap(), 30); assert_eq!(PalletInfo::name::().unwrap(), "System"); - assert_eq!(PalletInfo::index::().unwrap(), 3); - assert_eq!(PalletInfo::name::().unwrap(), "Module1_2"); + assert_eq!(PalletInfo::index::().unwrap(), 31); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_1"); - assert_eq!(PalletInfo::index::().unwrap(), 2); + assert_eq!(PalletInfo::index::().unwrap(), 32); assert_eq!(PalletInfo::name::().unwrap(), "Module2"); + + assert_eq!(PalletInfo::index::().unwrap(), 33); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_2"); + + assert_eq!(PalletInfo::index::().unwrap(), 6); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_3"); + + assert_eq!(PalletInfo::index::().unwrap(), 3); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_4"); + + assert_eq!(PalletInfo::index::().unwrap(), 4); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_5"); + + assert_eq!(PalletInfo::index::().unwrap(), 1); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_6"); + + assert_eq!(PalletInfo::index::().unwrap(), 2); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_7"); + + assert_eq!(PalletInfo::index::().unwrap(), 12); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_8"); + + assert_eq!(PalletInfo::index::().unwrap(), 13); + assert_eq!(PalletInfo::name::().unwrap(), "Module1_9"); } diff --git a/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs b/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs new file mode 100644 index 0000000000000..a48b4bd097039 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/conflicting_index.rs @@ -0,0 +1,14 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + UncheckedExtrinsic = UncheckedExtrinsic, + Block = Block, + NodeBlock = Block, + { + System: system::{}, + Pallet1: pallet1::{} = 0, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr b/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr new file mode 100644 index 0000000000000..65368666c88fe --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/conflicting_index.stderr @@ -0,0 +1,11 @@ +error: Module indices are conflicting: Both modules System and Pallet1 are at index 0 + --> $DIR/conflicting_index.rs:9:3 + | +9 | System: system::{}, + | ^^^^^^ + +error: Module indices are conflicting: Both modules System and Pallet1 are at index 0 + --> $DIR/conflicting_index.rs:10:3 + | +10 | Pallet1: pallet1::{} = 0, + | ^^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs b/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs new file mode 100644 index 0000000000000..c949cb41a23fa --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.rs @@ -0,0 +1,16 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + UncheckedExtrinsic = UncheckedExtrinsic, + Block = Block, + NodeBlock = Block, + { + System: system::{} = 5, + Pallet1: pallet1::{} = 3, + Pallet2: pallet2::{}, + Pallet3: pallet3::{}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr b/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr new file mode 100644 index 0000000000000..b792ff5d2a541 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/conflicting_index_2.stderr @@ -0,0 +1,11 @@ +error: Module indices are conflicting: Both modules System and Pallet3 are at index 5 + --> $DIR/conflicting_index_2.rs:9:3 + | +9 | System: system::{} = 5, + | ^^^^^^ + +error: Module indices are conflicting: Both modules System and Pallet3 are at index 5 + --> $DIR/conflicting_index_2.rs:12:3 + | +12 | Pallet3: pallet3::{}, + | ^^^^^^^ diff --git a/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs b/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs new file mode 100644 index 0000000000000..4c8331ae442c8 --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.rs @@ -0,0 +1,14 @@ +use frame_support::construct_runtime; + +construct_runtime! { + pub enum Runtime where + UncheckedExtrinsic = UncheckedExtrinsic, + Block = Block, + NodeBlock = Block, + { + System: system::{} = 255, + Pallet256: pallet256::{}, + } +} + +fn main() {} diff --git a/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr b/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr new file mode 100644 index 0000000000000..c0ef5c8e60b9e --- /dev/null +++ b/frame/support/test/tests/construct_runtime_ui/more_than_256_modules.stderr @@ -0,0 +1,5 @@ +error: Module index doesn't fit into u8, index is 256 + --> $DIR/more_than_256_modules.rs:10:3 + | +10 | Pallet256: pallet256::{}, + | ^^^^^^^^^ diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index 90ce05199e16d..a7d4d43c341a9 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -31,7 +31,10 @@ pub trait Trait: 'static + Eq + Clone { } frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::Origin, system=self { + #[weight = 0] + fn noop(origin) {} + } } impl Module {