mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 16:27:58 +00:00
5647e71947
* construct_runtime: Fix generation of types behind features With the recent addition of supporting features in `construct_runtime!` there was a bug overseen. The `AllPalletsWithSystem` etc type declarations would be declared twice when a certain was enabled. The problem was that in the macro we didn't feature gate the types that should be declared when there is no feature enabled. This pull request now takes care of feature gating this type behind `all(#( not(feature) ))`. So, these types will only be enabled if no of the configured features is enabled. * Fix tests * FMT
617 lines
19 KiB
Rust
617 lines
19 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) 2019-2022 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.
|
|
|
|
//! Implementation of `construct_runtime`.
|
|
//!
|
|
//! `construct_runtime` implementation is recursive and can generate code which will call itself in
|
|
//! order to get all the pallet parts for each pallet.
|
|
//!
|
|
//! Pallets define their parts (`Call`, `Storage`, ..) either explicitly with the syntax
|
|
//! `::{Call, ...}` or implicitly.
|
|
//!
|
|
//! In case a pallet defines its parts implicitly, then the pallet must provide the
|
|
//! `tt_default_parts` macro. `construct_rutime` will generate some code which utilizes `tt_call`
|
|
//! to call the `tt_default_parts` macro of the pallet. `tt_default_parts` will then return the
|
|
//! default pallet parts as input tokens to the `match_and_replace` macro, which ultimately
|
|
//! generates a call to `construct_runtime` again, this time with all the pallet parts explicitly
|
|
//! defined.
|
|
//!
|
|
//! E.g.
|
|
//! ```ignore
|
|
//! construct_runtime!(
|
|
//! //...
|
|
//! {
|
|
//! System: frame_system = 0, // Implicit definition of parts
|
|
//! Balances: pallet_balances = 1, // Implicit definition of parts
|
|
//! }
|
|
//! );
|
|
//! ```
|
|
//! This call has some implicit pallet parts, thus it will expand to:
|
|
//! ```ignore
|
|
//! frame_support::tt_call! {
|
|
//! macro = [{ pallet_balances::tt_default_parts }]
|
|
//! ~~> frame_support::match_and_insert! {
|
|
//! target = [{
|
|
//! frame_support::tt_call! {
|
|
//! macro = [{ frame_system::tt_default_parts }]
|
|
//! ~~> frame_support::match_and_insert! {
|
|
//! target = [{
|
|
//! construct_runtime!(
|
|
//! //...
|
|
//! {
|
|
//! System: frame_system = 0,
|
|
//! Balances: pallet_balances = 1,
|
|
//! }
|
|
//! );
|
|
//! }]
|
|
//! pattern = [{ System: frame_system }]
|
|
//! }
|
|
//! }
|
|
//! }]
|
|
//! pattern = [{ Balances: pallet_balances }]
|
|
//! }
|
|
//! }
|
|
//! ```
|
|
//! `tt_default_parts` must be defined. It returns the pallet parts inside some tokens, and
|
|
//! then `tt_call` will pipe the returned pallet parts into the input of `match_and_insert`.
|
|
//! Thus `match_and_insert` will initially receive the following inputs:
|
|
//! ```ignore
|
|
//! frame_support::match_and_insert! {
|
|
//! target = [{
|
|
//! frame_support::match_and_insert! {
|
|
//! target = [{
|
|
//! construct_runtime!(
|
|
//! //...
|
|
//! {
|
|
//! System: frame_system = 0,
|
|
//! Balances: pallet_balances = 1,
|
|
//! }
|
|
//! )
|
|
//! }]
|
|
//! pattern = [{ System: frame_system }]
|
|
//! tokens = [{ ::{Pallet, Call} }]
|
|
//! }
|
|
//! }]
|
|
//! pattern = [{ Balances: pallet_balances }]
|
|
//! tokens = [{ ::{Pallet, Call} }]
|
|
//! }
|
|
//! ```
|
|
//! After dealing with `pallet_balances`, the inner `match_and_insert` will expand to:
|
|
//! ```ignore
|
|
//! frame_support::match_and_insert! {
|
|
//! target = [{
|
|
//! construct_runtime!(
|
|
//! //...
|
|
//! {
|
|
//! System: frame_system = 0, // Implicit definition of parts
|
|
//! Balances: pallet_balances::{Pallet, Call} = 1, // Explicit definition of parts
|
|
//! }
|
|
//! )
|
|
//! }]
|
|
//! pattern = [{ System: frame_system }]
|
|
//! tokens = [{ ::{Pallet, Call} }]
|
|
//! }
|
|
//! ```
|
|
//! Which will then finally expand to the following:
|
|
//! ```ignore
|
|
//! construct_runtime!(
|
|
//! //...
|
|
//! {
|
|
//! System: frame_system::{Pallet, Call},
|
|
//! Balances: pallet_balances::{Pallet, Call},
|
|
//! }
|
|
//! )
|
|
//! ```
|
|
//! This call has no implicit pallet parts, thus it will expand to the runtime construction:
|
|
//! ```ignore
|
|
//! pub struct Runtime { ... }
|
|
//! pub struct Call { ... }
|
|
//! impl Call ...
|
|
//! pub enum Origin { ... }
|
|
//! ...
|
|
//! ```
|
|
//!
|
|
//! Visualizing the entire flow of `construct_runtime!`, it would look like the following:
|
|
//!
|
|
//! ```ignore
|
|
//! +--------------------+ +---------------------+ +-------------------+
|
|
//! | | | (defined in pallet) | | |
|
|
//! | construct_runtime! | --> | tt_default_parts! | --> | match_and_insert! |
|
|
//! | w/ no pallet parts | | | | |
|
|
//! +--------------------+ +---------------------+ +-------------------+
|
|
//!
|
|
//! +--------------------+
|
|
//! | |
|
|
//! --> | construct_runtime! |
|
|
//! | w/ pallet parts |
|
|
//! +--------------------+
|
|
//! ```
|
|
|
|
mod expand;
|
|
mod parse;
|
|
|
|
use cfg_expr::Predicate;
|
|
use frame_support_procedural_tools::{
|
|
generate_crate_access, generate_crate_access_2018, generate_hidden_includes,
|
|
};
|
|
use itertools::Itertools;
|
|
use parse::{
|
|
ExplicitRuntimeDeclaration, ImplicitRuntimeDeclaration, Pallet, RuntimeDeclaration,
|
|
WhereSection,
|
|
};
|
|
use proc_macro::TokenStream;
|
|
use proc_macro2::TokenStream as TokenStream2;
|
|
use quote::quote;
|
|
use std::{collections::HashSet, str::FromStr};
|
|
use syn::{Ident, Result};
|
|
|
|
/// The fixed name of the system pallet.
|
|
const SYSTEM_PALLET_NAME: &str = "System";
|
|
|
|
/// Implementation of `construct_runtime` macro. Either expand to some code which will call
|
|
/// `construct_runtime` again, or expand to the final runtime definition.
|
|
pub fn construct_runtime(input: TokenStream) -> TokenStream {
|
|
let input_copy = input.clone();
|
|
let definition = syn::parse_macro_input!(input as RuntimeDeclaration);
|
|
|
|
let res = match definition {
|
|
RuntimeDeclaration::Implicit(implicit_def) =>
|
|
construct_runtime_intermediary_expansion(input_copy.into(), implicit_def),
|
|
RuntimeDeclaration::Explicit(explicit_decl) =>
|
|
construct_runtime_final_expansion(explicit_decl),
|
|
};
|
|
|
|
res.unwrap_or_else(|e| e.to_compile_error()).into()
|
|
}
|
|
|
|
/// When some pallet have implicit parts definition then the macro will expand into a macro call to
|
|
/// `construct_runtime_args` of each pallets, see root documentation.
|
|
fn construct_runtime_intermediary_expansion(
|
|
input: TokenStream2,
|
|
definition: ImplicitRuntimeDeclaration,
|
|
) -> Result<TokenStream2> {
|
|
let frame_support = generate_crate_access_2018("frame-support")?;
|
|
let mut expansion = quote::quote!(
|
|
#frame_support::construct_runtime! { #input }
|
|
);
|
|
for pallet in definition.pallets.iter().filter(|pallet| pallet.pallet_parts.is_none()) {
|
|
let pallet_path = &pallet.path;
|
|
let pallet_name = &pallet.name;
|
|
let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(::<#instance>));
|
|
expansion = quote::quote!(
|
|
#frame_support::tt_call! {
|
|
macro = [{ #pallet_path::tt_default_parts }]
|
|
frame_support = [{ #frame_support }]
|
|
~~> #frame_support::match_and_insert! {
|
|
target = [{ #expansion }]
|
|
pattern = [{ #pallet_name: #pallet_path #pallet_instance }]
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
Ok(expansion)
|
|
}
|
|
|
|
/// All pallets have explicit definition of parts, this will expand to the runtime declaration.
|
|
fn construct_runtime_final_expansion(
|
|
definition: ExplicitRuntimeDeclaration,
|
|
) -> Result<TokenStream2> {
|
|
let ExplicitRuntimeDeclaration {
|
|
name,
|
|
where_section: WhereSection { block, node_block, unchecked_extrinsic },
|
|
pallets,
|
|
pallets_token,
|
|
} = definition;
|
|
|
|
let system_pallet =
|
|
pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| {
|
|
syn::Error::new(
|
|
pallets_token.span,
|
|
"`System` pallet declaration is missing. \
|
|
Please add this line: `System: frame_system::{Pallet, Call, Storage, Config, Event<T>},`",
|
|
)
|
|
})?;
|
|
if !system_pallet.cfg_pattern.is_empty() {
|
|
return Err(syn::Error::new(
|
|
system_pallet.name.span(),
|
|
"`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes",
|
|
))
|
|
}
|
|
|
|
let features = pallets
|
|
.iter()
|
|
.filter_map(|decl| {
|
|
(!decl.cfg_pattern.is_empty()).then(|| {
|
|
decl.cfg_pattern.iter().flat_map(|attr| {
|
|
attr.predicates().filter_map(|pred| match pred {
|
|
Predicate::Feature(feat) => Some(feat),
|
|
Predicate::Test => Some("test"),
|
|
_ => None,
|
|
})
|
|
})
|
|
})
|
|
})
|
|
.flatten()
|
|
.collect::<HashSet<_>>();
|
|
|
|
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");
|
|
|
|
let outer_event = expand::expand_outer_event(&name, &pallets, &scrate)?;
|
|
|
|
let outer_origin = expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?;
|
|
let all_pallets = decl_all_pallets(&name, pallets.iter(), &features);
|
|
let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate);
|
|
|
|
let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate);
|
|
let metadata = expand::expand_runtime_metadata(&name, &pallets, &scrate, &unchecked_extrinsic);
|
|
let outer_config = expand::expand_outer_config(&name, &pallets, &scrate);
|
|
let inherent =
|
|
expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
|
|
let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
|
|
let integrity_test = decl_integrity_test(&scrate);
|
|
let static_assertions = decl_static_assertions(&name, &pallets, &scrate);
|
|
|
|
let res = quote!(
|
|
#scrate_decl
|
|
|
|
// Prevent UncheckedExtrinsic to print unused warning.
|
|
const _: () = {
|
|
#[allow(unused)]
|
|
type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic;
|
|
};
|
|
|
|
#[derive(
|
|
Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug,
|
|
#scrate::scale_info::TypeInfo
|
|
)]
|
|
pub struct #name;
|
|
impl #scrate::sp_runtime::traits::GetNodeBlockType for #name {
|
|
type NodeBlock = #node_block;
|
|
}
|
|
impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name {
|
|
type RuntimeBlock = #block;
|
|
}
|
|
|
|
#outer_event
|
|
|
|
#outer_origin
|
|
|
|
#all_pallets
|
|
|
|
#pallet_to_index
|
|
|
|
#dispatch
|
|
|
|
#metadata
|
|
|
|
#outer_config
|
|
|
|
#inherent
|
|
|
|
#validate_unsigned
|
|
|
|
#integrity_test
|
|
|
|
#static_assertions
|
|
);
|
|
|
|
Ok(res)
|
|
}
|
|
|
|
fn decl_all_pallets<'a>(
|
|
runtime: &'a Ident,
|
|
pallet_declarations: impl Iterator<Item = &'a Pallet>,
|
|
features: &HashSet<&str>,
|
|
) -> TokenStream2 {
|
|
let mut types = TokenStream2::new();
|
|
|
|
// Every feature set to the pallet names that should be included by this feature set.
|
|
let mut features_to_names = features
|
|
.iter()
|
|
.map(|f| *f)
|
|
.powerset()
|
|
.map(|feat| (HashSet::from_iter(feat), Vec::new()))
|
|
.collect::<Vec<(HashSet<_>, Vec<_>)>>();
|
|
|
|
for pallet_declaration in pallet_declarations {
|
|
let type_name = &pallet_declaration.name;
|
|
let pallet = &pallet_declaration.path;
|
|
let mut generics = vec![quote!(#runtime)];
|
|
generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name)));
|
|
let mut attrs = Vec::new();
|
|
for cfg in &pallet_declaration.cfg_pattern {
|
|
let feat = format!("#[cfg({})]\n", cfg.original());
|
|
attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed"));
|
|
}
|
|
let type_decl = quote!(
|
|
#(#attrs)*
|
|
pub type #type_name = #pallet::Pallet <#(#generics),*>;
|
|
);
|
|
types.extend(type_decl);
|
|
|
|
if pallet_declaration.cfg_pattern.is_empty() {
|
|
for (_, names) in features_to_names.iter_mut() {
|
|
names.push(&pallet_declaration.name);
|
|
}
|
|
} else {
|
|
for (feature_set, names) in &mut features_to_names {
|
|
// Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the
|
|
// predicates listed in all `#[cfg]` attributes are effectively joined by `and()`,
|
|
// meaning that all of them must match in order to activate the item
|
|
let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| {
|
|
expr.eval(|pred| match pred {
|
|
Predicate::Feature(f) => feature_set.contains(f),
|
|
Predicate::Test => feature_set.contains(&"test"),
|
|
_ => false,
|
|
})
|
|
});
|
|
|
|
if is_feature_active {
|
|
names.push(&pallet_declaration.name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// All possible features. This will be used below for the empty feature set.
|
|
let mut all_features = features_to_names
|
|
.iter()
|
|
.flat_map(|f| f.0.iter().cloned())
|
|
.collect::<HashSet<_>>();
|
|
let attribute_to_names = features_to_names
|
|
.into_iter()
|
|
.map(|(mut features, names)| {
|
|
// If this is the empty feature set, it needs to be changed to negate all available
|
|
// features. So, we ensure that there is some type declared when all features are not
|
|
// enabled.
|
|
if features.is_empty() {
|
|
let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter();
|
|
let features = all_features.iter();
|
|
let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]);
|
|
|
|
(attr, names)
|
|
} else {
|
|
let test_cfg = features.remove("test").then_some(quote!(test)).into_iter();
|
|
let features = features.iter();
|
|
let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #features),* ))]);
|
|
|
|
(attr, names)
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| {
|
|
let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME);
|
|
quote! {
|
|
#attr
|
|
/// All pallets included in the runtime as a nested tuple of types.
|
|
/// Excludes the System pallet.
|
|
pub type AllPalletsWithoutSystem = ( #(#names,)* );
|
|
}
|
|
});
|
|
|
|
let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| {
|
|
quote! {
|
|
#attr
|
|
/// All pallets included in the runtime as a nested tuple of types.
|
|
pub type AllPalletsWithSystem = ( #(#names,)* );
|
|
}
|
|
});
|
|
|
|
let all_pallets_without_system_reversed = attribute_to_names.iter().map(|(attr, names)| {
|
|
let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev();
|
|
quote! {
|
|
#attr
|
|
/// All pallets included in the runtime as a nested tuple of types in reversed order.
|
|
/// Excludes the System pallet.
|
|
#[deprecated(note = "Using reverse pallet orders is deprecated. use only \
|
|
`AllPalletWithSystem or AllPalletsWithoutSystem`")]
|
|
pub type AllPalletsWithoutSystemReversed = ( #(#names,)* );
|
|
}
|
|
});
|
|
|
|
let all_pallets_with_system_reversed = attribute_to_names.iter().map(|(attr, names)| {
|
|
let names = names.iter().rev();
|
|
quote! {
|
|
#attr
|
|
/// All pallets included in the runtime as a nested tuple of types in reversed order.
|
|
#[deprecated(note = "Using reverse pallet orders is deprecated. use only \
|
|
`AllPalletWithSystem or AllPalletsWithoutSystem`")]
|
|
pub type AllPalletsWithSystemReversed = ( #(#names,)* );
|
|
}
|
|
});
|
|
|
|
let all_pallets_reversed_with_system_first = attribute_to_names.iter().map(|(attr, names)| {
|
|
let system = quote::format_ident!("{}", SYSTEM_PALLET_NAME);
|
|
let names = std::iter::once(&system)
|
|
.chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME).cloned());
|
|
quote! {
|
|
#attr
|
|
/// All pallets included in the runtime as a nested tuple of types in reversed order.
|
|
/// With the system pallet first.
|
|
#[deprecated(note = "Using reverse pallet orders is deprecated. use only \
|
|
`AllPalletWithSystem or AllPalletsWithoutSystem`")]
|
|
pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* );
|
|
}
|
|
});
|
|
|
|
quote!(
|
|
#types
|
|
|
|
/// All pallets included in the runtime as a nested tuple of types.
|
|
#[deprecated(note = "The type definition has changed from representing all pallets \
|
|
excluding system, in reversed order to become the representation of all pallets \
|
|
including system pallet in regular order. For this reason it is encouraged to use \
|
|
explicitly one of `AllPalletsWithSystem`, `AllPalletsWithoutSystem`, \
|
|
`AllPalletsWithSystemReversed`, `AllPalletsWithoutSystemReversed`. \
|
|
Note that the type `frame_executive::Executive` expects one of `AllPalletsWithSystem` \
|
|
, `AllPalletsWithSystemReversed`, `AllPalletsReversedWithSystemFirst`. More details in \
|
|
https://github.com/paritytech/substrate/pull/10043")]
|
|
pub type AllPallets = AllPalletsWithSystem;
|
|
|
|
#( #all_pallets_with_system )*
|
|
|
|
#( #all_pallets_without_system )*
|
|
|
|
#( #all_pallets_with_system_reversed )*
|
|
|
|
#( #all_pallets_without_system_reversed )*
|
|
|
|
#( #all_pallets_reversed_with_system_first )*
|
|
)
|
|
}
|
|
|
|
fn decl_pallet_runtime_setup(
|
|
runtime: &Ident,
|
|
pallet_declarations: &[Pallet],
|
|
scrate: &TokenStream2,
|
|
) -> TokenStream2 {
|
|
let names = pallet_declarations.iter().map(|d| &d.name).collect::<Vec<_>>();
|
|
let name_strings = pallet_declarations.iter().map(|d| d.name.to_string());
|
|
let module_names = pallet_declarations.iter().map(|d| d.path.module_name());
|
|
let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize);
|
|
let pallet_structs = pallet_declarations
|
|
.iter()
|
|
.map(|pallet| {
|
|
let path = &pallet.path;
|
|
match pallet.instance.as_ref() {
|
|
Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>),
|
|
None => quote!(#path::Pallet<#runtime>),
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
let pallet_attrs = pallet_declarations
|
|
.iter()
|
|
.map(|pallet| {
|
|
pallet.cfg_pattern.iter().fold(TokenStream2::new(), |acc, pattern| {
|
|
let attr = TokenStream2::from_str(&format!("#[cfg({})]", pattern.original()))
|
|
.expect("was successfully parsed before; qed");
|
|
quote! {
|
|
#acc
|
|
#attr
|
|
}
|
|
})
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
quote!(
|
|
/// Provides an implementation of `PalletInfo` to provide information
|
|
/// about the pallet setup in the runtime.
|
|
pub struct PalletInfo;
|
|
|
|
impl #scrate::traits::PalletInfo for PalletInfo {
|
|
fn index<P: 'static>() -> Option<usize> {
|
|
let type_id = #scrate::sp_std::any::TypeId::of::<P>();
|
|
#(
|
|
#pallet_attrs
|
|
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
|
|
return Some(#indices)
|
|
}
|
|
)*
|
|
|
|
None
|
|
}
|
|
|
|
fn name<P: 'static>() -> Option<&'static str> {
|
|
let type_id = #scrate::sp_std::any::TypeId::of::<P>();
|
|
#(
|
|
#pallet_attrs
|
|
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
|
|
return Some(#name_strings)
|
|
}
|
|
)*
|
|
|
|
None
|
|
}
|
|
|
|
fn module_name<P: 'static>() -> Option<&'static str> {
|
|
let type_id = #scrate::sp_std::any::TypeId::of::<P>();
|
|
#(
|
|
#pallet_attrs
|
|
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
|
|
return Some(#module_names)
|
|
}
|
|
)*
|
|
|
|
None
|
|
}
|
|
|
|
fn crate_version<P: 'static>() -> Option<#scrate::traits::CrateVersion> {
|
|
let type_id = #scrate::sp_std::any::TypeId::of::<P>();
|
|
#(
|
|
#pallet_attrs
|
|
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
|
|
return Some(
|
|
<#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version()
|
|
)
|
|
}
|
|
)*
|
|
|
|
None
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 {
|
|
quote!(
|
|
#[cfg(test)]
|
|
mod __construct_runtime_integrity_test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
pub fn runtime_integrity_tests() {
|
|
<AllPalletsWithSystem as #scrate::traits::IntegrityTest>::integrity_test();
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
fn decl_static_assertions(
|
|
runtime: &Ident,
|
|
pallet_decls: &[Pallet],
|
|
scrate: &TokenStream2,
|
|
) -> TokenStream2 {
|
|
let error_encoded_size_check = pallet_decls.iter().map(|decl| {
|
|
let path = &decl.path;
|
|
let assert_message = format!(
|
|
"The maximum encoded size of the error type in the `{}` pallet exceeds \
|
|
`MAX_MODULE_ERROR_ENCODED_SIZE`",
|
|
decl.name,
|
|
);
|
|
|
|
quote! {
|
|
#scrate::tt_call! {
|
|
macro = [{ #path::tt_error_token }]
|
|
frame_support = [{ #scrate }]
|
|
~~> #scrate::assert_error_encoded_size! {
|
|
path = [{ #path }]
|
|
runtime = [{ #runtime }]
|
|
assert_message = [{ #assert_message }]
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
quote! {
|
|
#(#error_encoded_size_check)*
|
|
}
|
|
}
|