Skip to content

Commit 262510b

Browse files
gui1117shawntabrizikianenigmaascjonesbkchr
authored
Add pallet attribute macro to declare pallets (#6877)
* rename system Config to system Trait. command used: ``` find frame/ bin/ test-utils/ utils/ -name *.rs -exec sed -i 's/system::Trait>::/system::Config>::/g' {} \; find frame/ bin/ test-utils/ utils/ -name *.rs -exec sed -i 's/impl frame_system::Trait for /impl frame_system::Config for /g' {} \; find frame/ bin/ test-utils/ utils/ -name *.rs -exec sed -i 's/impl system::Trait for /impl system::Config for /g' {} \; ``` plus some manual ones especially for frame-support tests and frame-system * make construct_runtime handle Pallet and Module pallets can now be implemented on struct named Pallet or Module, both definition are valid. This is because next macro will generate only Pallet placeholder. * introduce pallet attribute macro currently just with tests, frame_system and other example hasn't been upgraded * allow to print some upgrade helper from decl_storage * Improved error msg, typo. Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Improved error msg, typo. Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Improved error message on unexpected attributes + ui test * add test for transactional * various typo * some tips when spans are lost * allow pallet to depend on other pallet instances * make event type metadata consistent with call and constant * error messages * ignore doc example * fix pallet upgrade template * fixup * fix doc * fix indentation * Apply suggestions code formatting Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * some renames + fix compilation * remove unsupported genesis config type alias * merge fixup * fix ui tests * additional doc * implement StorageInstance with new syntax * fix line width * fix doc: because pallet doc goes below reexport doc * Update frame/support/procedural/src/pallet/parse/event.rs Co-authored-by: Andrew Jones <ascjones@gmail.com> * Update frame/system/src/lib.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Update frame/support/test/tests/pallet_ui.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * improve doc as suggested * revert construct_runtime Pallet part. This revert the changes on construct_runtime. Now construct_runtime is unchanged and instead pallet macro create a type alias `type Module<..> = Pallet<..>` to be used by construct_runtime * refactor with less intricated code * fix ui test with new image * fix ui tests * add minor tests Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Andrew Jones <ascjones@gmail.com> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
1 parent 78aee75 commit 262510b

File tree

130 files changed

+9592
-30
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+9592
-30
lines changed

procedural/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121

2222
mod storage;
2323
mod construct_runtime;
24+
mod pallet;
2425
mod pallet_version;
2526
mod transactional;
2627
mod debug_no_bound;
2728
mod clone_no_bound;
2829
mod partial_eq_no_bound;
2930

31+
pub(crate) use storage::INHERENT_INSTANCE_NAME;
3032
use proc_macro::TokenStream;
3133

3234
/// Declares strongly-typed wrappers around codec-compatible types in storage.
@@ -305,6 +307,12 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream {
305307
construct_runtime::construct_runtime(input)
306308
}
307309

310+
/// Macro to define a pallet. Docs are at `frame_support::pallet`.
311+
#[proc_macro_attribute]
312+
pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream {
313+
pallet::pallet(attr, item)
314+
}
315+
308316
/// Execute the annotated function in a new storage transaction.
309317
///
310318
/// The return type of the annotated function must be `Result`. All changes to storage performed

procedural/src/pallet/expand/call.rs

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
use crate::pallet::Def;
19+
use frame_support_procedural_tools::clean_type_string;
20+
use syn::spanned::Spanned;
21+
22+
/// * Generate enum call and implement various trait on it.
23+
/// * Implement Callable and call_function on `Pallet`
24+
pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
25+
let frame_support = &def.frame_support;
26+
let frame_system = &def.frame_system;
27+
let type_impl_gen = &def.type_impl_generics();
28+
let type_decl_bounded_gen = &def.type_decl_bounded_generics();
29+
let type_use_gen = &def.type_use_generics();
30+
let call_ident = syn::Ident::new("Call", def.call.attr_span.clone());
31+
let pallet_ident = &def.pallet_struct.pallet;
32+
let where_clause = &def.call.where_clause;
33+
34+
let fn_name = def.call.methods.iter().map(|method| &method.name).collect::<Vec<_>>();
35+
36+
let fn_weight = def.call.methods.iter().map(|method| &method.weight);
37+
38+
let fn_doc = def.call.methods.iter().map(|method| &method.docs).collect::<Vec<_>>();
39+
40+
let args_name = def.call.methods.iter()
41+
.map(|method| method.args.iter().map(|(_, name, _)| name.clone()).collect::<Vec<_>>())
42+
.collect::<Vec<_>>();
43+
44+
let args_type = def.call.methods.iter()
45+
.map(|method| method.args.iter().map(|(_, _, type_)| type_.clone()).collect::<Vec<_>>())
46+
.collect::<Vec<_>>();
47+
48+
let args_compact_attr = def.call.methods.iter().map(|method| {
49+
method.args.iter()
50+
.map(|(is_compact, _, type_)| {
51+
if *is_compact {
52+
quote::quote_spanned!(type_.span() => #[codec(compact)] )
53+
} else {
54+
quote::quote!()
55+
}
56+
})
57+
.collect::<Vec<_>>()
58+
});
59+
60+
let args_metadata_type = def.call.methods.iter().map(|method| {
61+
method.args.iter()
62+
.map(|(is_compact, _, type_)| {
63+
let final_type = if *is_compact {
64+
quote::quote!(Compact<#type_>)
65+
} else {
66+
quote::quote!(#type_)
67+
};
68+
clean_type_string(&final_type.to_string())
69+
})
70+
.collect::<Vec<_>>()
71+
});
72+
73+
quote::quote_spanned!(def.call.attr_span =>
74+
#[derive(
75+
#frame_support::RuntimeDebugNoBound,
76+
#frame_support::CloneNoBound,
77+
#frame_support::EqNoBound,
78+
#frame_support::PartialEqNoBound,
79+
#frame_support::codec::Encode,
80+
#frame_support::codec::Decode,
81+
)]
82+
#[allow(non_camel_case_types)]
83+
pub enum #call_ident<#type_decl_bounded_gen> #where_clause {
84+
#[doc(hidden)]
85+
#[codec(skip)]
86+
__Ignore(
87+
#frame_support::sp_std::marker::PhantomData<(#type_use_gen,)>,
88+
#frame_support::Never,
89+
),
90+
#( #fn_name( #( #args_compact_attr #args_type ),* ), )*
91+
}
92+
93+
impl<#type_impl_gen> #frame_support::dispatch::GetDispatchInfo
94+
for #call_ident<#type_use_gen>
95+
#where_clause
96+
{
97+
fn get_dispatch_info(&self) -> #frame_support::dispatch::DispatchInfo {
98+
match *self {
99+
#(
100+
Self::#fn_name ( #( ref #args_name, )* ) => {
101+
let base_weight = #fn_weight;
102+
103+
let weight = <
104+
dyn #frame_support::dispatch::WeighData<( #( & #args_type, )* )>
105+
>::weigh_data(&base_weight, ( #( #args_name, )* ));
106+
107+
let class = <
108+
dyn #frame_support::dispatch::ClassifyDispatch<
109+
( #( & #args_type, )* )
110+
>
111+
>::classify_dispatch(&base_weight, ( #( #args_name, )* ));
112+
113+
let pays_fee = <
114+
dyn #frame_support::dispatch::PaysFee<( #( & #args_type, )* )>
115+
>::pays_fee(&base_weight, ( #( #args_name, )* ));
116+
117+
#frame_support::dispatch::DispatchInfo {
118+
weight,
119+
class,
120+
pays_fee,
121+
}
122+
},
123+
)*
124+
Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
125+
}
126+
}
127+
}
128+
129+
impl<#type_impl_gen> #frame_support::dispatch::GetCallName for #call_ident<#type_use_gen>
130+
#where_clause
131+
{
132+
fn get_call_name(&self) -> &'static str {
133+
match *self {
134+
#( Self::#fn_name(..) => stringify!(#fn_name), )*
135+
Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."),
136+
}
137+
}
138+
139+
fn get_call_names() -> &'static [&'static str] {
140+
&[ #( stringify!(#fn_name), )* ]
141+
}
142+
}
143+
144+
impl<#type_impl_gen> #frame_support::traits::UnfilteredDispatchable
145+
for #call_ident<#type_use_gen>
146+
#where_clause
147+
{
148+
type Origin = #frame_system::pallet_prelude::OriginFor<T>;
149+
fn dispatch_bypass_filter(
150+
self,
151+
origin: Self::Origin
152+
) -> #frame_support::dispatch::DispatchResultWithPostInfo {
153+
match self {
154+
#(
155+
Self::#fn_name( #( #args_name, )* ) =>
156+
<#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* )
157+
.map(Into::into).map_err(Into::into),
158+
)*
159+
Self::__Ignore(_, _) => {
160+
let _ = origin; // Use origin for empty Call enum
161+
unreachable!("__PhantomItem cannot be used.");
162+
},
163+
}
164+
}
165+
}
166+
167+
impl<#type_impl_gen> #frame_support::dispatch::Callable<T> for #pallet_ident<#type_use_gen>
168+
#where_clause
169+
{
170+
type Call = #call_ident<#type_use_gen>;
171+
}
172+
173+
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause {
174+
#[doc(hidden)]
175+
pub fn call_functions() -> &'static [#frame_support::dispatch::FunctionMetadata] {
176+
&[ #(
177+
#frame_support::dispatch::FunctionMetadata {
178+
name: #frame_support::dispatch::DecodeDifferent::Encode(
179+
stringify!(#fn_name)
180+
),
181+
arguments: #frame_support::dispatch::DecodeDifferent::Encode(
182+
&[ #(
183+
#frame_support::dispatch::FunctionArgumentMetadata {
184+
name: #frame_support::dispatch::DecodeDifferent::Encode(
185+
stringify!(#args_name)
186+
),
187+
ty: #frame_support::dispatch::DecodeDifferent::Encode(
188+
#args_metadata_type
189+
),
190+
},
191+
)* ]
192+
),
193+
documentation: #frame_support::dispatch::DecodeDifferent::Encode(
194+
&[ #( #fn_doc ),* ]
195+
),
196+
},
197+
)* ]
198+
}
199+
}
200+
)
201+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
use crate::pallet::Def;
19+
use frame_support_procedural_tools::clean_type_string;
20+
use quote::ToTokens;
21+
22+
struct ConstDef {
23+
/// Name of the associated type.
24+
pub ident: syn::Ident,
25+
/// The type in Get, e.g. `u32` in `type Foo: Get<u32>;`, but `Self` is replaced by `T`
26+
pub type_: syn::Type,
27+
/// The doc associated
28+
pub doc: Vec<syn::Lit>,
29+
/// default_byte implementation
30+
pub default_byte_impl: proc_macro2::TokenStream,
31+
}
32+
33+
/// * Impl fn module_constant_metadata for pallet.
34+
pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream {
35+
let frame_support = &def.frame_support;
36+
let type_impl_gen = &def.type_impl_generics();
37+
let type_decl_gen = &def.type_decl_generics();
38+
let type_use_gen = &def.type_use_generics();
39+
let pallet_ident = &def.pallet_struct.pallet;
40+
41+
let mut where_clauses = vec![&def.config.where_clause];
42+
where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause));
43+
let completed_where_clause = super::merge_where_clauses(&where_clauses);
44+
45+
let config_consts = def.config.consts_metadata.iter().map(|const_| {
46+
let ident = &const_.ident;
47+
let const_type = &const_.type_;
48+
49+
ConstDef {
50+
ident: const_.ident.clone(),
51+
type_: const_.type_.clone(),
52+
doc: const_.doc.clone(),
53+
default_byte_impl: quote::quote!(
54+
let value = <T::#ident as #frame_support::traits::Get<#const_type>>::get();
55+
#frame_support::codec::Encode::encode(&value)
56+
),
57+
}
58+
});
59+
60+
let extra_consts = def.extra_constants.iter().flat_map(|d| &d.extra_constants).map(|const_| {
61+
let ident = &const_.ident;
62+
63+
ConstDef {
64+
ident: const_.ident.clone(),
65+
type_: const_.type_.clone(),
66+
doc: const_.doc.clone(),
67+
default_byte_impl: quote::quote!(
68+
let value = <Pallet<#type_use_gen>>::#ident();
69+
#frame_support::codec::Encode::encode(&value)
70+
),
71+
}
72+
});
73+
74+
let consts = config_consts.chain(extra_consts)
75+
.map(|const_| {
76+
let const_type = &const_.type_;
77+
let const_type_str = clean_type_string(&const_type.to_token_stream().to_string());
78+
let ident = &const_.ident;
79+
let ident_str = format!("{}", ident);
80+
let doc = const_.doc.clone().into_iter();
81+
let default_byte_impl = &const_.default_byte_impl;
82+
let default_byte_getter = syn::Ident::new(
83+
&format!("{}DefaultByteGetter", ident),
84+
ident.span()
85+
);
86+
87+
quote::quote!({
88+
#[allow(non_upper_case_types)]
89+
#[allow(non_camel_case_types)]
90+
struct #default_byte_getter<#type_decl_gen>(
91+
#frame_support::sp_std::marker::PhantomData<(#type_use_gen)>
92+
);
93+
94+
impl<#type_impl_gen> #frame_support::dispatch::DefaultByte for
95+
#default_byte_getter<#type_use_gen>
96+
#completed_where_clause
97+
{
98+
fn default_byte(&self) -> #frame_support::sp_std::vec::Vec<u8> {
99+
#default_byte_impl
100+
}
101+
}
102+
103+
unsafe impl<#type_impl_gen> Send for #default_byte_getter<#type_use_gen>
104+
#completed_where_clause
105+
{}
106+
unsafe impl<#type_impl_gen> Sync for #default_byte_getter<#type_use_gen>
107+
#completed_where_clause
108+
{}
109+
110+
#frame_support::dispatch::ModuleConstantMetadata {
111+
name: #frame_support::dispatch::DecodeDifferent::Encode(#ident_str),
112+
ty: #frame_support::dispatch::DecodeDifferent::Encode(#const_type_str),
113+
value: #frame_support::dispatch::DecodeDifferent::Encode(
114+
#frame_support::dispatch::DefaultByteGetter(
115+
&#default_byte_getter::<#type_use_gen>(
116+
#frame_support::sp_std::marker::PhantomData
117+
)
118+
)
119+
),
120+
documentation: #frame_support::dispatch::DecodeDifferent::Encode(
121+
&[ #( #doc ),* ]
122+
),
123+
}
124+
})
125+
});
126+
127+
quote::quote!(
128+
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause{
129+
130+
#[doc(hidden)]
131+
pub fn module_constants_metadata()
132+
-> &'static [#frame_support::dispatch::ModuleConstantMetadata]
133+
{
134+
&[ #( #consts ),* ]
135+
}
136+
}
137+
)
138+
}

0 commit comments

Comments
 (0)