mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 15:11:03 +00:00
Automatic pallet parts in construct_runtime (#9681)
* implement automatic parts * ui tests * rename * remove unnecessary exclude * better doc * better doc * fix genesis config * fix UI tests * fix UI test * Revert "fix UI test" This reverts commit a910351c0b24cfe42195cfd97d83a416640e3259. * implemented used_parts * Update frame/support/procedural/src/construct_runtime/mod.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * doc + fmt * Update frame/support/procedural/src/construct_runtime/parse.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * add doc in the macro * remove yet some more parts * fix ui test * more determnistic error message + fix ui tests * fix ui test * Apply suggestions from code review Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * do refactor + fix ui tests * fmt * fix test * fix test * fix ui test * Apply suggestions from code review Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * refactor * remove even more part in node-runtime * fix test * Add flow chart for the construct_runtime! execution flow * Fix typo * Ignore snippets that don't contain code * Refactor some code in expand_after * Rename expand_after to match_and_insert * cargo fmt * Fix rename * Remove frame_support argument to construct_runtime_parts * Make use of tt-call to simplify intermediate expansions * cargo fmt * Update match_and_insert documentation * Reset cursor to 0 when no matching patterns are found * Reorder struct fields on MatchAndInsertDef * Add test for dependency renames and fix frame-support import * Add more doc comments * Update frame/support/test/compile_pass/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
committed by
GitHub
parent
0214fde9a6
commit
4292e18e50
Generated
+20
@@ -2058,6 +2058,7 @@ dependencies = [
|
|||||||
"sp-state-machine",
|
"sp-state-machine",
|
||||||
"sp-std",
|
"sp-std",
|
||||||
"sp-tracing",
|
"sp-tracing",
|
||||||
|
"tt-call",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2113,6 +2114,19 @@ dependencies = [
|
|||||||
"trybuild",
|
"trybuild",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "frame-support-test-compile-pass"
|
||||||
|
version = "4.0.0-dev"
|
||||||
|
dependencies = [
|
||||||
|
"frame-support",
|
||||||
|
"frame-system",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"scale-info",
|
||||||
|
"sp-core",
|
||||||
|
"sp-runtime",
|
||||||
|
"sp-version",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-support-test-pallet"
|
name = "frame-support-test-pallet"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
@@ -10803,6 +10817,12 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tt-call"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "twox-hash"
|
name = "twox-hash"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ members = [
|
|||||||
"frame/support/procedural/tools",
|
"frame/support/procedural/tools",
|
||||||
"frame/support/procedural/tools/derive",
|
"frame/support/procedural/tools/derive",
|
||||||
"frame/support/test",
|
"frame/support/test",
|
||||||
|
"frame/support/test/compile_pass",
|
||||||
"frame/system",
|
"frame/system",
|
||||||
"frame/system/benchmarking",
|
"frame/system/benchmarking",
|
||||||
"frame/system/rpc/runtime-api",
|
"frame/system/rpc/runtime-api",
|
||||||
@@ -271,4 +272,4 @@ yamux = { opt-level = 3 }
|
|||||||
zeroize = { opt-level = 3 }
|
zeroize = { opt-level = 3 }
|
||||||
[profile.release]
|
[profile.release]
|
||||||
# Substrate runtime requires unwinding.
|
# Substrate runtime requires unwinding.
|
||||||
panic = "unwind"
|
panic = "unwind"
|
||||||
|
|||||||
@@ -364,6 +364,8 @@ pub fn testnet_genesis(
|
|||||||
assets: Default::default(),
|
assets: Default::default(),
|
||||||
gilt: Default::default(),
|
gilt: Default::default(),
|
||||||
transaction_storage: Default::default(),
|
transaction_storage: Default::default(),
|
||||||
|
scheduler: Default::default(),
|
||||||
|
transaction_payment: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1248,47 +1248,47 @@ construct_runtime!(
|
|||||||
NodeBlock = node_primitives::Block,
|
NodeBlock = node_primitives::Block,
|
||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
{
|
{
|
||||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
System: frame_system,
|
||||||
Utility: pallet_utility::{Pallet, Call, Event},
|
Utility: pallet_utility,
|
||||||
Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned},
|
Babe: pallet_babe,
|
||||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
|
Timestamp: pallet_timestamp,
|
||||||
Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent},
|
Authorship: pallet_authorship,
|
||||||
Indices: pallet_indices::{Pallet, Call, Storage, Config<T>, Event<T>},
|
Indices: pallet_indices,
|
||||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
Balances: pallet_balances,
|
||||||
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
|
TransactionPayment: pallet_transaction_payment,
|
||||||
ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event<T>, ValidateUnsigned},
|
ElectionProviderMultiPhase: pallet_election_provider_multi_phase,
|
||||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
Staking: pallet_staking,
|
||||||
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
|
Session: pallet_session,
|
||||||
Democracy: pallet_democracy::{Pallet, Call, Storage, Config<T>, Event<T>},
|
Democracy: pallet_democracy,
|
||||||
Council: pallet_collective::<Instance1>::{Pallet, Call, Storage, Origin<T>, Event<T>, Config<T>},
|
Council: pallet_collective::<Instance1>,
|
||||||
TechnicalCommittee: pallet_collective::<Instance2>::{Pallet, Call, Storage, Origin<T>, Event<T>, Config<T>},
|
TechnicalCommittee: pallet_collective::<Instance2>,
|
||||||
Elections: pallet_elections_phragmen::{Pallet, Call, Storage, Event<T>, Config<T>},
|
Elections: pallet_elections_phragmen,
|
||||||
TechnicalMembership: pallet_membership::<Instance1>::{Pallet, Call, Storage, Event<T>, Config<T>},
|
TechnicalMembership: pallet_membership::<Instance1>,
|
||||||
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned},
|
Grandpa: pallet_grandpa,
|
||||||
Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>},
|
Treasury: pallet_treasury,
|
||||||
Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>},
|
Contracts: pallet_contracts,
|
||||||
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
|
Sudo: pallet_sudo,
|
||||||
ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
|
ImOnline: pallet_im_online,
|
||||||
AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config},
|
AuthorityDiscovery: pallet_authority_discovery,
|
||||||
Offences: pallet_offences::{Pallet, Storage, Event},
|
Offences: pallet_offences,
|
||||||
Historical: pallet_session_historical::{Pallet},
|
Historical: pallet_session_historical::{Pallet},
|
||||||
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
|
RandomnessCollectiveFlip: pallet_randomness_collective_flip,
|
||||||
Identity: pallet_identity::{Pallet, Call, Storage, Event<T>},
|
Identity: pallet_identity,
|
||||||
Society: pallet_society::{Pallet, Call, Storage, Event<T>, Config<T>},
|
Society: pallet_society,
|
||||||
Recovery: pallet_recovery::{Pallet, Call, Storage, Event<T>},
|
Recovery: pallet_recovery,
|
||||||
Vesting: pallet_vesting::{Pallet, Call, Storage, Event<T>, Config<T>},
|
Vesting: pallet_vesting,
|
||||||
Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>},
|
Scheduler: pallet_scheduler,
|
||||||
Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>},
|
Proxy: pallet_proxy,
|
||||||
Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>},
|
Multisig: pallet_multisig,
|
||||||
Bounties: pallet_bounties::{Pallet, Call, Storage, Event<T>},
|
Bounties: pallet_bounties,
|
||||||
Tips: pallet_tips::{Pallet, Call, Storage, Event<T>},
|
Tips: pallet_tips,
|
||||||
Assets: pallet_assets::{Pallet, Call, Storage, Event<T>, Config<T>},
|
Assets: pallet_assets,
|
||||||
Mmr: pallet_mmr::{Pallet, Storage},
|
Mmr: pallet_mmr,
|
||||||
Lottery: pallet_lottery::{Pallet, Call, Storage, Event<T>},
|
Lottery: pallet_lottery,
|
||||||
Gilt: pallet_gilt::{Pallet, Call, Storage, Event<T>, Config},
|
Gilt: pallet_gilt,
|
||||||
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>},
|
Uniques: pallet_uniques,
|
||||||
TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Inherent, Config<T>, Event<T>},
|
TransactionStorage: pallet_transaction_storage,
|
||||||
BagsList: pallet_bags_list::{Pallet, Call, Storage, Event<T>},
|
BagsList: pallet_bags_list,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -101,5 +101,7 @@ pub fn config_endowed(
|
|||||||
assets: Default::default(),
|
assets: Default::default(),
|
||||||
gilt: Default::default(),
|
gilt: Default::default(),
|
||||||
transaction_storage: Default::default(),
|
transaction_storage: Default::default(),
|
||||||
|
scheduler: Default::default(),
|
||||||
|
transaction_payment: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ sp-core = { version = "4.0.0-dev", default-features = false, path = "../../primi
|
|||||||
sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" }
|
sp-arithmetic = { version = "4.0.0-dev", default-features = false, path = "../../primitives/arithmetic" }
|
||||||
sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" }
|
sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" }
|
||||||
sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" }
|
sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" }
|
||||||
|
tt-call = "1.0.8"
|
||||||
frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" }
|
frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" }
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
once_cell = { version = "1", default-features = false, optional = true }
|
once_cell = { version = "1", default-features = false, optional = true }
|
||||||
|
|||||||
@@ -15,114 +15,204 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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 expand;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
use frame_support_procedural_tools::{
|
use frame_support_procedural_tools::{
|
||||||
generate_crate_access, generate_hidden_includes, syn_ext as ext,
|
generate_crate_access, generate_crate_access_2018, generate_hidden_includes,
|
||||||
|
};
|
||||||
|
use parse::{
|
||||||
|
ExplicitRuntimeDeclaration, ImplicitRuntimeDeclaration, Pallet, RuntimeDeclaration,
|
||||||
|
WhereSection,
|
||||||
};
|
};
|
||||||
use parse::{PalletDeclaration, PalletPart, PalletPath, RuntimeDefinition, WhereSection};
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use std::collections::HashMap;
|
|
||||||
use syn::{Ident, Result};
|
use syn::{Ident, Result};
|
||||||
|
|
||||||
/// The fixed name of the system pallet.
|
/// The fixed name of the system pallet.
|
||||||
const SYSTEM_PALLET_NAME: &str = "System";
|
const SYSTEM_PALLET_NAME: &str = "System";
|
||||||
|
|
||||||
/// The complete definition of a pallet with the resulting fixed index.
|
/// Implementation of `construct_runtime` macro. Either expand to some code which will call
|
||||||
#[derive(Debug, Clone)]
|
/// `construct_runtime` again, or expand to the final runtime definition.
|
||||||
pub struct Pallet {
|
|
||||||
pub name: Ident,
|
|
||||||
pub index: u8,
|
|
||||||
pub path: PalletPath,
|
|
||||||
pub instance: Option<Ident>,
|
|
||||||
pub pallet_parts: Vec<PalletPart>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pallet {
|
|
||||||
/// Get resolved pallet parts
|
|
||||||
fn pallet_parts(&self) -> &[PalletPart] {
|
|
||||||
&self.pallet_parts
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find matching parts
|
|
||||||
fn find_part(&self, name: &str) -> Option<&PalletPart> {
|
|
||||||
self.pallet_parts.iter().find(|part| part.name() == name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return whether pallet contains part
|
|
||||||
fn exists_part(&self, name: &str) -> bool {
|
|
||||||
self.find_part(name).is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert from the parsed pallet to their final information.
|
|
||||||
/// Assign index to each pallet using same rules as rust for fieldless enum.
|
|
||||||
/// I.e. implicit are assigned number incrementedly from last explicit or 0.
|
|
||||||
fn complete_pallets(decl: impl Iterator<Item = PalletDeclaration>) -> syn::Result<Vec<Pallet>> {
|
|
||||||
let mut indices = HashMap::new();
|
|
||||||
let mut last_index: Option<u8> = None;
|
|
||||||
let mut names = HashMap::new();
|
|
||||||
|
|
||||||
decl.map(|pallet| {
|
|
||||||
let final_index = match pallet.index {
|
|
||||||
Some(i) => i,
|
|
||||||
None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| {
|
|
||||||
let msg = "Pallet index doesn't fit into u8, index is 256";
|
|
||||||
syn::Error::new(pallet.name.span(), msg)
|
|
||||||
})?,
|
|
||||||
};
|
|
||||||
|
|
||||||
last_index = Some(final_index);
|
|
||||||
|
|
||||||
if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) {
|
|
||||||
let msg = format!(
|
|
||||||
"Pallet indices are conflicting: Both pallets {} and {} are at index {}",
|
|
||||||
used_pallet, pallet.name, final_index,
|
|
||||||
);
|
|
||||||
let mut err = syn::Error::new(used_pallet.span(), &msg);
|
|
||||||
err.combine(syn::Error::new(pallet.name.span(), msg));
|
|
||||||
return Err(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) {
|
|
||||||
let msg = "Two pallets with the same name!";
|
|
||||||
|
|
||||||
let mut err = syn::Error::new(used_pallet, &msg);
|
|
||||||
err.combine(syn::Error::new(pallet.name.span(), &msg));
|
|
||||||
return Err(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Pallet {
|
|
||||||
name: pallet.name,
|
|
||||||
index: final_index,
|
|
||||||
path: pallet.path,
|
|
||||||
instance: pallet.instance,
|
|
||||||
pallet_parts: pallet.pallet_parts,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn construct_runtime(input: TokenStream) -> TokenStream {
|
pub fn construct_runtime(input: TokenStream) -> TokenStream {
|
||||||
let definition = syn::parse_macro_input!(input as RuntimeDefinition);
|
let input_copy = input.clone();
|
||||||
construct_runtime_parsed(definition)
|
let definition = syn::parse_macro_input!(input as RuntimeDeclaration);
|
||||||
.unwrap_or_else(|e| e.to_compile_error())
|
|
||||||
.into()
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream2> {
|
/// When some pallet have implicit parts definition then the macro will expand into a macro call to
|
||||||
let RuntimeDefinition {
|
/// `construct_runtime_args` of each pallets, see root documentation.
|
||||||
name,
|
fn construct_runtime_intermediary_expansion(
|
||||||
where_section: WhereSection { block, node_block, unchecked_extrinsic, .. },
|
input: TokenStream2,
|
||||||
pallets:
|
definition: ImplicitRuntimeDeclaration,
|
||||||
ext::Braces { content: ext::Punctuated { inner: pallets, .. }, token: pallets_token },
|
) -> Result<TokenStream2> {
|
||||||
..
|
let frame_support = generate_crate_access_2018("frame-support")?;
|
||||||
} = definition;
|
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 }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let pallets = complete_pallets(pallets.into_iter())?;
|
Ok(expansion.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 hidden_crate_name = "construct_runtime";
|
let hidden_crate_name = "construct_runtime";
|
||||||
let scrate = generate_crate_access(&hidden_crate_name, "frame-support");
|
let scrate = generate_crate_access(&hidden_crate_name, "frame-support");
|
||||||
|
|||||||
@@ -17,13 +17,13 @@
|
|||||||
|
|
||||||
use frame_support_procedural_tools::syn_ext as ext;
|
use frame_support_procedural_tools::syn_ext as ext;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashMap, HashSet};
|
||||||
use syn::{
|
use syn::{
|
||||||
ext::IdentExt,
|
ext::IdentExt,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token, Error, Ident, Path, PathArguments, PathSegment, Result, Token,
|
token, Error, Ident, Path, Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod keyword {
|
mod keyword {
|
||||||
@@ -38,26 +38,63 @@ mod keyword {
|
|||||||
syn::custom_keyword!(Origin);
|
syn::custom_keyword!(Origin);
|
||||||
syn::custom_keyword!(Inherent);
|
syn::custom_keyword!(Inherent);
|
||||||
syn::custom_keyword!(ValidateUnsigned);
|
syn::custom_keyword!(ValidateUnsigned);
|
||||||
|
syn::custom_keyword!(exclude_parts);
|
||||||
|
syn::custom_keyword!(use_parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declaration of a runtime.
|
||||||
|
///
|
||||||
|
/// Pallet declare their part either explicitly or implicitly (using no part declaration)
|
||||||
|
/// If all pallet have explicit parts then the runtime declaration is explicit, otherwise it is
|
||||||
|
/// implicit.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RuntimeDefinition {
|
pub enum RuntimeDeclaration {
|
||||||
pub visibility_token: Token![pub],
|
Implicit(ImplicitRuntimeDeclaration),
|
||||||
pub enum_token: Token![enum],
|
Explicit(ExplicitRuntimeDeclaration),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declaration of a runtime with some pallet with implicit declaration of parts.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ImplicitRuntimeDeclaration {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub where_section: WhereSection,
|
pub where_section: WhereSection,
|
||||||
pub pallets: ext::Braces<ext::Punctuated<PalletDeclaration, Token![,]>>,
|
pub pallets: Vec<PalletDeclaration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for RuntimeDefinition {
|
/// Declaration of a runtime with all pallet having explicit declaration of parts.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ExplicitRuntimeDeclaration {
|
||||||
|
pub name: Ident,
|
||||||
|
pub where_section: WhereSection,
|
||||||
|
pub pallets: Vec<Pallet>,
|
||||||
|
pub pallets_token: token::Brace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for RuntimeDeclaration {
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
Ok(Self {
|
input.parse::<Token![pub]>()?;
|
||||||
visibility_token: input.parse()?,
|
input.parse::<Token![enum]>()?;
|
||||||
enum_token: input.parse()?,
|
let name = input.parse::<syn::Ident>()?;
|
||||||
name: input.parse()?,
|
let where_section = input.parse()?;
|
||||||
where_section: input.parse()?,
|
let pallets =
|
||||||
pallets: input.parse()?,
|
input.parse::<ext::Braces<ext::Punctuated<PalletDeclaration, Token![,]>>>()?;
|
||||||
})
|
let pallets_token = pallets.token;
|
||||||
|
|
||||||
|
match convert_pallets(pallets.content.inner.into_iter().collect())? {
|
||||||
|
PalletsConversion::Implicit(pallets) =>
|
||||||
|
Ok(RuntimeDeclaration::Implicit(ImplicitRuntimeDeclaration {
|
||||||
|
name,
|
||||||
|
where_section,
|
||||||
|
pallets,
|
||||||
|
})),
|
||||||
|
PalletsConversion::Explicit(pallets) =>
|
||||||
|
Ok(RuntimeDeclaration::Explicit(ExplicitRuntimeDeclaration {
|
||||||
|
name,
|
||||||
|
where_section,
|
||||||
|
pallets,
|
||||||
|
pallets_token,
|
||||||
|
})),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,14 +173,34 @@ impl Parse for WhereDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The declaration of a pallet.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PalletDeclaration {
|
pub struct PalletDeclaration {
|
||||||
|
/// The name of the pallet, e.g.`System` in `System: frame_system`.
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
/// Optional fixed index (e.g. `MyPallet ... = 3,`)
|
/// Optional fixed index, e.g. `MyPallet ... = 3,`.
|
||||||
pub index: Option<u8>,
|
pub index: Option<u8>,
|
||||||
|
/// The path of the pallet, e.g. `frame_system` in `System: frame_system`.
|
||||||
pub path: PalletPath,
|
pub path: PalletPath,
|
||||||
|
/// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::<Instance1>`.
|
||||||
pub instance: Option<Ident>,
|
pub instance: Option<Ident>,
|
||||||
pub pallet_parts: Vec<PalletPart>,
|
/// The declared pallet parts,
|
||||||
|
/// e.g. `Some([Pallet, Call])` for `System: system::{Pallet, Call}`
|
||||||
|
/// or `None` for `System: system`.
|
||||||
|
pub pallet_parts: Option<Vec<PalletPart>>,
|
||||||
|
/// The specified parts, either use_parts or exclude_parts.
|
||||||
|
pub specified_parts: SpecifiedParts,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The possible declaration of pallet parts to use.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SpecifiedParts {
|
||||||
|
/// Use all the pallet parts except those specified.
|
||||||
|
Exclude(Vec<PalletPartNoGeneric>),
|
||||||
|
/// Use only the specified pallet parts.
|
||||||
|
Use(Vec<PalletPartNoGeneric>),
|
||||||
|
/// Use the all the pallet parts.
|
||||||
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for PalletDeclaration {
|
impl Parse for PalletDeclaration {
|
||||||
@@ -151,38 +208,78 @@ impl Parse for PalletDeclaration {
|
|||||||
let name = input.parse()?;
|
let name = input.parse()?;
|
||||||
let _: Token![:] = input.parse()?;
|
let _: Token![:] = input.parse()?;
|
||||||
let path = input.parse()?;
|
let path = input.parse()?;
|
||||||
let instance = if input.peek(Token![<]) {
|
|
||||||
|
// Parse for instance.
|
||||||
|
let instance = if input.peek(Token![::]) && input.peek3(Token![<]) {
|
||||||
|
let _: Token![::] = input.parse()?;
|
||||||
let _: Token![<] = input.parse()?;
|
let _: Token![<] = input.parse()?;
|
||||||
let res = Some(input.parse()?);
|
let res = Some(input.parse()?);
|
||||||
let _: Token![>] = input.parse()?;
|
let _: Token![>] = input.parse()?;
|
||||||
let _: Token![::] = input.parse()?;
|
|
||||||
res
|
res
|
||||||
|
} else if !(input.peek(Token![::]) && input.peek3(token::Brace)) &&
|
||||||
|
!input.peek(keyword::exclude_parts) &&
|
||||||
|
!input.peek(keyword::use_parts) &&
|
||||||
|
!input.peek(Token![=]) &&
|
||||||
|
!input.peek(Token![,]) &&
|
||||||
|
!input.is_empty()
|
||||||
|
{
|
||||||
|
return Err(input.error(
|
||||||
|
"Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`",
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let pallet_parts = parse_pallet_parts(input)?;
|
// Parse for explicit parts
|
||||||
|
let pallet_parts = if input.peek(Token![::]) && input.peek3(token::Brace) {
|
||||||
|
let _: Token![::] = input.parse()?;
|
||||||
|
Some(parse_pallet_parts(input)?)
|
||||||
|
} else if !input.peek(keyword::exclude_parts) &&
|
||||||
|
!input.peek(keyword::use_parts) &&
|
||||||
|
!input.peek(Token![=]) &&
|
||||||
|
!input.peek(Token![,]) &&
|
||||||
|
!input.is_empty()
|
||||||
|
{
|
||||||
|
return Err(input.error(
|
||||||
|
"Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`",
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse for specified parts
|
||||||
|
let specified_parts = if input.peek(keyword::exclude_parts) {
|
||||||
|
let _: keyword::exclude_parts = input.parse()?;
|
||||||
|
SpecifiedParts::Exclude(parse_pallet_parts_no_generic(input)?)
|
||||||
|
} else if input.peek(keyword::use_parts) {
|
||||||
|
let _: keyword::use_parts = input.parse()?;
|
||||||
|
SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?)
|
||||||
|
} else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() {
|
||||||
|
return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`"))
|
||||||
|
} else {
|
||||||
|
SpecifiedParts::All
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse for pallet index
|
||||||
let index = if input.peek(Token![=]) {
|
let index = if input.peek(Token![=]) {
|
||||||
input.parse::<Token![=]>()?;
|
input.parse::<Token![=]>()?;
|
||||||
let index = input.parse::<syn::LitInt>()?;
|
let index = input.parse::<syn::LitInt>()?;
|
||||||
let index = index.base10_parse::<u8>()?;
|
let index = index.base10_parse::<u8>()?;
|
||||||
Some(index)
|
Some(index)
|
||||||
|
} else if !input.peek(Token![,]) && !input.is_empty() {
|
||||||
|
return Err(input.error("Unexpected tokens, expected one of `=`, `,`"))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let parsed = Self { name, path, instance, pallet_parts, index };
|
Ok(Self { name, path, instance, pallet_parts, specified_parts, index })
|
||||||
|
|
||||||
Ok(parsed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard
|
/// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard
|
||||||
/// Rust path with a few restrictions:
|
/// Rust path with a few restrictions:
|
||||||
/// - No leading colons allowed
|
/// - No leading colons allowed
|
||||||
/// - Path segments can only consist of identifers; angle-bracketed or parenthesized segments will
|
/// - Path segments can only consist of identifers separated by colons
|
||||||
/// result in a parsing error (except when specifying instances)
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PalletPath {
|
pub struct PalletPath {
|
||||||
pub inner: Path,
|
pub inner: Path,
|
||||||
@@ -202,34 +299,27 @@ impl PalletPath {
|
|||||||
|
|
||||||
impl Parse for PalletPath {
|
impl Parse for PalletPath {
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
let mut lookahead = input.lookahead1();
|
let mut res =
|
||||||
let mut segments = Punctuated::new();
|
PalletPath { inner: Path { leading_colon: None, segments: Punctuated::new() } };
|
||||||
|
|
||||||
|
let lookahead = input.lookahead1();
|
||||||
if lookahead.peek(Token![crate]) ||
|
if lookahead.peek(Token![crate]) ||
|
||||||
lookahead.peek(Token![self]) ||
|
lookahead.peek(Token![self]) ||
|
||||||
lookahead.peek(Token![super]) ||
|
lookahead.peek(Token![super]) ||
|
||||||
lookahead.peek(Ident)
|
lookahead.peek(Ident)
|
||||||
{
|
{
|
||||||
let ident = input.call(Ident::parse_any)?;
|
let ident = input.call(Ident::parse_any)?;
|
||||||
segments.push(PathSegment { ident, arguments: PathArguments::None });
|
res.inner.segments.push(ident.into());
|
||||||
let _: Token![::] = input.parse()?;
|
|
||||||
lookahead = input.lookahead1();
|
|
||||||
} else {
|
} else {
|
||||||
return Err(lookahead.error())
|
return Err(lookahead.error())
|
||||||
}
|
}
|
||||||
|
|
||||||
while lookahead.peek(Ident) {
|
while input.peek(Token![::]) && input.peek3(Ident) {
|
||||||
let ident = input.parse()?;
|
input.parse::<Token![::]>()?;
|
||||||
segments.push(PathSegment { ident, arguments: PathArguments::None });
|
let ident = input.parse::<Ident>()?;
|
||||||
let _: Token![::] = input.parse()?;
|
res.inner.segments.push(ident.into());
|
||||||
lookahead = input.lookahead1();
|
|
||||||
}
|
}
|
||||||
|
Ok(res)
|
||||||
if !lookahead.peek(token::Brace) && !lookahead.peek(Token![<]) {
|
|
||||||
return Err(lookahead.error())
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self { inner: Path { leading_colon: None, segments } })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,3 +481,174 @@ fn remove_kind(
|
|||||||
Err(input.error(msg))
|
Err(input.error(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The declaration of a part without its generics
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PalletPartNoGeneric {
|
||||||
|
keyword: PalletPartKeyword,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for PalletPartNoGeneric {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
Ok(Self { keyword: input.parse()? })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse [`PalletPartNoGeneric`]'s from a braces enclosed list that is split by commas, e.g.
|
||||||
|
///
|
||||||
|
/// `{ Call, Event }`
|
||||||
|
fn parse_pallet_parts_no_generic(input: ParseStream) -> Result<Vec<PalletPartNoGeneric>> {
|
||||||
|
let pallet_parts: ext::Braces<ext::Punctuated<PalletPartNoGeneric, Token![,]>> =
|
||||||
|
input.parse()?;
|
||||||
|
|
||||||
|
let mut resolved = HashSet::new();
|
||||||
|
for part in pallet_parts.content.inner.iter() {
|
||||||
|
if !resolved.insert(part.keyword.name()) {
|
||||||
|
let msg = format!(
|
||||||
|
"`{}` was already declared before. Please remove the duplicate declaration",
|
||||||
|
part.keyword.name(),
|
||||||
|
);
|
||||||
|
return Err(Error::new(part.keyword.span(), msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(pallet_parts.content.inner.into_iter().collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The final definition of a pallet with the resulting fixed index and explicit parts.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Pallet {
|
||||||
|
/// The name of the pallet, e.g.`System` in `System: frame_system`.
|
||||||
|
pub name: Ident,
|
||||||
|
/// Either automatically infered, or defined (e.g. `MyPallet ... = 3,`).
|
||||||
|
pub index: u8,
|
||||||
|
/// The path of the pallet, e.g. `frame_system` in `System: frame_system`.
|
||||||
|
pub path: PalletPath,
|
||||||
|
/// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::<Instance1>`.
|
||||||
|
pub instance: Option<Ident>,
|
||||||
|
/// The pallet parts to use for the pallet.
|
||||||
|
pub pallet_parts: Vec<PalletPart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pallet {
|
||||||
|
/// Get resolved pallet parts
|
||||||
|
pub fn pallet_parts(&self) -> &[PalletPart] {
|
||||||
|
&self.pallet_parts
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find matching parts
|
||||||
|
pub fn find_part(&self, name: &str) -> Option<&PalletPart> {
|
||||||
|
self.pallet_parts.iter().find(|part| part.name() == name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return whether pallet contains part
|
||||||
|
pub fn exists_part(&self, name: &str) -> bool {
|
||||||
|
self.find_part(name).is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Result of a conversion of a declaration of pallets.
|
||||||
|
enum PalletsConversion {
|
||||||
|
Implicit(Vec<PalletDeclaration>),
|
||||||
|
Explicit(Vec<Pallet>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from the parsed pallet declaration to their final information.
|
||||||
|
///
|
||||||
|
/// Check if all pallet have explicit declaration of their parts, if so then assign index to each
|
||||||
|
/// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number
|
||||||
|
/// incrementedly from last explicit or 0.
|
||||||
|
fn convert_pallets(pallets: Vec<PalletDeclaration>) -> syn::Result<PalletsConversion> {
|
||||||
|
if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) {
|
||||||
|
return Ok(PalletsConversion::Implicit(pallets))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut indices = HashMap::new();
|
||||||
|
let mut last_index: Option<u8> = None;
|
||||||
|
let mut names = HashMap::new();
|
||||||
|
|
||||||
|
let pallets = pallets
|
||||||
|
.into_iter()
|
||||||
|
.map(|pallet| {
|
||||||
|
let final_index = match pallet.index {
|
||||||
|
Some(i) => i,
|
||||||
|
None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| {
|
||||||
|
let msg = "Pallet index doesn't fit into u8, index is 256";
|
||||||
|
syn::Error::new(pallet.name.span(), msg)
|
||||||
|
})?,
|
||||||
|
};
|
||||||
|
|
||||||
|
last_index = Some(final_index);
|
||||||
|
|
||||||
|
if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) {
|
||||||
|
let msg = format!(
|
||||||
|
"Pallet indices are conflicting: Both pallets {} and {} are at index {}",
|
||||||
|
used_pallet, pallet.name, final_index,
|
||||||
|
);
|
||||||
|
let mut err = syn::Error::new(used_pallet.span(), &msg);
|
||||||
|
err.combine(syn::Error::new(pallet.name.span(), msg));
|
||||||
|
return Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) {
|
||||||
|
let msg = "Two pallets with the same name!";
|
||||||
|
|
||||||
|
let mut err = syn::Error::new(used_pallet, &msg);
|
||||||
|
err.combine(syn::Error::new(pallet.name.span(), &msg));
|
||||||
|
return Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pallet_parts = pallet.pallet_parts.expect("Checked above");
|
||||||
|
|
||||||
|
let available_parts =
|
||||||
|
pallet_parts.iter().map(|part| part.keyword.name()).collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
// Check parts are correctly specified
|
||||||
|
match &pallet.specified_parts {
|
||||||
|
SpecifiedParts::Exclude(parts) | SpecifiedParts::Use(parts) =>
|
||||||
|
for part in parts {
|
||||||
|
if !available_parts.contains(part.keyword.name()) {
|
||||||
|
let msg = format!(
|
||||||
|
"Invalid pallet part specified, the pallet `{}` doesn't have the \
|
||||||
|
`{}` part. Available parts are: {}.",
|
||||||
|
pallet.name,
|
||||||
|
part.keyword.name(),
|
||||||
|
pallet_parts.iter().fold(String::new(), |fold, part| {
|
||||||
|
if fold.is_empty() {
|
||||||
|
format!("`{}`", part.keyword.name())
|
||||||
|
} else {
|
||||||
|
format!("{}, `{}`", fold, part.keyword.name())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return Err(syn::Error::new(part.keyword.span(), msg))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SpecifiedParts::All => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set only specified parts.
|
||||||
|
match pallet.specified_parts {
|
||||||
|
SpecifiedParts::Exclude(excluded_parts) => pallet_parts.retain(|part| {
|
||||||
|
!excluded_parts
|
||||||
|
.iter()
|
||||||
|
.any(|excluded_part| excluded_part.keyword.name() == part.keyword.name())
|
||||||
|
}),
|
||||||
|
SpecifiedParts::Use(used_parts) => pallet_parts.retain(|part| {
|
||||||
|
used_parts.iter().any(|use_part| use_part.keyword.name() == part.keyword.name())
|
||||||
|
}),
|
||||||
|
SpecifiedParts::All => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Pallet {
|
||||||
|
name: pallet.name,
|
||||||
|
index: final_index,
|
||||||
|
path: pallet.path,
|
||||||
|
instance: pallet.instance,
|
||||||
|
pallet_parts,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
Ok(PalletsConversion::Explicit(pallets))
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ mod debug_no_bound;
|
|||||||
mod default_no_bound;
|
mod default_no_bound;
|
||||||
mod dummy_part_checker;
|
mod dummy_part_checker;
|
||||||
mod key_prefix;
|
mod key_prefix;
|
||||||
|
mod match_and_insert;
|
||||||
mod pallet;
|
mod pallet;
|
||||||
mod partial_eq_no_bound;
|
mod partial_eq_no_bound;
|
||||||
mod storage;
|
mod storage;
|
||||||
@@ -297,52 +298,91 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
|
|||||||
///
|
///
|
||||||
/// # Example:
|
/// # Example:
|
||||||
///
|
///
|
||||||
/// ```nocompile
|
/// ```ignore
|
||||||
/// construct_runtime!(
|
/// construct_runtime!(
|
||||||
/// pub enum Runtime where
|
/// pub enum Runtime where
|
||||||
/// Block = Block,
|
/// Block = Block,
|
||||||
/// NodeBlock = node::Block,
|
/// NodeBlock = node::Block,
|
||||||
/// UncheckedExtrinsic = UncheckedExtrinsic
|
/// UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
/// {
|
/// {
|
||||||
/// System: system::{Pallet, Call, Event<T>, Config<T>} = 0,
|
/// System: frame_system::{Pallet, Call, Event<T>, Config<T>} = 0,
|
||||||
/// Test: test::{Pallet, Call} = 1,
|
/// Test: path::to::test::{Pallet, Call} = 1,
|
||||||
/// Test2: test_with_long_module::{Pallet, Event<T>},
|
|
||||||
///
|
///
|
||||||
/// // Pallets with instances
|
/// // Pallets with instances
|
||||||
/// Test3_Instance1: test3::<Instance1>::{Pallet, Call, Storage, Event<T, I>, Config<T, I>, Origin<T, I>},
|
/// Test2_Instance1: test2::<Instance1>::{Pallet, Call, Storage, Event<T, I>, Config<T, I>, Origin<T, I>},
|
||||||
/// Test3_DefaultInstance: test3::{Pallet, Call, Storage, Event<T>, Config<T>, Origin<T>} = 4,
|
/// Test2_DefaultInstance: test2::{Pallet, Call, Storage, Event<T>, Config<T>, Origin<T>} = 4,
|
||||||
|
///
|
||||||
|
/// // Pallets declared with `pallet` attribute macro: no need to define the parts
|
||||||
|
/// Test3_Instance1: test3::<Instance1>,
|
||||||
|
/// Test3_DefaultInstance: test3,
|
||||||
|
///
|
||||||
|
/// // with `exclude_parts` keyword some part can be excluded.
|
||||||
|
/// Test4_Instance1: test4::<Instance1> exclude_parts { Call, Origin },
|
||||||
|
/// Test4_DefaultInstance: test4 exclude_parts { Storage },
|
||||||
|
///
|
||||||
|
/// // with `use_parts` keyword, a subset of the pallet parts can be specified.
|
||||||
|
/// Test4_Instance1: test4::<Instance1> use_parts { Pallet, Call},
|
||||||
|
/// Test4_DefaultInstance: test4 use_parts { Pallet },
|
||||||
/// }
|
/// }
|
||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The identifier `System` is the name of the pallet and the lower case identifier `system` is the
|
/// Each pallet is declared as such:
|
||||||
/// name of the Rust module/crate for this Substrate pallet. The identifiers between the braces are
|
/// * `Identifier`: name given to the pallet that uniquely identifies it.
|
||||||
/// the pallet parts provided by the pallet. It is important to list these parts here to export
|
|
||||||
/// them correctly in the metadata or to make the pallet usable in the runtime.
|
|
||||||
///
|
///
|
||||||
/// We provide support for the following module parts in a pallet:
|
/// * `:`: colon separator
|
||||||
///
|
///
|
||||||
/// - `Pallet` - Required for all pallets
|
/// * `path::to::pallet`: identifiers separated by colons which declare the path to a pallet
|
||||||
/// - `Call` - If the pallet has callable functions
|
/// definition.
|
||||||
/// - `Storage` - If the pallet uses storage
|
|
||||||
/// - `Event` or `Event<T>` (if the event is generic) - If the pallet emits events
|
|
||||||
/// - `Origin` or `Origin<T>` (if the origin is generic) - If the pallet has instanciable origins
|
|
||||||
/// - `Config` or `Config<T>` (if the config is generic) - If the pallet builds the genesis storage
|
|
||||||
/// with `GenesisConfig`
|
|
||||||
/// - `Inherent` - If the pallet provides/can check inherents.
|
|
||||||
/// - `ValidateUnsigned` - If the pallet validates unsigned extrinsics.
|
|
||||||
///
|
///
|
||||||
/// `= $n` is an optional part allowing to define at which index the pallet variants in
|
/// * `::<InstanceN>` optional: specify the instance of the pallet to use. If not specified it will
|
||||||
/// `OriginCaller`, `Call` and `Event` are encoded, and to define the ModuleToIndex value.
|
/// use the default instance (or the only instance in case of non-instantiable pallets).
|
||||||
///
|
///
|
||||||
/// if `= $n` is not given, then index is resolved same as fieldless enum in Rust
|
/// * `::{ Part1, Part2<T>, .. }` optional if pallet declared with `frame_support::pallet`: Comma
|
||||||
/// (i.e. incrementedly from previous index):
|
/// separated parts declared with their generic. If a pallet is declared with
|
||||||
/// ```nocompile
|
/// `frame_support::pallet` macro then the parts can be automatically derived if not explicitly
|
||||||
/// pallet1 .. = 2,
|
/// provided. We provide support for the following module parts in a pallet:
|
||||||
/// pallet2 .., // Here pallet2 is given index 3
|
///
|
||||||
/// pallet3 .. = 0,
|
/// - `Pallet` - Required for all pallets
|
||||||
/// pallet4 .., // Here pallet4 is given index 1
|
/// - `Call` - If the pallet has callable functions
|
||||||
/// ```
|
/// - `Storage` - If the pallet uses storage
|
||||||
|
/// - `Event` or `Event<T>` (if the event is generic) - If the pallet emits events
|
||||||
|
/// - `Origin` or `Origin<T>` (if the origin is generic) - If the pallet has instanciable origins
|
||||||
|
/// - `Config` or `Config<T>` (if the config is generic) - If the pallet builds the genesis
|
||||||
|
/// storage with `GenesisConfig`
|
||||||
|
/// - `Inherent` - If the pallet provides/can check inherents.
|
||||||
|
/// - `ValidateUnsigned` - If the pallet validates unsigned extrinsics.
|
||||||
|
///
|
||||||
|
/// It is important to list these parts here to export them correctly in the metadata or to make
|
||||||
|
/// the pallet usable in the runtime.
|
||||||
|
///
|
||||||
|
/// * `exclude_parts { Part1, Part2 }` optional: comma separated parts without generics. I.e. one of
|
||||||
|
/// `Pallet`, `Call`, `Storage`, `Event`, `Origin`, `Config`, `Inherent`, `ValidateUnsigned`. It
|
||||||
|
/// is incompatible with `use_parts`. This specifies the part to exclude. In order to select
|
||||||
|
/// subset of the pallet parts.
|
||||||
|
///
|
||||||
|
/// For example excluding the part `Call` can be useful if the runtime doesn't want to make the
|
||||||
|
/// pallet calls available.
|
||||||
|
///
|
||||||
|
/// * `use_parts { Part1, Part2 }` optional: comma separated parts without generics. I.e. one of
|
||||||
|
/// `Pallet`, `Call`, `Storage`, `Event`, `Origin`, `Config`, `Inherent`, `ValidateUnsigned`. It
|
||||||
|
/// is incompatible with `exclude_parts`. This specifies the part to use. In order to select a
|
||||||
|
/// subset of the pallet parts.
|
||||||
|
///
|
||||||
|
/// For example not using the part `Call` can be useful if the runtime doesn't want to make the
|
||||||
|
/// pallet calls available.
|
||||||
|
///
|
||||||
|
/// * `= $n` optional: number to define at which index the pallet variants in `OriginCaller`, `Call`
|
||||||
|
/// and `Event` are encoded, and to define the ModuleToIndex value.
|
||||||
|
///
|
||||||
|
/// if `= $n` is not given, then index is resolved in the same way as fieldless enum in Rust
|
||||||
|
/// (i.e. incrementedly from previous index):
|
||||||
|
/// ```nocompile
|
||||||
|
/// pallet1 .. = 2,
|
||||||
|
/// pallet2 .., // Here pallet2 is given index 3
|
||||||
|
/// pallet3 .. = 0,
|
||||||
|
/// pallet4 .., // Here pallet4 is given index 1
|
||||||
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
@@ -352,8 +392,8 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
|
|||||||
///
|
///
|
||||||
/// # Type definitions
|
/// # Type definitions
|
||||||
///
|
///
|
||||||
/// * The macro generates a type alias for each pallet to their `Module` (or `Pallet`). E.g. `type
|
/// * The macro generates a type alias for each pallet to their `Pallet`. E.g. `type System =
|
||||||
/// System = frame_system::Pallet<Runtime>`
|
/// frame_system::Pallet<Runtime>`
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn construct_runtime(input: TokenStream) -> TokenStream {
|
pub fn construct_runtime(input: TokenStream) -> TokenStream {
|
||||||
construct_runtime::construct_runtime(input)
|
construct_runtime::construct_runtime(input)
|
||||||
@@ -498,3 +538,27 @@ pub fn impl_key_prefix_for_tuples(input: TokenStream) -> TokenStream {
|
|||||||
pub fn __generate_dummy_part_checker(input: TokenStream) -> TokenStream {
|
pub fn __generate_dummy_part_checker(input: TokenStream) -> TokenStream {
|
||||||
dummy_part_checker::generate_dummy_part_checker(input)
|
dummy_part_checker::generate_dummy_part_checker(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Macro that inserts some tokens after the first match of some pattern.
|
||||||
|
///
|
||||||
|
/// # Example:
|
||||||
|
///
|
||||||
|
/// ```nocompile
|
||||||
|
/// match_and_insert!(
|
||||||
|
/// target = [{ Some content with { at some point match pattern } other match pattern are ignored }]
|
||||||
|
/// pattern = [{ match pattern }] // the match pattern cannot contain any group: `[]`, `()`, `{}`
|
||||||
|
/// // can relax this constraint, but will require modifying the match logic in code
|
||||||
|
/// tokens = [{ expansion tokens }] // content inside braces can be anything including groups
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// will generate:
|
||||||
|
///
|
||||||
|
/// ```nocompile
|
||||||
|
/// Some content with { at some point match pattern expansion tokens } other match patterns are
|
||||||
|
/// ignored
|
||||||
|
/// ```
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn match_and_insert(input: TokenStream) -> TokenStream {
|
||||||
|
match_and_insert::match_and_insert(input)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
// This file is part of Substrate.
|
||||||
|
|
||||||
|
// Copyright (C) 2021 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 the `match_and_insert` macro.
|
||||||
|
|
||||||
|
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||||
|
use std::iter::once;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
|
||||||
|
mod keyword {
|
||||||
|
syn::custom_keyword!(target);
|
||||||
|
syn::custom_keyword!(pattern);
|
||||||
|
syn::custom_keyword!(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn match_and_insert(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let MatchAndInsertDef { pattern, tokens, target } =
|
||||||
|
syn::parse_macro_input!(input as MatchAndInsertDef);
|
||||||
|
|
||||||
|
match expand_in_stream(&pattern, &mut Some(tokens), target) {
|
||||||
|
Ok(stream) => stream.into(),
|
||||||
|
Err(err) => err.to_compile_error().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MatchAndInsertDef {
|
||||||
|
// Token stream to search and insert tokens into.
|
||||||
|
target: TokenStream,
|
||||||
|
// Pattern to match against, this is ensured to have no TokenTree::Group nor TokenTree::Literal
|
||||||
|
// (i.e. contains only Punct or Ident), and not being empty.
|
||||||
|
pattern: Vec<TokenTree>,
|
||||||
|
// Token stream to insert after the match pattern.
|
||||||
|
tokens: TokenStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::parse::Parse for MatchAndInsertDef {
|
||||||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
|
let mut target;
|
||||||
|
let _ = input.parse::<keyword::target>()?;
|
||||||
|
let _ = input.parse::<syn::Token![=]>()?;
|
||||||
|
let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(target in input);
|
||||||
|
let _replace_with_brace: syn::token::Brace = syn::braced!(target in target);
|
||||||
|
let target = target.parse()?;
|
||||||
|
|
||||||
|
let mut pattern;
|
||||||
|
let _ = input.parse::<keyword::pattern>()?;
|
||||||
|
let _ = input.parse::<syn::Token![=]>()?;
|
||||||
|
let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(pattern in input);
|
||||||
|
let _replace_with_brace: syn::token::Brace = syn::braced!(pattern in pattern);
|
||||||
|
let pattern = pattern.parse::<TokenStream>()?.into_iter().collect::<Vec<TokenTree>>();
|
||||||
|
|
||||||
|
if let Some(t) = pattern.iter().find(|t| matches!(t, TokenTree::Group(_))) {
|
||||||
|
return Err(syn::Error::new(t.span(), "Unexpected group token tree"))
|
||||||
|
}
|
||||||
|
if let Some(t) = pattern.iter().find(|t| matches!(t, TokenTree::Literal(_))) {
|
||||||
|
return Err(syn::Error::new(t.span(), "Unexpected literal token tree"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if pattern.is_empty() {
|
||||||
|
return Err(syn::Error::new(Span::call_site(), "empty match pattern is invalid"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tokens;
|
||||||
|
let _ = input.parse::<keyword::tokens>()?;
|
||||||
|
let _ = input.parse::<syn::Token![=]>()?;
|
||||||
|
let _replace_with_bracket: syn::token::Bracket = syn::bracketed!(tokens in input);
|
||||||
|
let _replace_with_brace: syn::token::Brace = syn::braced!(tokens in tokens);
|
||||||
|
let tokens = tokens.parse()?;
|
||||||
|
|
||||||
|
Ok(Self { tokens, pattern, target })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert `tokens` after the first matching `pattern`.
|
||||||
|
// `tokens` must be some (Option is used for internal simplification).
|
||||||
|
// `pattern` must not be empty and should only contain Ident or Punct.
|
||||||
|
fn expand_in_stream(
|
||||||
|
pattern: &[TokenTree],
|
||||||
|
tokens: &mut Option<TokenStream>,
|
||||||
|
stream: TokenStream,
|
||||||
|
) -> syn::Result<TokenStream> {
|
||||||
|
assert!(
|
||||||
|
tokens.is_some(),
|
||||||
|
"`tokens` must be some, Option is used because `tokens` is used only once"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!pattern.is_empty(),
|
||||||
|
"`pattern` must not be empty, otherwise there is nothing to match against"
|
||||||
|
);
|
||||||
|
|
||||||
|
let stream_span = stream.span();
|
||||||
|
let mut stream = stream.into_iter();
|
||||||
|
let mut extended = TokenStream::new();
|
||||||
|
let mut match_cursor = 0;
|
||||||
|
|
||||||
|
while let Some(token) = stream.next() {
|
||||||
|
match token {
|
||||||
|
TokenTree::Group(group) => {
|
||||||
|
match_cursor = 0;
|
||||||
|
let group_stream = group.stream();
|
||||||
|
match expand_in_stream(pattern, tokens, group_stream) {
|
||||||
|
Ok(s) => {
|
||||||
|
extended.extend(once(TokenTree::Group(Group::new(group.delimiter(), s))));
|
||||||
|
extended.extend(stream);
|
||||||
|
return Ok(extended)
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
extended.extend(once(TokenTree::Group(group)));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
other => {
|
||||||
|
advance_match_cursor(&other, pattern, &mut match_cursor);
|
||||||
|
|
||||||
|
extended.extend(once(other));
|
||||||
|
|
||||||
|
if match_cursor == pattern.len() {
|
||||||
|
extended
|
||||||
|
.extend(once(tokens.take().expect("tokens is used to replace only once")));
|
||||||
|
extended.extend(stream);
|
||||||
|
return Ok(extended)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we reach this point, it means the stream is empty and we haven't found a matching pattern
|
||||||
|
let msg = format!("Cannot find pattern `{:?}` in given token stream", pattern);
|
||||||
|
Err(syn::Error::new(stream_span, msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_match_cursor(other: &TokenTree, pattern: &[TokenTree], match_cursor: &mut usize) {
|
||||||
|
use TokenTree::{Ident, Punct};
|
||||||
|
|
||||||
|
let does_match_other_pattern = match (other, &pattern[*match_cursor]) {
|
||||||
|
(Ident(i1), Ident(i2)) => i1 == i2,
|
||||||
|
(Punct(p1), Punct(p2)) => p1.as_char() == p2.as_char(),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if does_match_other_pattern {
|
||||||
|
*match_cursor += 1;
|
||||||
|
} else {
|
||||||
|
*match_cursor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ mod origin;
|
|||||||
mod pallet_struct;
|
mod pallet_struct;
|
||||||
mod storage;
|
mod storage;
|
||||||
mod store_trait;
|
mod store_trait;
|
||||||
|
mod tt_default_parts;
|
||||||
mod type_value;
|
mod type_value;
|
||||||
mod validate_unsigned;
|
mod validate_unsigned;
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream {
|
|||||||
let type_values = type_value::expand_type_values(&mut def);
|
let type_values = type_value::expand_type_values(&mut def);
|
||||||
let origins = origin::expand_origins(&mut def);
|
let origins = origin::expand_origins(&mut def);
|
||||||
let validate_unsigned = validate_unsigned::expand_validate_unsigned(&mut def);
|
let validate_unsigned = validate_unsigned::expand_validate_unsigned(&mut def);
|
||||||
|
let tt_default_parts = tt_default_parts::expand_tt_default_parts(&mut def);
|
||||||
|
|
||||||
if get_doc_literals(&def.item.attrs).is_empty() {
|
if get_doc_literals(&def.item.attrs).is_empty() {
|
||||||
def.item.attrs.push(syn::parse_quote!(
|
def.item.attrs.push(syn::parse_quote!(
|
||||||
@@ -96,6 +98,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream {
|
|||||||
#type_values
|
#type_values
|
||||||
#origins
|
#origins
|
||||||
#validate_unsigned
|
#validate_unsigned
|
||||||
|
#tt_default_parts
|
||||||
);
|
);
|
||||||
|
|
||||||
def.item
|
def.item
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// This file is part of Substrate.
|
||||||
|
|
||||||
|
// Copyright (C) 2021 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, COUNTER};
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
|
||||||
|
/// Generate the `tt_default_parts` macro.
|
||||||
|
pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
|
||||||
|
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||||
|
let default_parts_unique_id =
|
||||||
|
syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span());
|
||||||
|
|
||||||
|
let call_part = def.call.as_ref().map(|_| quote::quote!(Call,));
|
||||||
|
|
||||||
|
let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,));
|
||||||
|
|
||||||
|
let event_part = def.event.as_ref().map(|event| {
|
||||||
|
let gen = event.gen_kind.is_generic().then(|| quote::quote!( <T> ));
|
||||||
|
quote::quote!( Event #gen , )
|
||||||
|
});
|
||||||
|
|
||||||
|
let origin_part = def.origin.as_ref().map(|origin| {
|
||||||
|
let gen = origin.is_generic.then(|| quote::quote!( <T> ));
|
||||||
|
quote::quote!( Origin #gen , )
|
||||||
|
});
|
||||||
|
|
||||||
|
let config_part = def.genesis_config.as_ref().map(|genesis_config| {
|
||||||
|
let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!( <T> ));
|
||||||
|
quote::quote!( Config #gen , )
|
||||||
|
});
|
||||||
|
|
||||||
|
let inherent_part = def.inherent.as_ref().map(|_| quote::quote!(Inherent,));
|
||||||
|
|
||||||
|
let validate_unsigned_part =
|
||||||
|
def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,));
|
||||||
|
|
||||||
|
quote::quote!(
|
||||||
|
// This macro follows the conventions as laid out by the `tt-call` crate. It does not
|
||||||
|
// accept any arguments and simply returns the pallet parts, separated by commas, then
|
||||||
|
// wrapped inside of braces and finally prepended with double colons, to the caller inside
|
||||||
|
// of a key named `tokens`.
|
||||||
|
//
|
||||||
|
// We need to accept a frame_support argument here, because this macro gets expanded on the
|
||||||
|
// crate that called the `construct_runtime!` macro, and said crate may have renamed
|
||||||
|
// frame-support, and so we need to pass in the frame-support path that said crate
|
||||||
|
// recognizes.
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! #default_parts_unique_id {
|
||||||
|
{
|
||||||
|
$caller:tt
|
||||||
|
frame_support = [{ $($frame_support:ident)::* }]
|
||||||
|
} => {
|
||||||
|
$($frame_support)*::tt_return! {
|
||||||
|
$caller
|
||||||
|
tokens = [{
|
||||||
|
::{
|
||||||
|
Pallet, #call_part #storage_part #event_part #origin_part #config_part
|
||||||
|
#inherent_part #validate_unsigned_part
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use #default_parts_unique_id as tt_default_parts;
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -50,6 +50,8 @@ pub use sp_runtime::RuntimeDebug;
|
|||||||
pub use sp_state_machine::BasicExternalities;
|
pub use sp_state_machine::BasicExternalities;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use sp_std;
|
pub use sp_std;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use tt_call::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod dispatch;
|
pub mod dispatch;
|
||||||
@@ -573,7 +575,7 @@ pub fn debug(data: &impl sp_std::fmt::Debug) {
|
|||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use frame_support_procedural::{
|
pub use frame_support_procedural::{
|
||||||
construct_runtime, decl_storage, transactional, RuntimeDebugNoBound,
|
construct_runtime, decl_storage, match_and_insert, transactional, RuntimeDebugNoBound,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
name = "frame-support-test-compile-pass"
|
||||||
|
version = "4.0.0-dev"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
publish = false
|
||||||
|
homepage = "https://substrate.dev"
|
||||||
|
repository = "https://github.com/paritytech/substrate/"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
|
||||||
|
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
|
||||||
|
sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/core" }
|
||||||
|
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" }
|
||||||
|
sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" }
|
||||||
|
support = { package = "frame-support", version = "4.0.0-dev", default-features = false, path = "../../" }
|
||||||
|
system = { package = "frame-system", version = "4.0.0-dev", default-features = false, path = "../../../system" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = [
|
||||||
|
"codec/std",
|
||||||
|
"scale-info/std",
|
||||||
|
"support/std",
|
||||||
|
"system/std",
|
||||||
|
]
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
// This file is part of Substrate.
|
||||||
|
|
||||||
|
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
|
||||||
|
#![recursion_limit = "256"]
|
||||||
|
//! This crate tests that `construct_runtime!` expands the pallet parts
|
||||||
|
//! correctly even when frame-support is renamed in Cargo.toml
|
||||||
|
|
||||||
|
use sp_core::{sr25519, H256};
|
||||||
|
use sp_runtime::{
|
||||||
|
create_runtime_str, generic,
|
||||||
|
traits::{BlakeTwo256, IdentityLookup, Verify},
|
||||||
|
};
|
||||||
|
use sp_version::RuntimeVersion;
|
||||||
|
use support::{construct_runtime, parameter_types};
|
||||||
|
|
||||||
|
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||||
|
spec_name: create_runtime_str!("frame-support-test-compile-pass"),
|
||||||
|
impl_name: create_runtime_str!("substrate-frame-support-test-compile-pass-runtime"),
|
||||||
|
authoring_version: 0,
|
||||||
|
spec_version: 0,
|
||||||
|
impl_version: 0,
|
||||||
|
apis: sp_version::create_apis_vec!([]),
|
||||||
|
transaction_version: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type Signature = sr25519::Signature;
|
||||||
|
pub type AccountId = <Signature as Verify>::Signer;
|
||||||
|
pub type BlockNumber = u64;
|
||||||
|
pub type Index = u64;
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub const BlockHashCount: BlockNumber = 2400;
|
||||||
|
pub const Version: RuntimeVersion = VERSION;
|
||||||
|
pub const SS58Prefix: u8 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl system::Config for Runtime {
|
||||||
|
type BaseCallFilter = support::traits::Everything;
|
||||||
|
type BlockWeights = ();
|
||||||
|
type BlockLength = ();
|
||||||
|
type Index = u128;
|
||||||
|
type Hash = H256;
|
||||||
|
type Hashing = BlakeTwo256;
|
||||||
|
type Header = Header;
|
||||||
|
type Lookup = IdentityLookup<Self::AccountId>;
|
||||||
|
type BlockHashCount = BlockHashCount;
|
||||||
|
type Version = Version;
|
||||||
|
type AccountData = ();
|
||||||
|
type Origin = Origin;
|
||||||
|
type BlockNumber = BlockNumber;
|
||||||
|
type AccountId = AccountId;
|
||||||
|
type Event = Event;
|
||||||
|
type PalletInfo = PalletInfo;
|
||||||
|
type Call = Call;
|
||||||
|
type DbWeight = ();
|
||||||
|
type OnNewAccount = ();
|
||||||
|
type OnKilledAccount = ();
|
||||||
|
type OnSetCode = ();
|
||||||
|
type SystemWeightInfo = ();
|
||||||
|
type SS58Prefix = SS58Prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||||
|
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||||
|
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
|
||||||
|
construct_runtime!(
|
||||||
|
pub enum Runtime where
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
|
{
|
||||||
|
System: system,
|
||||||
|
}
|
||||||
|
);
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
use frame_support::construct_runtime;
|
||||||
|
use sp_runtime::{generic, traits::BlakeTwo256};
|
||||||
|
use sp_core::sr25519;
|
||||||
|
|
||||||
|
#[frame_support::pallet]
|
||||||
|
mod pallet {
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config: frame_system::Config {}
|
||||||
|
|
||||||
|
#[pallet::pallet]
|
||||||
|
pub struct Pallet<T>(_);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Signature = sr25519::Signature;
|
||||||
|
pub type BlockNumber = u64;
|
||||||
|
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||||
|
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||||
|
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
|
||||||
|
impl pallet::Config for Runtime {}
|
||||||
|
|
||||||
|
construct_runtime! {
|
||||||
|
pub enum Runtime where
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
|
{
|
||||||
|
System: system::{Pallet, Call, Storage, Config, Event<T>},
|
||||||
|
Pallet: pallet exclude_parts { Pallet } use_parts { Pallet },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
error: Unexpected tokens, expected one of `=`, `,`
|
||||||
|
--> $DIR/both_use_and_excluded_parts.rs:29:43
|
||||||
|
|
|
||||||
|
29 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet },
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `Call` in this scope
|
||||||
|
--> $DIR/both_use_and_excluded_parts.rs:18:64
|
||||||
|
|
|
||||||
|
18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: consider importing one of these items
|
||||||
|
|
|
||||||
|
1 | use crate::pallet::Call;
|
||||||
|
|
|
||||||
|
1 | use frame_support_test::Call;
|
||||||
|
|
|
||||||
|
1 | use frame_system::Call;
|
||||||
|
|
|
||||||
|
1 | use test_pallet::Call;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `Runtime` in this scope
|
||||||
|
--> $DIR/both_use_and_excluded_parts.rs:20:25
|
||||||
|
|
|
||||||
|
20 | impl pallet::Config for Runtime {}
|
||||||
|
| ^^^^^^^ not found in this scope
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
use frame_support::construct_runtime;
|
||||||
|
|
||||||
|
construct_runtime! {
|
||||||
|
pub enum Runtime where
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
{
|
||||||
|
System: frame_system exclude_parts { Call, Call },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
error: `Call` was already declared before. Please remove the duplicate declaration
|
||||||
|
--> $DIR/duplicate_exclude.rs:9:46
|
||||||
|
|
|
||||||
|
9 | System: frame_system exclude_parts { Call, Call },
|
||||||
|
| ^^^^
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
use frame_support::construct_runtime;
|
||||||
|
|
||||||
|
construct_runtime! {
|
||||||
|
pub enum Runtime where
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
{
|
||||||
|
System: frame_system exclude_part { Call },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`
|
||||||
|
--> $DIR/exclude_missspell.rs:9:24
|
||||||
|
|
|
||||||
|
9 | System: frame_system exclude_part { Call },
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
use frame_support::construct_runtime;
|
||||||
|
use sp_runtime::{generic, traits::BlakeTwo256};
|
||||||
|
use sp_core::sr25519;
|
||||||
|
|
||||||
|
#[frame_support::pallet]
|
||||||
|
mod pallet {
|
||||||
|
use frame_support::pallet_prelude::*;
|
||||||
|
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config: frame_system::Config {}
|
||||||
|
|
||||||
|
#[pallet::pallet]
|
||||||
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
|
#[pallet::storage]
|
||||||
|
type Foo<T> = StorageValue<Value=u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Signature = sr25519::Signature;
|
||||||
|
pub type BlockNumber = u64;
|
||||||
|
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||||
|
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||||
|
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
|
||||||
|
impl pallet::Config for Runtime {}
|
||||||
|
|
||||||
|
construct_runtime! {
|
||||||
|
pub enum Runtime where
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
|
{
|
||||||
|
System: system::{Pallet, Call, Storage, Config, Event<T>},
|
||||||
|
Pallet: pallet exclude_parts { Call },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`.
|
||||||
|
--> $DIR/exclude_undefined_part.rs:34:34
|
||||||
|
|
|
||||||
|
34 | Pallet: pallet exclude_parts { Call },
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `Call` in this scope
|
||||||
|
--> $DIR/exclude_undefined_part.rs:23:64
|
||||||
|
|
|
||||||
|
23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: consider importing one of these items
|
||||||
|
|
|
||||||
|
1 | use crate::pallet::Call;
|
||||||
|
|
|
||||||
|
1 | use frame_support_test::Call;
|
||||||
|
|
|
||||||
|
1 | use frame_system::Call;
|
||||||
|
|
|
||||||
|
1 | use test_pallet::Call;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `Runtime` in this scope
|
||||||
|
--> $DIR/exclude_undefined_part.rs:25:25
|
||||||
|
|
|
||||||
|
25 | impl pallet::Config for Runtime {}
|
||||||
|
| ^^^^^^^ not found in this scope
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
error: expected one of: identifier, curly braces, `<`
|
error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`
|
||||||
--> $DIR/invalid_module_details.rs:9:19
|
--> $DIR/invalid_module_details.rs:9:17
|
||||||
|
|
|
|
||||||
9 | system: System::(),
|
9 | system: System::(),
|
||||||
| ^^
|
| ^^
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
error: expected `::`
|
error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`
|
||||||
--> $DIR/invalid_token_after_module.rs:9:18
|
--> $DIR/invalid_token_after_module.rs:9:18
|
||||||
|
|
|
|
||||||
9 | system: System ?
|
9 | system: System ?
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
use frame_support::construct_runtime;
|
||||||
|
|
||||||
|
mod pallet_old {
|
||||||
|
pub trait Config: frame_system::Config {}
|
||||||
|
|
||||||
|
decl_storage! {
|
||||||
|
trait Store for Module<T: Config> as Example {}
|
||||||
|
}
|
||||||
|
|
||||||
|
decl_module! {
|
||||||
|
pub struct Module<T: Config> for enum Call where origin: T::Origin {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
construct_runtime! {
|
||||||
|
pub enum Runtime where
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
{
|
||||||
|
System: frame_system,
|
||||||
|
OldPallet: pallet_old,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
error[E0433]: failed to resolve: could not find `tt_default_parts` in `pallet_old`
|
||||||
|
--> $DIR/old_unsupported_pallet_decl.rs:15:1
|
||||||
|
|
|
||||||
|
15 | / construct_runtime! {
|
||||||
|
16 | | pub enum Runtime where
|
||||||
|
17 | | UncheckedExtrinsic = UncheckedExtrinsic,
|
||||||
|
18 | | Block = Block,
|
||||||
|
... |
|
||||||
|
23 | | }
|
||||||
|
24 | | }
|
||||||
|
| |_^ could not find `tt_default_parts` in `pallet_old`
|
||||||
|
|
|
||||||
|
= note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: cannot find macro `decl_storage` in this scope
|
||||||
|
--> $DIR/old_unsupported_pallet_decl.rs:6:2
|
||||||
|
|
|
||||||
|
6 | decl_storage! {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: consider importing this macro:
|
||||||
|
frame_support::decl_storage
|
||||||
|
|
||||||
|
error: cannot find macro `decl_module` in this scope
|
||||||
|
--> $DIR/old_unsupported_pallet_decl.rs:10:2
|
||||||
|
|
|
||||||
|
10 | decl_module! {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: consider importing this macro:
|
||||||
|
frame_support::decl_module
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
use frame_support::construct_runtime;
|
||||||
|
use sp_runtime::{generic, traits::BlakeTwo256};
|
||||||
|
use sp_core::sr25519;
|
||||||
|
|
||||||
|
#[frame_support::pallet]
|
||||||
|
mod pallet {
|
||||||
|
use frame_support::pallet_prelude::*;
|
||||||
|
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config: frame_system::Config {}
|
||||||
|
|
||||||
|
#[pallet::pallet]
|
||||||
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
|
#[pallet::storage]
|
||||||
|
type Foo<T> = StorageValue<Value=u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Signature = sr25519::Signature;
|
||||||
|
pub type BlockNumber = u64;
|
||||||
|
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||||
|
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||||
|
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
|
||||||
|
impl pallet::Config for Runtime {}
|
||||||
|
|
||||||
|
construct_runtime! {
|
||||||
|
pub enum Runtime where
|
||||||
|
Block = Block,
|
||||||
|
NodeBlock = Block,
|
||||||
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
|
{
|
||||||
|
System: system::{Pallet, Call, Storage, Config, Event<T>},
|
||||||
|
Pallet: pallet use_parts { Call },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`.
|
||||||
|
--> $DIR/use_undefined_part.rs:34:30
|
||||||
|
|
|
||||||
|
34 | Pallet: pallet use_parts { Call },
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `Call` in this scope
|
||||||
|
--> $DIR/use_undefined_part.rs:23:64
|
||||||
|
|
|
||||||
|
23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: consider importing one of these items
|
||||||
|
|
|
||||||
|
1 | use crate::pallet::Call;
|
||||||
|
|
|
||||||
|
1 | use frame_support_test::Call;
|
||||||
|
|
|
||||||
|
1 | use frame_system::Call;
|
||||||
|
|
|
||||||
|
1 | use test_pallet::Call;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `Runtime` in this scope
|
||||||
|
--> $DIR/use_undefined_part.rs:25:25
|
||||||
|
|
|
||||||
|
25 | impl pallet::Config for Runtime {}
|
||||||
|
| ^^^^^^^ not found in this scope
|
||||||
@@ -509,6 +509,18 @@ pub mod pallet3 {
|
|||||||
pub struct Pallet<T>(_);
|
pub struct Pallet<T>(_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[frame_support::pallet]
|
||||||
|
pub mod pallet4 {
|
||||||
|
#[pallet::config]
|
||||||
|
pub trait Config: frame_system::Config {}
|
||||||
|
|
||||||
|
#[pallet::pallet]
|
||||||
|
pub struct Pallet<T>(_);
|
||||||
|
|
||||||
|
#[pallet::call]
|
||||||
|
impl<T: Config> Pallet<T> {}
|
||||||
|
}
|
||||||
|
|
||||||
frame_support::parameter_types!(
|
frame_support::parameter_types!(
|
||||||
pub const MyGetParam: u32 = 10;
|
pub const MyGetParam: u32 = 10;
|
||||||
pub const MyGetParam2: u32 = 11;
|
pub const MyGetParam2: u32 = 11;
|
||||||
@@ -553,6 +565,8 @@ impl pallet2::Config for Runtime {
|
|||||||
type Event = Event;
|
type Event = Event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl pallet4::Config for Runtime {}
|
||||||
|
|
||||||
pub type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
|
pub type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
|
||||||
pub type Block = sp_runtime::generic::Block<Header, UncheckedExtrinsic>;
|
pub type Block = sp_runtime::generic::Block<Header, UncheckedExtrinsic>;
|
||||||
pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic<u32, Call, (), ()>;
|
pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic<u32, Call, (), ()>;
|
||||||
@@ -563,12 +577,21 @@ frame_support::construct_runtime!(
|
|||||||
NodeBlock = Block,
|
NodeBlock = Block,
|
||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
{
|
{
|
||||||
System: frame_system::{Call, Event<T>},
|
// Exclude part `Storage` in order not to check its metadata in tests.
|
||||||
Example: pallet::{Pallet, Call, Event<T>, Config, Storage, Inherent, Origin<T>, ValidateUnsigned},
|
System: frame_system exclude_parts { Pallet, Storage },
|
||||||
Example2: pallet2::{Pallet, Call, Event, Config<T>, Storage},
|
Example: pallet,
|
||||||
|
Example2: pallet2 exclude_parts { Call },
|
||||||
|
Example4: pallet4 use_parts { Call },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test that the part `Call` is excluded from Example2 and included in Example4.
|
||||||
|
fn _ensure_call_is_correctly_excluded_and_included(call: Call) {
|
||||||
|
match call {
|
||||||
|
Call::System(_) | Call::Example(_) | Call::Example4(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn transactional_works() {
|
fn transactional_works() {
|
||||||
TestExternalities::default().execute_with(|| {
|
TestExternalities::default().execute_with(|| {
|
||||||
@@ -995,8 +1018,8 @@ fn migrate_from_pallet_version_to_storage_version() {
|
|||||||
AllPalletsWithSystem,
|
AllPalletsWithSystem,
|
||||||
>(&db_weight);
|
>(&db_weight);
|
||||||
|
|
||||||
// 3 pallets, 2 writes and every write costs 5 weight.
|
// 4 pallets, 2 writes and every write costs 5 weight.
|
||||||
assert_eq!(3 * 2 * 5, weight);
|
assert_eq!(4 * 2 * 5, weight);
|
||||||
|
|
||||||
// All pallet versions should be removed
|
// All pallet versions should be removed
|
||||||
assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none());
|
assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none());
|
||||||
@@ -1268,7 +1291,7 @@ fn metadata() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
calls: Some(meta_type::<pallet2::Call<Runtime>>().into()),
|
calls: None,
|
||||||
event: Some(PalletEventMetadata { ty: meta_type::<pallet2::Event>() }),
|
event: Some(PalletEventMetadata { ty: meta_type::<pallet2::Event>() }),
|
||||||
constants: vec![],
|
constants: vec![],
|
||||||
error: None,
|
error: None,
|
||||||
|
|||||||
@@ -302,13 +302,12 @@ frame_support::construct_runtime!(
|
|||||||
NodeBlock = Block,
|
NodeBlock = Block,
|
||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
{
|
{
|
||||||
System: frame_system::{Pallet, Call, Event<T>},
|
// Exclude part `Storage` in order not to check its metadata in tests.
|
||||||
Example: pallet::{Pallet, Call, Event<T>, Config, Storage, Inherent, Origin<T>, ValidateUnsigned},
|
System: frame_system exclude_parts { Storage },
|
||||||
Instance1Example: pallet::<Instance1>::{
|
Example: pallet,
|
||||||
Pallet, Call, Event<T>, Config, Storage, Inherent, Origin<T>, ValidateUnsigned
|
Instance1Example: pallet::<Instance1>,
|
||||||
},
|
Example2: pallet2,
|
||||||
Example2: pallet2::{Pallet, Event<T>, Config<T>, Storage},
|
Instance1Example2: pallet2::<Instance1>,
|
||||||
Instance1Example2: pallet2::<Instance1>::{Pallet, Event<T>, Config<T>, Storage},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -601,7 +600,7 @@ fn metadata() {
|
|||||||
let system_pallet_metadata = PalletMetadata {
|
let system_pallet_metadata = PalletMetadata {
|
||||||
index: 0,
|
index: 0,
|
||||||
name: "System",
|
name: "System",
|
||||||
storage: None,
|
storage: None, // The storage metadatas have been excluded.
|
||||||
calls: Some(scale_info::meta_type::<frame_system::Call<Runtime>>().into()),
|
calls: Some(scale_info::meta_type::<frame_system::Call<Runtime>>().into()),
|
||||||
event: Some(PalletEventMetadata {
|
event: Some(PalletEventMetadata {
|
||||||
ty: scale_info::meta_type::<frame_system::Event<Runtime>>(),
|
ty: scale_info::meta_type::<frame_system::Event<Runtime>>(),
|
||||||
|
|||||||
Reference in New Issue
Block a user