Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Add pallet attribute macro to declare pallets #6877

Merged
47 commits merged into from
Dec 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b67c866
rename system Config to system Trait.
thiolliere Oct 27, 2020
336d3c9
make construct_runtime handle Pallet and Module
thiolliere Oct 27, 2020
942c161
introduce pallet attribute macro
thiolliere Oct 27, 2020
1e1e8a3
allow to print some upgrade helper from decl_storage
thiolliere Oct 29, 2020
0d9bb3e
Improved error msg, typo.
thiolliere Nov 19, 2020
b48cfc6
Improved error msg, typo.
thiolliere Nov 19, 2020
cc165a3
Improved error message on unexpected attributes + ui test
thiolliere Nov 19, 2020
460ccf9
add test for transactional
thiolliere Nov 19, 2020
5ced0a8
various typo
thiolliere Nov 19, 2020
688f044
some tips when spans are lost
thiolliere Nov 23, 2020
c5ef21f
allow pallet to depend on other pallet instances
thiolliere Nov 23, 2020
240a2a7
make event type metadata consistent with call and constant
thiolliere Nov 23, 2020
1229c33
error messages
thiolliere Nov 23, 2020
30000d0
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Nov 23, 2020
c2148b0
ignore doc example
thiolliere Nov 23, 2020
e5485c8
fix pallet upgrade template
thiolliere Nov 23, 2020
1ff085e
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Nov 25, 2020
d5b745f
fixup
thiolliere Nov 25, 2020
8e8ee8d
fix doc
thiolliere Nov 25, 2020
3ea926c
fix indentation
thiolliere Nov 25, 2020
bd99a8d
Apply suggestions code formatting
thiolliere Nov 30, 2020
0adbb30
some renames + fix compilation
thiolliere Nov 30, 2020
c96e1cf
remove unsupported genesis config type alias
thiolliere Nov 30, 2020
04a54d6
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Nov 30, 2020
78789d6
merge fixup
thiolliere Nov 30, 2020
96845d8
fix ui tests
thiolliere Dec 2, 2020
1762c47
additional doc
thiolliere Dec 2, 2020
a03a4b4
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 2, 2020
4cb71d8
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 3, 2020
cf7ae7d
implement StorageInstance with new syntax
thiolliere Dec 3, 2020
88e6995
fix line width
thiolliere Dec 3, 2020
d1ec690
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 3, 2020
3a29683
fix doc: because pallet doc goes below reexport doc
thiolliere Dec 4, 2020
9430b34
Merge remote-tracking branch 'origin/master' into HEAD
thiolliere Dec 9, 2020
888d121
Update frame/support/procedural/src/pallet/parse/event.rs
thiolliere Dec 9, 2020
6fa68a9
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 9, 2020
0c6f916
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 14, 2020
52a654f
Update frame/system/src/lib.rs
thiolliere Dec 23, 2020
03c7fbf
Update frame/support/test/tests/pallet_ui.rs
thiolliere Dec 23, 2020
3f23d3c
improve doc as suggested
thiolliere Dec 23, 2020
d9d48c7
revert construct_runtime Pallet part.
thiolliere Dec 23, 2020
0d56f2b
refactor with less intricated code
thiolliere Dec 23, 2020
d9fdc4b
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 23, 2020
98cdc0e
fix ui test with new image
thiolliere Dec 23, 2020
ae38859
fix ui tests
thiolliere Dec 23, 2020
c158e5f
add minor tests
thiolliere Dec 24, 2020
10e8a92
Merge remote-tracking branch 'origin/master' into gui-macro-attribute
thiolliere Dec 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions frame/support/procedural/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@

mod storage;
mod construct_runtime;
mod pallet;
mod pallet_version;
mod transactional;
mod debug_no_bound;
mod clone_no_bound;
mod partial_eq_no_bound;

pub(crate) use storage::INHERENT_INSTANCE_NAME;
use proc_macro::TokenStream;

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

/// Macro to define a pallet. Docs are at `frame_support::pallet`.
#[proc_macro_attribute]
pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream {
pallet::pallet(attr, item)
}

/// Execute the annotated function in a new storage transaction.
///
/// The return type of the annotated function must be `Result`. All changes to storage performed
Expand Down
201 changes: 201 additions & 0 deletions frame/support/procedural/src/pallet/expand/call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// This file is part of Substrate.

// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::pallet::Def;
use frame_support_procedural_tools::clean_type_string;
use syn::spanned::Spanned;

/// * Generate enum call and implement various trait on it.
/// * Implement Callable and call_function on `Pallet`
pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let type_impl_gen = &def.type_impl_generics();
let type_decl_bounded_gen = &def.type_decl_bounded_generics();
let type_use_gen = &def.type_use_generics();
let call_ident = syn::Ident::new("Call", def.call.attr_span.clone());
let pallet_ident = &def.pallet_struct.pallet;
let where_clause = &def.call.where_clause;

let fn_name = def.call.methods.iter().map(|method| &method.name).collect::<Vec<_>>();

let fn_weight = def.call.methods.iter().map(|method| &method.weight);

let fn_doc = def.call.methods.iter().map(|method| &method.docs).collect::<Vec<_>>();

let args_name = def.call.methods.iter()
.map(|method| method.args.iter().map(|(_, name, _)| name.clone()).collect::<Vec<_>>())
.collect::<Vec<_>>();

let args_type = def.call.methods.iter()
.map(|method| method.args.iter().map(|(_, _, type_)| type_.clone()).collect::<Vec<_>>())
.collect::<Vec<_>>();

let args_compact_attr = def.call.methods.iter().map(|method| {
method.args.iter()
.map(|(is_compact, _, type_)| {
if *is_compact {
quote::quote_spanned!(type_.span() => #[codec(compact)] )
} else {
quote::quote!()
}
})
.collect::<Vec<_>>()
});

let args_metadata_type = def.call.methods.iter().map(|method| {
method.args.iter()
.map(|(is_compact, _, type_)| {
let final_type = if *is_compact {
quote::quote!(Compact<#type_>)
} else {
quote::quote!(#type_)
};
clean_type_string(&final_type.to_string())
})
.collect::<Vec<_>>()
});

quote::quote_spanned!(def.call.attr_span =>
#[derive(
#frame_support::RuntimeDebugNoBound,
#frame_support::CloneNoBound,
#frame_support::EqNoBound,
#frame_support::PartialEqNoBound,
#frame_support::codec::Encode,
#frame_support::codec::Decode,
)]
#[allow(non_camel_case_types)]
pub enum #call_ident<#type_decl_bounded_gen> #where_clause {
#[doc(hidden)]
#[codec(skip)]
__Ignore(
#frame_support::sp_std::marker::PhantomData<(#type_use_gen,)>,
#frame_support::Never,
),
#( #fn_name( #( #args_compact_attr #args_type ),* ), )*
}

impl<#type_impl_gen> #frame_support::dispatch::GetDispatchInfo
for #call_ident<#type_use_gen>
#where_clause
{
fn get_dispatch_info(&self) -> #frame_support::dispatch::DispatchInfo {
match *self {
#(
Self::#fn_name ( #( ref #args_name, )* ) => {
let base_weight = #fn_weight;

let weight = <
dyn #frame_support::dispatch::WeighData<( #( & #args_type, )* )>
>::weigh_data(&base_weight, ( #( #args_name, )* ));

let class = <
dyn #frame_support::dispatch::ClassifyDispatch<
( #( & #args_type, )* )
>
>::classify_dispatch(&base_weight, ( #( #args_name, )* ));

let pays_fee = <
dyn #frame_support::dispatch::PaysFee<( #( & #args_type, )* )>
>::pays_fee(&base_weight, ( #( #args_name, )* ));

#frame_support::dispatch::DispatchInfo {
weight,
class,
pays_fee,
}
},
)*
Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
}
}
}

impl<#type_impl_gen> #frame_support::dispatch::GetCallName for #call_ident<#type_use_gen>
#where_clause
{
fn get_call_name(&self) -> &'static str {
match *self {
#( Self::#fn_name(..) => stringify!(#fn_name), )*
Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."),
}
}

fn get_call_names() -> &'static [&'static str] {
&[ #( stringify!(#fn_name), )* ]
}
}

impl<#type_impl_gen> #frame_support::traits::UnfilteredDispatchable
for #call_ident<#type_use_gen>
#where_clause
{
type Origin = #frame_system::pallet_prelude::OriginFor<T>;
fn dispatch_bypass_filter(
self,
origin: Self::Origin
thiolliere marked this conversation as resolved.
Show resolved Hide resolved
) -> #frame_support::dispatch::DispatchResultWithPostInfo {
match self {
#(
Self::#fn_name( #( #args_name, )* ) =>
<#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* )
.map(Into::into).map_err(Into::into),
)*
Self::__Ignore(_, _) => {
let _ = origin; // Use origin for empty Call enum
unreachable!("__PhantomItem cannot be used.");
},
}
}
}

impl<#type_impl_gen> #frame_support::dispatch::Callable<T> for #pallet_ident<#type_use_gen>
#where_clause
{
type Call = #call_ident<#type_use_gen>;
}

impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause {
#[doc(hidden)]
pub fn call_functions() -> &'static [#frame_support::dispatch::FunctionMetadata] {
&[ #(
#frame_support::dispatch::FunctionMetadata {
name: #frame_support::dispatch::DecodeDifferent::Encode(
stringify!(#fn_name)
),
arguments: #frame_support::dispatch::DecodeDifferent::Encode(
&[ #(
#frame_support::dispatch::FunctionArgumentMetadata {
name: #frame_support::dispatch::DecodeDifferent::Encode(
stringify!(#args_name)
),
ty: #frame_support::dispatch::DecodeDifferent::Encode(
#args_metadata_type
),
},
)* ]
),
documentation: #frame_support::dispatch::DecodeDifferent::Encode(
&[ #( #fn_doc ),* ]
),
},
)* ]
}
}
)
}
138 changes: 138 additions & 0 deletions frame/support/procedural/src/pallet/expand/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// This file is part of Substrate.

// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::pallet::Def;
use frame_support_procedural_tools::clean_type_string;
use quote::ToTokens;

struct ConstDef {
/// Name of the associated type.
pub ident: syn::Ident,
/// The type in Get, e.g. `u32` in `type Foo: Get<u32>;`, but `Self` is replaced by `T`
pub type_: syn::Type,
/// The doc associated
pub doc: Vec<syn::Lit>,
/// default_byte implementation
pub default_byte_impl: proc_macro2::TokenStream,
}

/// * Impl fn module_constant_metadata for pallet.
pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let type_impl_gen = &def.type_impl_generics();
let type_decl_gen = &def.type_decl_generics();
let type_use_gen = &def.type_use_generics();
let pallet_ident = &def.pallet_struct.pallet;

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 config_consts = def.config.consts_metadata.iter().map(|const_| {
let ident = &const_.ident;
let const_type = &const_.type_;

ConstDef {
ident: const_.ident.clone(),
type_: const_.type_.clone(),
doc: const_.doc.clone(),
default_byte_impl: quote::quote!(
let value = <T::#ident as #frame_support::traits::Get<#const_type>>::get();
#frame_support::codec::Encode::encode(&value)
),
}
});

let extra_consts = def.extra_constants.iter().flat_map(|d| &d.extra_constants).map(|const_| {
let ident = &const_.ident;

ConstDef {
ident: const_.ident.clone(),
type_: const_.type_.clone(),
doc: const_.doc.clone(),
default_byte_impl: quote::quote!(
let value = <Pallet<#type_use_gen>>::#ident();
#frame_support::codec::Encode::encode(&value)
),
}
});

let consts = config_consts.chain(extra_consts)
.map(|const_| {
let const_type = &const_.type_;
let const_type_str = clean_type_string(&const_type.to_token_stream().to_string());
let ident = &const_.ident;
let ident_str = format!("{}", ident);
let doc = const_.doc.clone().into_iter();
let default_byte_impl = &const_.default_byte_impl;
let default_byte_getter = syn::Ident::new(
&format!("{}DefaultByteGetter", ident),
ident.span()
);

quote::quote!({
#[allow(non_upper_case_types)]
#[allow(non_camel_case_types)]
struct #default_byte_getter<#type_decl_gen>(
#frame_support::sp_std::marker::PhantomData<(#type_use_gen)>
);

impl<#type_impl_gen> #frame_support::dispatch::DefaultByte for
#default_byte_getter<#type_use_gen>
#completed_where_clause
{
fn default_byte(&self) -> #frame_support::sp_std::vec::Vec<u8> {
#default_byte_impl
}
}

unsafe impl<#type_impl_gen> Send for #default_byte_getter<#type_use_gen>
#completed_where_clause
{}
unsafe impl<#type_impl_gen> Sync for #default_byte_getter<#type_use_gen>
#completed_where_clause
{}

#frame_support::dispatch::ModuleConstantMetadata {
name: #frame_support::dispatch::DecodeDifferent::Encode(#ident_str),
ty: #frame_support::dispatch::DecodeDifferent::Encode(#const_type_str),
value: #frame_support::dispatch::DecodeDifferent::Encode(
#frame_support::dispatch::DefaultByteGetter(
&#default_byte_getter::<#type_use_gen>(
#frame_support::sp_std::marker::PhantomData
)
)
),
documentation: #frame_support::dispatch::DecodeDifferent::Encode(
&[ #( #doc ),* ]
),
}
})
});

quote::quote!(
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause{

#[doc(hidden)]
pub fn module_constants_metadata()
-> &'static [#frame_support::dispatch::ModuleConstantMetadata]
{
&[ #( #consts ),* ]
}
}
)
}