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

Commit

Permalink
allow pallets to specify an auto_construct_runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
gui1117 committed Jun 24, 2020
1 parent c771821 commit 2616950
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 6 deletions.
2 changes: 1 addition & 1 deletion bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ construct_runtime!(
TechnicalMembership: pallet_membership::<Instance1>::{Module, Call, Storage, Event<T>, Config<T>},
FinalityTracker: pallet_finality_tracker::{Module, Call, Inherent},
Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event},
Treasury: pallet_treasury::{Module, Call, Storage, Config, Event<T>},
Treasury: pallet_treasury::{auto},
Contracts: pallet_contracts::{Module, Call, Config, Storage, Event<T>},
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
ImOnline: pallet_im_online::{Module, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
Expand Down
47 changes: 45 additions & 2 deletions frame/support/procedural/src/construct_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,62 @@ use frame_support_procedural_tools::{generate_crate_access, generate_hidden_incl
use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{Ident, Result, TypePath};
use quote::{quote, quote_spanned};
use syn::{Ident, Result, TypePath, spanned::Spanned};

/// The fixed name of the system module.
const SYSTEM_MODULE_NAME: &str = "System";

pub fn construct_runtime(input: TokenStream) -> TokenStream {
let input_clone = input.clone().into();
let definition = syn::parse_macro_input!(input as RuntimeDefinition);

if let Some(preprocess) = construct_runtime_preprocess(&definition, input_clone)
.unwrap_or_else(|e| Some(e.to_compile_error()))
{
return preprocess.into()
}

construct_runtime_parsed(definition)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}

fn construct_runtime_preprocess(
definition: &RuntimeDefinition,
input_clone: TokenStream2,
) -> Result<Option<TokenStream2>> {
let mut auto_modules = vec![];
for module in definition.modules.content.inner.iter() {
if module.module_parts.iter().any(|p| p.keyword.name() == "auto") {
if module.module_parts.len() != 1 {
return Err(syn::Error::new(
module.module_parts[0].keyword.span(),
"Module parts must either provide explicit parts or use `auto` keyword but
cannot combine."
))
}

auto_modules.push(module.module.clone());
}
}

if !auto_modules.is_empty() {
let mut expand = input_clone;

while let Some(module) = auto_modules.pop() {
expand = quote_spanned!(module.span() => #module::auto_construct_runtime!{
construct_runtime! { #expand }
}
)
}

Ok(Some(expand))
} else {
Ok(None)
}
}

fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream2> {
let RuntimeDefinition {
name,
Expand Down
10 changes: 8 additions & 2 deletions frame/support/procedural/src/construct_runtime/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use syn::{
token, Error, Ident, Result, Token,
};

mod keyword {
pub mod keyword {
syn::custom_keyword!(Block);
syn::custom_keyword!(NodeBlock);
syn::custom_keyword!(UncheckedExtrinsic);
Expand All @@ -36,6 +36,7 @@ mod keyword {
syn::custom_keyword!(Origin);
syn::custom_keyword!(Inherent);
syn::custom_keyword!(ValidateUnsigned);
syn::custom_keyword!(auto);
}

#[derive(Debug)]
Expand Down Expand Up @@ -231,6 +232,7 @@ pub enum ModulePartKeyword {
Origin(keyword::Origin),
Inherent(keyword::Inherent),
ValidateUnsigned(keyword::ValidateUnsigned),
Auto(keyword::auto),
}

impl Parse for ModulePartKeyword {
Expand All @@ -253,6 +255,8 @@ impl Parse for ModulePartKeyword {
Ok(Self::Inherent(input.parse()?))
} else if lookahead.peek(keyword::ValidateUnsigned) {
Ok(Self::ValidateUnsigned(input.parse()?))
} else if lookahead.peek(keyword::auto) {
Ok(Self::Auto(input.parse()?))
} else {
Err(lookahead.error())
}
Expand All @@ -261,7 +265,7 @@ impl Parse for ModulePartKeyword {

impl ModulePartKeyword {
/// Returns the name of `Self`.
fn name(&self) -> &'static str {
pub fn name(&self) -> &'static str {
match self {
Self::Module(_) => "Module",
Self::Call(_) => "Call",
Expand All @@ -271,6 +275,7 @@ impl ModulePartKeyword {
Self::Origin(_) => "Origin",
Self::Inherent(_) => "Inherent",
Self::ValidateUnsigned(_) => "ValidateUnsigned",
Self::Auto(_) => "auto",
}
}

Expand Down Expand Up @@ -313,6 +318,7 @@ impl Spanned for ModulePartKeyword {
Self::Origin(inner) => inner.span(),
Self::Inherent(inner) => inner.span(),
Self::ValidateUnsigned(inner) => inner.span(),
Self::Auto(inner) => inner.span(),
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions frame/support/procedural/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

mod storage;
mod construct_runtime;
mod replace_auto_with;

use proc_macro::TokenStream;

Expand Down Expand Up @@ -260,6 +261,8 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
/// // Module with instances
/// Test3_Instance1: test3::<Instance1>::{Module, Call, Storage, Event<T, I>, Config<T, I>, Origin<T, I>},
/// Test3_DefaultInstance: test3::{Module, Call, Storage, Event<T>, Config<T>, Origin<T>},
///
/// TestAuto: pallet_with_auto_construct_runtime::{auto},
/// }
/// )
/// ```
Expand All @@ -282,6 +285,9 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
/// inherent.
/// - `ValidateUnsigned` - If the module validates unsigned extrinsics.
///
/// alternatively if the pallet provide the auto_contruct_runtime macro, parts can be automatically
/// filled using `auto` keyword.
///
/// # Note
///
/// The population of the genesis storage depends on the order of modules. So, if one of your
Expand All @@ -291,3 +297,24 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
pub fn construct_runtime(input: TokenStream) -> TokenStream {
construct_runtime::construct_runtime(input)
}

/// Macro than replace the first found `auto` ident with some specified content.
///
/// # Example:
///
/// ```nocompile
/// replace_auto_with!(
/// { something or else } // content inside braces can be anything.
/// Some content with at some point { an ident named auto } other auto are ignored
/// )
/// ```
///
/// will generate:
///
/// ```nocompile
/// Some content with at some point { an ident named something or else } other auto are ignored
/// ```
#[proc_macro]
pub fn replace_auto_with(input: TokenStream) -> TokenStream {
replace_auto_with::replace_auto_with(input)
}
2 changes: 1 addition & 1 deletion frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ macro_rules! ord_parameter_types {
}

#[doc(inline)]
pub use frame_support_procedural::{decl_storage, construct_runtime};
pub use frame_support_procedural::{decl_storage, construct_runtime, replace_auto_with};

/// Return Err of the expression: `return Err($expression);`.
///
Expand Down
10 changes: 10 additions & 0 deletions frame/treasury/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trai
type PositiveImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::PositiveImbalance;
type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::NegativeImbalance;

#[macro_export]
macro_rules! auto_construct_runtime {
( $( $t:tt )* ) => {
frame_support::replace_auto_with! {
{ Module, Call, Storage, Config, Event<T> }
$( $t )*
}
}
}

pub trait Trait: frame_system::Trait {
/// The treasury's module id, used for deriving its sovereign account ID.
type ModuleId: Get<ModuleId>;
Expand Down

0 comments on commit 2616950

Please sign in to comment.