mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-25 17:37:56 +00:00
Construct Runtime v2 (#1378)
Moved from https://github.com/paritytech/substrate/pull/14788 ---- Fixes https://github.com/paritytech/polkadot-sdk/issues/232 This PR introduces outer-macro approach for `construct_runtime` as discussed in the linked issue. It looks like the following: ```rust #[frame_support::runtime] mod runtime { #[runtime::runtime] #[runtime::derive( RuntimeCall, RuntimeEvent, RuntimeError, RuntimeOrigin, RuntimeFreezeReason, RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, RuntimeTask, )] pub struct Runtime; #[runtime::pallet_index(0)] pub type System = frame_system; #[runtime::pallet_index(1)] pub type Timestamp = pallet_timestamp; #[runtime::pallet_index(2)] pub type Aura = pallet_aura; #[runtime::pallet_index(3)] pub type Grandpa = pallet_grandpa; #[runtime::pallet_index(4)] pub type Balances = pallet_balances; #[runtime::pallet_index(5)] pub type TransactionPayment = pallet_transaction_payment; #[runtime::pallet_index(6)] pub type Sudo = pallet_sudo; // Include the custom logic from the pallet-template in the runtime. #[runtime::pallet_index(7)] pub type TemplateModule = pallet_template; } ``` ## Features - `#[runtime::runtime]` attached to a struct defines the main runtime - `#[runtime::derive]` attached to this struct defines the types generated by runtime - `#[runtime::pallet_index]` must be attached to a pallet to define its index - `#[runtime::disable_call]` can be optionally attached to a pallet to disable its calls - `#[runtime::disable_unsigned]` can be optionally attached to a pallet to disable unsigned calls - A pallet instance can be defined as `TemplateModule: pallet_template<Instance>` - An optional attribute can be defined as `#[frame_support::runtime(legacy_ordering)]` to ensure that the order of hooks is same as the order of pallets (and not based on the pallet_index). This is to support legacy runtimes and should be avoided for new ones. ## Todo - [x] Update the latest syntax in kitchensink and tests - [x] Update UI tests - [x] Docs ## Extension - Abstract away the Executive similar to https://github.com/paritytech/substrate/pull/14742 - Optionally avoid the need to specify all runtime types (TBD) --------- Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> Co-authored-by: Nikhil Gupta <>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
title: Construct Runtime V2 - An outer macro approach to define the runtime
|
||||
|
||||
doc:
|
||||
- audience: Runtime Dev
|
||||
description: |
|
||||
Introduces `#[frame_support::runtime]` that can be attached to a mod to define a runtime. The items
|
||||
in this mod can be attached to the following attributes to define the key components of the runtime.
|
||||
1. `#[runtime::runtime]` attached to a struct defines the main runtime
|
||||
2. `#[runtime::derive]` attached to the runtime struct defines the types generated by the runtime
|
||||
3. `#[runtime::pallet_index]` must be attached to a pallet to define its index
|
||||
4. `#[runtime::disable_call]` can be optionally attached to a pallet to disable its calls
|
||||
5. `#[runtime::disable_unsigned]` can be optionally attached to a pallet to disable unsigned calls
|
||||
6. A pallet instance can be defined as `TemplateModule: pallet_template<Instance>`
|
||||
An optional attribute can be defined as `#[frame_support::runtime(legacy_ordering)]` to ensure that
|
||||
the order of hooks is same as the order of pallets (and not based on the pallet_index). This is to support
|
||||
legacy runtimes and should be avoided for new ones.
|
||||
|
||||
migrations:
|
||||
db: []
|
||||
|
||||
runtime: []
|
||||
|
||||
crates:
|
||||
- name: frame-support
|
||||
- name: frame-support-procedural
|
||||
|
||||
host_functions: []
|
||||
@@ -58,7 +58,7 @@ sp-io = { path = "../../../primitives/io", default-features = false }
|
||||
frame-executive = { path = "../../../frame/executive", default-features = false }
|
||||
frame-benchmarking = { path = "../../../frame/benchmarking", default-features = false }
|
||||
frame-benchmarking-pallet-pov = { path = "../../../frame/benchmarking/pov", default-features = false }
|
||||
frame-support = { path = "../../../frame/support", default-features = false, features = ["tuples-96"] }
|
||||
frame-support = { path = "../../../frame/support", default-features = false, features = ["experimental", "tuples-96"] }
|
||||
frame-system = { path = "../../../frame/system", default-features = false }
|
||||
frame-system-benchmarking = { path = "../../../frame/system/benchmarking", default-features = false, optional = true }
|
||||
frame-election-provider-support = { path = "../../../frame/election-provider-support", default-features = false }
|
||||
|
||||
@@ -28,7 +28,7 @@ use frame_election_provider_support::{
|
||||
onchain, BalancingConfig, ElectionDataProvider, SequentialPhragmen, VoteWeight,
|
||||
};
|
||||
use frame_support::{
|
||||
construct_runtime, derive_impl,
|
||||
derive_impl,
|
||||
dispatch::DispatchClass,
|
||||
dynamic_params::{dynamic_pallet_params, dynamic_params},
|
||||
genesis_builder_helper::{build_config, create_default_config},
|
||||
@@ -2196,92 +2196,260 @@ impl pallet_parameters::Config for Runtime {
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Utility: pallet_utility,
|
||||
Babe: pallet_babe,
|
||||
Timestamp: pallet_timestamp,
|
||||
// Authorship must be before session in order to note author in the correct session and era
|
||||
// for im-online and staking.
|
||||
Authorship: pallet_authorship,
|
||||
Indices: pallet_indices,
|
||||
Balances: pallet_balances,
|
||||
TransactionPayment: pallet_transaction_payment,
|
||||
AssetTxPayment: pallet_asset_tx_payment,
|
||||
AssetConversionTxPayment: pallet_asset_conversion_tx_payment,
|
||||
ElectionProviderMultiPhase: pallet_election_provider_multi_phase,
|
||||
Staking: pallet_staking,
|
||||
Session: pallet_session,
|
||||
Democracy: pallet_democracy,
|
||||
Council: pallet_collective::<Instance1>,
|
||||
TechnicalCommittee: pallet_collective::<Instance2>,
|
||||
Elections: pallet_elections_phragmen,
|
||||
TechnicalMembership: pallet_membership::<Instance1>,
|
||||
Grandpa: pallet_grandpa,
|
||||
Treasury: pallet_treasury,
|
||||
AssetRate: pallet_asset_rate,
|
||||
Contracts: pallet_contracts,
|
||||
Sudo: pallet_sudo,
|
||||
ImOnline: pallet_im_online,
|
||||
AuthorityDiscovery: pallet_authority_discovery,
|
||||
Offences: pallet_offences,
|
||||
Historical: pallet_session_historical,
|
||||
RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip,
|
||||
Identity: pallet_identity,
|
||||
Society: pallet_society,
|
||||
Recovery: pallet_recovery,
|
||||
Vesting: pallet_vesting,
|
||||
Scheduler: pallet_scheduler,
|
||||
Glutton: pallet_glutton,
|
||||
Preimage: pallet_preimage,
|
||||
Proxy: pallet_proxy,
|
||||
Multisig: pallet_multisig,
|
||||
Bounties: pallet_bounties,
|
||||
Tips: pallet_tips,
|
||||
Assets: pallet_assets::<Instance1>,
|
||||
PoolAssets: pallet_assets::<Instance2>,
|
||||
Beefy: pallet_beefy,
|
||||
// MMR leaf construction must be after session in order to have a leaf's next_auth_set
|
||||
// refer to block<N>. See issue polkadot-fellows/runtimes#160 for details.
|
||||
Mmr: pallet_mmr,
|
||||
MmrLeaf: pallet_beefy_mmr,
|
||||
Lottery: pallet_lottery,
|
||||
Nis: pallet_nis,
|
||||
Uniques: pallet_uniques,
|
||||
Nfts: pallet_nfts,
|
||||
NftFractionalization: pallet_nft_fractionalization,
|
||||
Salary: pallet_salary,
|
||||
CoreFellowship: pallet_core_fellowship,
|
||||
TransactionStorage: pallet_transaction_storage,
|
||||
VoterList: pallet_bags_list::<Instance1>,
|
||||
StateTrieMigration: pallet_state_trie_migration,
|
||||
ChildBounties: pallet_child_bounties,
|
||||
Referenda: pallet_referenda,
|
||||
Remark: pallet_remark,
|
||||
RootTesting: pallet_root_testing,
|
||||
ConvictionVoting: pallet_conviction_voting,
|
||||
Whitelist: pallet_whitelist,
|
||||
AllianceMotion: pallet_collective::<Instance3>,
|
||||
Alliance: pallet_alliance,
|
||||
NominationPools: pallet_nomination_pools,
|
||||
RankedPolls: pallet_referenda::<Instance2>,
|
||||
RankedCollective: pallet_ranked_collective,
|
||||
AssetConversion: pallet_asset_conversion,
|
||||
FastUnstake: pallet_fast_unstake,
|
||||
MessageQueue: pallet_message_queue,
|
||||
Pov: frame_benchmarking_pallet_pov,
|
||||
TxPause: pallet_tx_pause,
|
||||
SafeMode: pallet_safe_mode,
|
||||
Statement: pallet_statement,
|
||||
MultiBlockMigrations: pallet_migrations,
|
||||
Broker: pallet_broker,
|
||||
TasksExample: pallet_example_tasks,
|
||||
Mixnet: pallet_mixnet,
|
||||
Parameters: pallet_parameters,
|
||||
SkipFeelessPayment: pallet_skip_feeless_payment,
|
||||
}
|
||||
);
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(
|
||||
RuntimeCall,
|
||||
RuntimeEvent,
|
||||
RuntimeError,
|
||||
RuntimeOrigin,
|
||||
RuntimeFreezeReason,
|
||||
RuntimeHoldReason,
|
||||
RuntimeSlashReason,
|
||||
RuntimeLockId,
|
||||
RuntimeTask
|
||||
)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type System = frame_system;
|
||||
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type Utility = pallet_utility;
|
||||
|
||||
#[runtime::pallet_index(2)]
|
||||
pub type Babe = pallet_babe;
|
||||
|
||||
#[runtime::pallet_index(3)]
|
||||
pub type Timestamp = pallet_timestamp;
|
||||
|
||||
// Authorship must be before session in order to note author in the correct session and era
|
||||
// for im-online and staking.
|
||||
#[runtime::pallet_index(4)]
|
||||
pub type Authorship = pallet_authorship;
|
||||
|
||||
#[runtime::pallet_index(5)]
|
||||
pub type Indices = pallet_indices;
|
||||
|
||||
#[runtime::pallet_index(6)]
|
||||
pub type Balances = pallet_balances;
|
||||
|
||||
#[runtime::pallet_index(7)]
|
||||
pub type TransactionPayment = pallet_transaction_payment;
|
||||
|
||||
#[runtime::pallet_index(8)]
|
||||
pub type AssetTxPayment = pallet_asset_tx_payment;
|
||||
|
||||
#[runtime::pallet_index(9)]
|
||||
pub type AssetConversionTxPayment = pallet_asset_conversion_tx_payment;
|
||||
|
||||
#[runtime::pallet_index(10)]
|
||||
pub type ElectionProviderMultiPhase = pallet_election_provider_multi_phase;
|
||||
|
||||
#[runtime::pallet_index(11)]
|
||||
pub type Staking = pallet_staking;
|
||||
|
||||
#[runtime::pallet_index(12)]
|
||||
pub type Session = pallet_session;
|
||||
|
||||
#[runtime::pallet_index(13)]
|
||||
pub type Democracy = pallet_democracy;
|
||||
|
||||
#[runtime::pallet_index(14)]
|
||||
pub type Council = pallet_collective<Instance1>;
|
||||
|
||||
#[runtime::pallet_index(15)]
|
||||
pub type TechnicalCommittee = pallet_collective<Instance2>;
|
||||
|
||||
#[runtime::pallet_index(16)]
|
||||
pub type Elections = pallet_elections_phragmen;
|
||||
|
||||
#[runtime::pallet_index(17)]
|
||||
pub type TechnicalMembership = pallet_membership<Instance1>;
|
||||
|
||||
#[runtime::pallet_index(18)]
|
||||
pub type Grandpa = pallet_grandpa;
|
||||
|
||||
#[runtime::pallet_index(19)]
|
||||
pub type Treasury = pallet_treasury;
|
||||
|
||||
#[runtime::pallet_index(20)]
|
||||
pub type AssetRate = pallet_asset_rate;
|
||||
|
||||
#[runtime::pallet_index(21)]
|
||||
pub type Contracts = pallet_contracts;
|
||||
|
||||
#[runtime::pallet_index(22)]
|
||||
pub type Sudo = pallet_sudo;
|
||||
|
||||
#[runtime::pallet_index(23)]
|
||||
pub type ImOnline = pallet_im_online;
|
||||
|
||||
#[runtime::pallet_index(24)]
|
||||
pub type AuthorityDiscovery = pallet_authority_discovery;
|
||||
|
||||
#[runtime::pallet_index(25)]
|
||||
pub type Offences = pallet_offences;
|
||||
|
||||
#[runtime::pallet_index(26)]
|
||||
pub type Historical = pallet_session_historical;
|
||||
|
||||
#[runtime::pallet_index(27)]
|
||||
pub type RandomnessCollectiveFlip = pallet_insecure_randomness_collective_flip;
|
||||
|
||||
#[runtime::pallet_index(28)]
|
||||
pub type Identity = pallet_identity;
|
||||
|
||||
#[runtime::pallet_index(29)]
|
||||
pub type Society = pallet_society;
|
||||
|
||||
#[runtime::pallet_index(30)]
|
||||
pub type Recovery = pallet_recovery;
|
||||
|
||||
#[runtime::pallet_index(31)]
|
||||
pub type Vesting = pallet_vesting;
|
||||
|
||||
#[runtime::pallet_index(32)]
|
||||
pub type Scheduler = pallet_scheduler;
|
||||
|
||||
#[runtime::pallet_index(33)]
|
||||
pub type Glutton = pallet_glutton;
|
||||
|
||||
#[runtime::pallet_index(34)]
|
||||
pub type Preimage = pallet_preimage;
|
||||
|
||||
#[runtime::pallet_index(35)]
|
||||
pub type Proxy = pallet_proxy;
|
||||
|
||||
#[runtime::pallet_index(36)]
|
||||
pub type Multisig = pallet_multisig;
|
||||
|
||||
#[runtime::pallet_index(37)]
|
||||
pub type Bounties = pallet_bounties;
|
||||
|
||||
#[runtime::pallet_index(38)]
|
||||
pub type Tips = pallet_tips;
|
||||
|
||||
#[runtime::pallet_index(39)]
|
||||
pub type Assets = pallet_assets<Instance1>;
|
||||
|
||||
#[runtime::pallet_index(40)]
|
||||
pub type PoolAssets = pallet_assets<Instance2>;
|
||||
|
||||
#[runtime::pallet_index(41)]
|
||||
pub type Beefy = pallet_beefy;
|
||||
|
||||
// MMR leaf construction must be after session in order to have a leaf's next_auth_set
|
||||
// refer to block<N>. See issue polkadot-fellows/runtimes#160 for details.
|
||||
#[runtime::pallet_index(42)]
|
||||
pub type Mmr = pallet_mmr;
|
||||
|
||||
#[runtime::pallet_index(43)]
|
||||
pub type MmrLeaf = pallet_beefy_mmr;
|
||||
|
||||
#[runtime::pallet_index(44)]
|
||||
pub type Lottery = pallet_lottery;
|
||||
|
||||
#[runtime::pallet_index(45)]
|
||||
pub type Nis = pallet_nis;
|
||||
|
||||
#[runtime::pallet_index(46)]
|
||||
pub type Uniques = pallet_uniques;
|
||||
|
||||
#[runtime::pallet_index(47)]
|
||||
pub type Nfts = pallet_nfts;
|
||||
|
||||
#[runtime::pallet_index(48)]
|
||||
pub type NftFractionalization = pallet_nft_fractionalization;
|
||||
|
||||
#[runtime::pallet_index(49)]
|
||||
pub type Salary = pallet_salary;
|
||||
|
||||
#[runtime::pallet_index(50)]
|
||||
pub type CoreFellowship = pallet_core_fellowship;
|
||||
|
||||
#[runtime::pallet_index(51)]
|
||||
pub type TransactionStorage = pallet_transaction_storage;
|
||||
|
||||
#[runtime::pallet_index(52)]
|
||||
pub type VoterList = pallet_bags_list<Instance1>;
|
||||
|
||||
#[runtime::pallet_index(53)]
|
||||
pub type StateTrieMigration = pallet_state_trie_migration;
|
||||
|
||||
#[runtime::pallet_index(54)]
|
||||
pub type ChildBounties = pallet_child_bounties;
|
||||
|
||||
#[runtime::pallet_index(55)]
|
||||
pub type Referenda = pallet_referenda;
|
||||
|
||||
#[runtime::pallet_index(56)]
|
||||
pub type Remark = pallet_remark;
|
||||
|
||||
#[runtime::pallet_index(57)]
|
||||
pub type RootTesting = pallet_root_testing;
|
||||
|
||||
#[runtime::pallet_index(58)]
|
||||
pub type ConvictionVoting = pallet_conviction_voting;
|
||||
|
||||
#[runtime::pallet_index(59)]
|
||||
pub type Whitelist = pallet_whitelist;
|
||||
|
||||
#[runtime::pallet_index(60)]
|
||||
pub type AllianceMotion = pallet_collective<Instance3>;
|
||||
|
||||
#[runtime::pallet_index(61)]
|
||||
pub type Alliance = pallet_alliance;
|
||||
|
||||
#[runtime::pallet_index(62)]
|
||||
pub type NominationPools = pallet_nomination_pools;
|
||||
|
||||
#[runtime::pallet_index(63)]
|
||||
pub type RankedPolls = pallet_referenda<Instance2>;
|
||||
|
||||
#[runtime::pallet_index(64)]
|
||||
pub type RankedCollective = pallet_ranked_collective;
|
||||
|
||||
#[runtime::pallet_index(65)]
|
||||
pub type AssetConversion = pallet_asset_conversion;
|
||||
|
||||
#[runtime::pallet_index(66)]
|
||||
pub type FastUnstake = pallet_fast_unstake;
|
||||
|
||||
#[runtime::pallet_index(67)]
|
||||
pub type MessageQueue = pallet_message_queue;
|
||||
|
||||
#[runtime::pallet_index(68)]
|
||||
pub type Pov = frame_benchmarking_pallet_pov;
|
||||
|
||||
#[runtime::pallet_index(69)]
|
||||
pub type TxPause = pallet_tx_pause;
|
||||
|
||||
#[runtime::pallet_index(70)]
|
||||
pub type SafeMode = pallet_safe_mode;
|
||||
|
||||
#[runtime::pallet_index(71)]
|
||||
pub type Statement = pallet_statement;
|
||||
|
||||
#[runtime::pallet_index(72)]
|
||||
pub type MultiBlockMigrations = pallet_migrations;
|
||||
|
||||
#[runtime::pallet_index(73)]
|
||||
pub type Broker = pallet_broker;
|
||||
|
||||
#[runtime::pallet_index(74)]
|
||||
pub type TasksExample = pallet_example_tasks;
|
||||
|
||||
#[runtime::pallet_index(75)]
|
||||
pub type Mixnet = pallet_mixnet;
|
||||
|
||||
#[runtime::pallet_index(76)]
|
||||
pub type Parameters = pallet_parameters;
|
||||
|
||||
#[runtime::pallet_index(77)]
|
||||
pub type SkipFeelessPayment = pallet_skip_feeless_payment;
|
||||
}
|
||||
|
||||
/// The address format for describing accounts.
|
||||
pub type Address = sp_runtime::MultiAddress<AccountId, AccountIndex>;
|
||||
|
||||
@@ -109,7 +109,9 @@ try-runtime = [
|
||||
"sp-debug-derive/force-debug",
|
||||
"sp-runtime/try-runtime",
|
||||
]
|
||||
experimental = []
|
||||
experimental = [
|
||||
"frame-support-procedural/experimental",
|
||||
]
|
||||
# By default some types have documentation, `no-metadata-docs` allows to reduce the documentation
|
||||
# in the metadata.
|
||||
no-metadata-docs = [
|
||||
|
||||
@@ -38,6 +38,7 @@ regex = "1"
|
||||
default = ["std"]
|
||||
std = ["sp-crypto-hashing/std"]
|
||||
no-metadata-docs = []
|
||||
experimental = []
|
||||
# Generate impl-trait for tuples with the given number of tuples. Will be needed as the number of
|
||||
# pallets in a runtime grows. Does increase the compile time!
|
||||
tuples-96 = []
|
||||
|
||||
@@ -208,8 +208,8 @@
|
||||
//! This macro returns the ` :: expanded { Error }` list of additional parts we would like to
|
||||
//! expose.
|
||||
|
||||
mod expand;
|
||||
mod parse;
|
||||
pub(crate) mod expand;
|
||||
pub(crate) mod parse;
|
||||
|
||||
use crate::pallet::parse::helper::two128_str;
|
||||
use cfg_expr::Predicate;
|
||||
@@ -515,7 +515,7 @@ fn construct_runtime_final_expansion(
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn decl_all_pallets<'a>(
|
||||
pub(crate) fn decl_all_pallets<'a>(
|
||||
runtime: &'a Ident,
|
||||
pallet_declarations: impl Iterator<Item = &'a Pallet>,
|
||||
features: &HashSet<&str>,
|
||||
@@ -624,7 +624,8 @@ fn decl_all_pallets<'a>(
|
||||
#( #all_pallets_without_system )*
|
||||
)
|
||||
}
|
||||
fn decl_pallet_runtime_setup(
|
||||
|
||||
pub(crate) fn decl_pallet_runtime_setup(
|
||||
runtime: &Ident,
|
||||
pallet_declarations: &[Pallet],
|
||||
scrate: &TokenStream2,
|
||||
@@ -730,7 +731,7 @@ fn decl_pallet_runtime_setup(
|
||||
)
|
||||
}
|
||||
|
||||
fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 {
|
||||
pub(crate) fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 {
|
||||
quote!(
|
||||
#[cfg(test)]
|
||||
mod __construct_runtime_integrity_test {
|
||||
@@ -745,7 +746,7 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 {
|
||||
)
|
||||
}
|
||||
|
||||
fn decl_static_assertions(
|
||||
pub(crate) fn decl_static_assertions(
|
||||
runtime: &Ident,
|
||||
pallet_decls: &[Pallet],
|
||||
scrate: &TokenStream2,
|
||||
@@ -776,7 +777,7 @@ fn decl_static_assertions(
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> {
|
||||
pub(crate) fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> {
|
||||
let max_pallet_num = {
|
||||
if cfg!(feature = "tuples-96") {
|
||||
96
|
||||
|
||||
@@ -31,6 +31,7 @@ mod match_and_insert;
|
||||
mod no_bound;
|
||||
mod pallet;
|
||||
mod pallet_error;
|
||||
mod runtime;
|
||||
mod storage_alias;
|
||||
mod transactional;
|
||||
mod tt_macro;
|
||||
@@ -1220,6 +1221,73 @@ pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Construct a runtime, with the given name and the given pallets.
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[frame_support::runtime]
|
||||
/// mod runtime {
|
||||
/// // The main runtime
|
||||
/// #[runtime::runtime]
|
||||
/// // Runtime Types to be generated
|
||||
/// #[runtime::derive(
|
||||
/// RuntimeCall,
|
||||
/// RuntimeEvent,
|
||||
/// RuntimeError,
|
||||
/// RuntimeOrigin,
|
||||
/// RuntimeFreezeReason,
|
||||
/// RuntimeHoldReason,
|
||||
/// RuntimeSlashReason,
|
||||
/// RuntimeLockId,
|
||||
/// RuntimeTask,
|
||||
/// )]
|
||||
/// pub struct Runtime;
|
||||
///
|
||||
/// #[runtime::pallet_index(0)]
|
||||
/// pub type System = frame_system;
|
||||
///
|
||||
/// #[runtime::pallet_index(1)]
|
||||
/// pub type Test = path::to::test;
|
||||
///
|
||||
/// // Pallet with instance.
|
||||
/// #[runtime::pallet_index(2)]
|
||||
/// pub type Test2_Instance1 = test2<Instance1>;
|
||||
///
|
||||
/// // Pallet with calls disabled.
|
||||
/// #[runtime::pallet_index(3)]
|
||||
/// #[runtime::disable_call]
|
||||
/// pub type Test3 = test3;
|
||||
///
|
||||
/// // Pallet with unsigned extrinsics disabled.
|
||||
/// #[runtime::pallet_index(4)]
|
||||
/// #[runtime::disable_unsigned]
|
||||
/// pub type Test4 = test4;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Legacy Ordering
|
||||
///
|
||||
/// An optional attribute can be defined as #[frame_support::runtime(legacy_ordering)] to
|
||||
/// ensure that the order of hooks is same as the order of pallets (and not based on the
|
||||
/// pallet_index). This is to support legacy runtimes and should be avoided for new ones.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The population of the genesis storage depends on the order of pallets. So, if one of your
|
||||
/// pallets depends on another pallet, the pallet that is depended upon needs to come before
|
||||
/// the pallet depending on it.
|
||||
///
|
||||
/// # Type definitions
|
||||
///
|
||||
/// * The macro generates a type alias for each pallet to their `Pallet`. E.g. `type System =
|
||||
/// frame_system::Pallet<Runtime>`
|
||||
#[cfg(feature = "experimental")]
|
||||
#[proc_macro_attribute]
|
||||
pub fn runtime(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
runtime::runtime(attr, item)
|
||||
}
|
||||
|
||||
/// Mark a module that contains dynamic parameters.
|
||||
///
|
||||
/// See the `pallet_parameters` for a full example.
|
||||
|
||||
@@ -28,6 +28,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span());
|
||||
let extra_parts_unique_id =
|
||||
syn::Ident::new(&format!("__tt_extra_parts_{}", count), def.item.span());
|
||||
let default_parts_unique_id_v2 =
|
||||
syn::Ident::new(&format!("__tt_default_parts_v2_{}", count), def.item.span());
|
||||
|
||||
let call_part = def.call.as_ref().map(|_| quote::quote!(Call,));
|
||||
|
||||
@@ -81,6 +83,58 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_)))
|
||||
.then_some(quote::quote!(SlashReason,));
|
||||
|
||||
let call_part_v2 = def.call.as_ref().map(|_| quote::quote!(+ Call));
|
||||
|
||||
let task_part_v2 = def.task_enum.as_ref().map(|_| quote::quote!(+ Task));
|
||||
|
||||
let storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage));
|
||||
|
||||
let event_part_v2 = def.event.as_ref().map(|event| {
|
||||
let gen = event.gen_kind.is_generic().then(|| quote::quote!(<T>));
|
||||
quote::quote!(+ Event #gen)
|
||||
});
|
||||
|
||||
let error_part_v2 = def.error.as_ref().map(|_| quote::quote!(+ Error<T>));
|
||||
|
||||
let origin_part_v2 = def.origin.as_ref().map(|origin| {
|
||||
let gen = origin.is_generic.then(|| quote::quote!(<T>));
|
||||
quote::quote!(+ Origin #gen)
|
||||
});
|
||||
|
||||
let config_part_v2 = 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_v2 = def.inherent.as_ref().map(|_| quote::quote!(+ Inherent));
|
||||
|
||||
let validate_unsigned_part_v2 =
|
||||
def.validate_unsigned.as_ref().map(|_| quote::quote!(+ ValidateUnsigned));
|
||||
|
||||
let freeze_reason_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_)))
|
||||
.then_some(quote::quote!(+ FreezeReason));
|
||||
|
||||
let hold_reason_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_)))
|
||||
.then_some(quote::quote!(+ HoldReason));
|
||||
|
||||
let lock_id_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_)))
|
||||
.then_some(quote::quote!(+ LockId));
|
||||
|
||||
let slash_reason_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_)))
|
||||
.then_some(quote::quote!(+ SlashReason));
|
||||
|
||||
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
|
||||
@@ -138,5 +192,25 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
}
|
||||
|
||||
pub use #extra_parts_unique_id as tt_extra_parts;
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #default_parts_unique_id_v2 {
|
||||
{
|
||||
$caller:tt
|
||||
frame_support = [{ $($frame_support:ident)::* }]
|
||||
} => {
|
||||
$($frame_support)*::__private::tt_return! {
|
||||
$caller
|
||||
tokens = [{
|
||||
+ Pallet #call_part_v2 #storage_part_v2 #event_part_v2 #error_part_v2 #origin_part_v2 #config_part_v2
|
||||
#inherent_part_v2 #validate_unsigned_part_v2 #freeze_reason_part_v2 #task_part_v2
|
||||
#hold_reason_part_v2 #lock_id_part_v2 #slash_reason_part_v2
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use #default_parts_unique_id_v2 as tt_default_parts_v2;
|
||||
)
|
||||
}
|
||||
|
||||
@@ -148,6 +148,12 @@ impl MutItemAttrs for syn::ImplItemFn {
|
||||
}
|
||||
}
|
||||
|
||||
impl MutItemAttrs for syn::ItemType {
|
||||
fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
|
||||
Some(&mut self.attrs)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse for `()`
|
||||
struct Unit;
|
||||
impl syn::parse::Parse for Unit {
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 super::parse::runtime_types::RuntimeType;
|
||||
use crate::{
|
||||
construct_runtime::{
|
||||
check_pallet_number, decl_all_pallets, decl_integrity_test, decl_pallet_runtime_setup,
|
||||
decl_static_assertions, expand,
|
||||
},
|
||||
runtime::{
|
||||
parse::{
|
||||
AllPalletsDeclaration, ExplicitAllPalletsDeclaration, ImplicitAllPalletsDeclaration,
|
||||
},
|
||||
Def,
|
||||
},
|
||||
};
|
||||
use cfg_expr::Predicate;
|
||||
use frame_support_procedural_tools::{
|
||||
generate_access_from_frame_or_crate, generate_crate_access, generate_hidden_includes,
|
||||
};
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use std::collections::HashSet;
|
||||
use syn::{Ident, Result};
|
||||
|
||||
/// The fixed name of the system pallet.
|
||||
const SYSTEM_PALLET_NAME: &str = "System";
|
||||
|
||||
pub fn expand(def: Def, legacy_ordering: bool) -> TokenStream2 {
|
||||
let input = def.input;
|
||||
|
||||
let (check_pallet_number_res, res) = match def.pallets {
|
||||
AllPalletsDeclaration::Implicit(ref decl) => (
|
||||
check_pallet_number(input.clone(), decl.pallet_count),
|
||||
construct_runtime_implicit_to_explicit(input.into(), decl.clone(), legacy_ordering),
|
||||
),
|
||||
AllPalletsDeclaration::Explicit(ref decl) => (
|
||||
check_pallet_number(input, decl.pallets.len()),
|
||||
construct_runtime_final_expansion(
|
||||
def.runtime_struct.ident.clone(),
|
||||
decl.clone(),
|
||||
def.runtime_types.clone(),
|
||||
legacy_ordering,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
let res = res.unwrap_or_else(|e| e.to_compile_error());
|
||||
|
||||
// We want to provide better error messages to the user and thus, handle the error here
|
||||
// separately. If there is an error, we print the error and still generate all of the code to
|
||||
// get in overall less errors for the user.
|
||||
let res = if let Err(error) = check_pallet_number_res {
|
||||
let error = error.to_compile_error();
|
||||
|
||||
quote! {
|
||||
#error
|
||||
|
||||
#res
|
||||
}
|
||||
} else {
|
||||
res
|
||||
};
|
||||
|
||||
let res = expander::Expander::new("construct_runtime")
|
||||
.dry(std::env::var("FRAME_EXPAND").is_err())
|
||||
.verbose(true)
|
||||
.write_to_out_dir(res)
|
||||
.expect("Does not fail because of IO in OUT_DIR; qed");
|
||||
|
||||
res.into()
|
||||
}
|
||||
|
||||
fn construct_runtime_implicit_to_explicit(
|
||||
input: TokenStream2,
|
||||
definition: ImplicitAllPalletsDeclaration,
|
||||
legacy_ordering: bool,
|
||||
) -> Result<TokenStream2> {
|
||||
let frame_support = generate_access_from_frame_or_crate("frame-support")?;
|
||||
let attr = if legacy_ordering { quote!((legacy_ordering)) } else { quote!() };
|
||||
let mut expansion = quote::quote!(
|
||||
#[frame_support::runtime #attr]
|
||||
#input
|
||||
);
|
||||
for pallet in definition.pallet_decls.iter() {
|
||||
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::__private::tt_call! {
|
||||
macro = [{ #pallet_path::tt_default_parts_v2 }]
|
||||
frame_support = [{ #frame_support }]
|
||||
~~> #frame_support::match_and_insert! {
|
||||
target = [{ #expansion }]
|
||||
pattern = [{ #pallet_name = #pallet_path #pallet_instance }]
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok(expansion)
|
||||
}
|
||||
|
||||
fn construct_runtime_final_expansion(
|
||||
name: Ident,
|
||||
definition: ExplicitAllPalletsDeclaration,
|
||||
runtime_types: Vec<RuntimeType>,
|
||||
legacy_ordering: bool,
|
||||
) -> Result<TokenStream2> {
|
||||
let ExplicitAllPalletsDeclaration { mut pallets, name: pallets_name } = definition;
|
||||
|
||||
if !legacy_ordering {
|
||||
// Ensure that order of hooks is based on the pallet index
|
||||
pallets.sort_by_key(|p| p.index);
|
||||
}
|
||||
|
||||
let system_pallet =
|
||||
pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| {
|
||||
syn::Error::new(
|
||||
pallets_name.span(),
|
||||
"`System` pallet declaration is missing. \
|
||||
Please add this line: `pub type System = frame_system;`",
|
||||
)
|
||||
})?;
|
||||
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 frame_system = generate_access_from_frame_or_crate("frame-system")?;
|
||||
let block = quote!(<#name as #frame_system::Config>::Block);
|
||||
let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic);
|
||||
|
||||
let mut dispatch = None;
|
||||
let mut outer_event = None;
|
||||
let mut outer_error = None;
|
||||
let mut outer_origin = None;
|
||||
let mut freeze_reason = None;
|
||||
let mut hold_reason = None;
|
||||
let mut slash_reason = None;
|
||||
let mut lock_id = None;
|
||||
let mut task = None;
|
||||
|
||||
for runtime_type in runtime_types.iter() {
|
||||
match runtime_type {
|
||||
RuntimeType::RuntimeCall(_) => {
|
||||
dispatch =
|
||||
Some(expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate));
|
||||
},
|
||||
RuntimeType::RuntimeEvent(_) => {
|
||||
outer_event = Some(expand::expand_outer_enum(
|
||||
&name,
|
||||
&pallets,
|
||||
&scrate,
|
||||
expand::OuterEnumType::Event,
|
||||
)?);
|
||||
},
|
||||
RuntimeType::RuntimeError(_) => {
|
||||
outer_error = Some(expand::expand_outer_enum(
|
||||
&name,
|
||||
&pallets,
|
||||
&scrate,
|
||||
expand::OuterEnumType::Error,
|
||||
)?);
|
||||
},
|
||||
RuntimeType::RuntimeOrigin(_) => {
|
||||
outer_origin =
|
||||
Some(expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?);
|
||||
},
|
||||
RuntimeType::RuntimeFreezeReason(_) => {
|
||||
freeze_reason = Some(expand::expand_outer_freeze_reason(&pallets, &scrate));
|
||||
},
|
||||
RuntimeType::RuntimeHoldReason(_) => {
|
||||
hold_reason = Some(expand::expand_outer_hold_reason(&pallets, &scrate));
|
||||
},
|
||||
RuntimeType::RuntimeSlashReason(_) => {
|
||||
slash_reason = Some(expand::expand_outer_slash_reason(&pallets, &scrate));
|
||||
},
|
||||
RuntimeType::RuntimeLockId(_) => {
|
||||
lock_id = Some(expand::expand_outer_lock_id(&pallets, &scrate));
|
||||
},
|
||||
RuntimeType::RuntimeTask(_) => {
|
||||
task = Some(expand::expand_outer_task(&name, &pallets, &scrate));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let all_pallets = decl_all_pallets(&name, pallets.iter(), &features);
|
||||
let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate);
|
||||
|
||||
let metadata = expand::expand_runtime_metadata(
|
||||
&name,
|
||||
&pallets,
|
||||
&scrate,
|
||||
&unchecked_extrinsic,
|
||||
&system_pallet.path,
|
||||
);
|
||||
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::__private::scale_info::TypeInfo
|
||||
)]
|
||||
pub struct #name;
|
||||
impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name {
|
||||
type RuntimeBlock = #block;
|
||||
}
|
||||
|
||||
// Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata.
|
||||
// The function is implemented by calling `impl_runtime_apis!`.
|
||||
//
|
||||
// However, the `runtime` may be used without calling `impl_runtime_apis!`.
|
||||
// Rely on the `Deref` trait to differentiate between a runtime that implements
|
||||
// APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro runtime).
|
||||
//
|
||||
// Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function.
|
||||
// `InternalConstructRuntime` is implemented by the `runtime` for Runtime references (`& Runtime`),
|
||||
// while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`).
|
||||
//
|
||||
// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
|
||||
// when both macros are called; and will resolve an empty `runtime_metadata` when only the `runtime`
|
||||
// is used.
|
||||
|
||||
#[doc(hidden)]
|
||||
trait InternalConstructRuntime {
|
||||
#[inline(always)]
|
||||
fn runtime_metadata(&self) -> #scrate::__private::sp_std::vec::Vec<#scrate::__private::metadata_ir::RuntimeApiMetadataIR> {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
impl InternalConstructRuntime for &#name {}
|
||||
|
||||
#outer_event
|
||||
|
||||
#outer_error
|
||||
|
||||
#outer_origin
|
||||
|
||||
#all_pallets
|
||||
|
||||
#pallet_to_index
|
||||
|
||||
#dispatch
|
||||
|
||||
#task
|
||||
|
||||
#metadata
|
||||
|
||||
#outer_config
|
||||
|
||||
#inherent
|
||||
|
||||
#validate_unsigned
|
||||
|
||||
#freeze_reason
|
||||
|
||||
#hold_reason
|
||||
|
||||
#lock_id
|
||||
|
||||
#slash_reason
|
||||
|
||||
#integrity_test
|
||||
|
||||
#static_assertions
|
||||
);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 `runtime`.
|
||||
//!
|
||||
//! `runtime` implementation is recursive and can generate code which will call itself
|
||||
//! in order to get all the pallet parts for each pallet.
|
||||
//!
|
||||
//! Pallets can define their parts:
|
||||
//! - Implicitly: `pub type System = frame_system;`
|
||||
//! - Explicitly: `pub type System = frame_system + Pallet + Call;`
|
||||
//!
|
||||
//! The `runtime` transitions from the implicit definition to the explicit one.
|
||||
//! From the explicit state, Substrate expands the pallets with additional information
|
||||
//! that is to be included in the runtime metadata.
|
||||
//!
|
||||
//! Pallets must provide the `tt_default_parts_v2` macro for these transitions.
|
||||
//! These are automatically implemented by the `#[pallet::pallet]` macro.
|
||||
//!
|
||||
//! This macro also generates the following enums for ease of decoding if the respective type
|
||||
//! is defined inside `#[runtime::derive]`:
|
||||
//! - `enum RuntimeCall`: This type contains the information needed to decode extrinsics.
|
||||
//! - `enum RuntimeEvent`: This type contains the information needed to decode events.
|
||||
//! - `enum RuntimeError`: While this cannot be used directly to decode `sp_runtime::DispatchError`
|
||||
//! from the chain, it contains the information needed to decode the
|
||||
//! `sp_runtime::DispatchError::Module`.
|
||||
//!
|
||||
//! # State Transitions
|
||||
//!
|
||||
//! ```ignore
|
||||
//! +----------+
|
||||
//! | Implicit |
|
||||
//! +----------+
|
||||
//! |
|
||||
//! v
|
||||
//! +----------+
|
||||
//! | Explicit |
|
||||
//! +----------+
|
||||
//! ```
|
||||
//!
|
||||
//! The `runtime` macro transforms the implicit declaration of each pallet
|
||||
//! `System: frame_system` to an explicit one `System: frame_system + Pallet + Call` using the
|
||||
//! `tt_default_parts_v2` macro.
|
||||
//!
|
||||
//! The `tt_default_parts_v2` macro exposes a plus separated list of pallet parts. For example, the
|
||||
//! `Event` part is exposed only if the pallet implements an event via `#[pallet::event]` macro.
|
||||
//! The tokens generated by this macro are `+ Pallet + Call` for our example.
|
||||
//!
|
||||
//! The `match_and_insert` macro takes in 3 arguments:
|
||||
//! - target: This is the `TokenStream` that contains the `runtime` macro.
|
||||
//! - pattern: The pattern to match against in the target stream.
|
||||
//! - tokens: The tokens to added after the pattern match.
|
||||
//!
|
||||
//! The `runtime` macro uses the `tt_call` to get the default pallet parts via
|
||||
//! the `tt_default_parts_v2` macro defined by each pallet. The pallet parts are then returned as
|
||||
//! input to the `match_and_replace` macro.
|
||||
//! The `match_and_replace` then will modify the `runtime` to expand the implicit
|
||||
//! definition to the explicit one.
|
||||
//!
|
||||
//! For example,
|
||||
//!
|
||||
//! ```ignore
|
||||
//! #[frame_support::runtime]
|
||||
//! mod runtime {
|
||||
//! //...
|
||||
//!
|
||||
//! #[runtime::pallet_index(0)]
|
||||
//! pub type System = frame_system; // Implicit definition of parts
|
||||
//!
|
||||
//! #[runtime::pallet_index(1)]
|
||||
//! pub type Balances = pallet_balances; // Implicit definition of parts
|
||||
//! }
|
||||
//! ```
|
||||
//! This call has some implicit pallet parts, thus it will expand to:
|
||||
//! ```ignore
|
||||
//! frame_support::__private::tt_call! {
|
||||
//! macro = [{ pallet_balances::tt_default_parts_v2 }]
|
||||
//! ~~> frame_support::match_and_insert! {
|
||||
//! target = [{
|
||||
//! frame_support::__private::tt_call! {
|
||||
//! macro = [{ frame_system::tt_default_parts_v2 }]
|
||||
//! ~~> frame_support::match_and_insert! {
|
||||
//! target = [{
|
||||
//! #[frame_support::runtime]
|
||||
//! mod runtime {
|
||||
//! //...
|
||||
//!
|
||||
//! #[runtime::pallet_index(0)]
|
||||
//! pub type System = frame_system;
|
||||
//!
|
||||
//! #[runtime::pallet_index(1)]
|
||||
//! pub type Balances = pallet_balances;
|
||||
//! }
|
||||
//! }]
|
||||
//! pattern = [{ System = frame_system }]
|
||||
//! }
|
||||
//! }
|
||||
//! }]
|
||||
//! pattern = [{ Balances = pallet_balances }]
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//! `tt_default_parts_v2` 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 = [{
|
||||
//! #[frame_support::runtime]
|
||||
//! mod runtime {
|
||||
//! //...
|
||||
//!
|
||||
//! #[runtime::pallet_index(0)]
|
||||
//! pub type System = frame_system;
|
||||
//!
|
||||
//! #[runtime::pallet_index(1)]
|
||||
//! pub type Balances = pallet_balances;
|
||||
//! }
|
||||
//! }]
|
||||
//! 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 = [{
|
||||
//! #[frame_support::runtime]
|
||||
//! mod runtime {
|
||||
//! //...
|
||||
//!
|
||||
//! #[runtime::pallet_index(0)]
|
||||
//! pub type System = frame_system; // Implicit definition of parts
|
||||
//!
|
||||
//! #[runtime::pallet_index(1)]
|
||||
//! pub type Balances = pallet_balances + Pallet + Call; // Explicit definition of parts
|
||||
//! }
|
||||
//! }]
|
||||
//! pattern = [{ System = frame_system }]
|
||||
//! tokens = [{ ::{+ Pallet + Call} }]
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Which will then finally expand to the following:
|
||||
//! ```ignore
|
||||
//! #[frame_support::runtime]
|
||||
//! mod runtime {
|
||||
//! //...
|
||||
//!
|
||||
//! #[runtime::pallet_index(0)]
|
||||
//! pub type System = frame_system + Pallet + Call;
|
||||
//!
|
||||
//! #[runtime::pallet_index(1)]
|
||||
//! pub type 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 `#[frame_support::runtime]`, it would look like the following:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! +----------------------+ +------------------------+ +-------------------+
|
||||
//! | | | (defined in pallet) | | |
|
||||
//! | runtime | --> | tt_default_parts_v2! | --> | match_and_insert! |
|
||||
//! | w/ no pallet parts | | | | |
|
||||
//! +----------------------+ +------------------------+ +-------------------+
|
||||
//!
|
||||
//! +----------------------+
|
||||
//! | |
|
||||
//! --> | runtime |
|
||||
//! | w/ pallet parts |
|
||||
//! +----------------------+
|
||||
//! ```
|
||||
|
||||
#![cfg(feature = "experimental")]
|
||||
|
||||
pub use parse::Def;
|
||||
use proc_macro::TokenStream;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
mod expand;
|
||||
mod parse;
|
||||
|
||||
mod keyword {
|
||||
syn::custom_keyword!(legacy_ordering);
|
||||
}
|
||||
|
||||
pub fn runtime(attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
let mut legacy_ordering = false;
|
||||
if !attr.is_empty() {
|
||||
if let Ok(_) = syn::parse::<keyword::legacy_ordering>(attr.clone()) {
|
||||
legacy_ordering = true;
|
||||
} else {
|
||||
let msg = "Invalid runtime macro call: unexpected attribute. Macro call must be \
|
||||
bare, such as `#[frame_support::runtime]` or `#[runtime]`, or must specify the \
|
||||
`legacy_ordering` attribute, such as `#[frame_support::runtime(legacy_ordering)]` or \
|
||||
#[runtime(legacy_ordering)].";
|
||||
let span = proc_macro2::TokenStream::from(attr).span();
|
||||
return syn::Error::new(span, msg).to_compile_error().into()
|
||||
}
|
||||
}
|
||||
|
||||
let item = syn::parse_macro_input!(tokens as syn::ItemMod);
|
||||
match parse::Def::try_from(item) {
|
||||
Ok(def) => expand::expand(def, legacy_ordering).into(),
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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::parse::helper::MutItemAttrs;
|
||||
use quote::ToTokens;
|
||||
|
||||
pub(crate) fn take_first_item_runtime_attr<Attr>(
|
||||
item: &mut impl MutItemAttrs,
|
||||
) -> syn::Result<Option<Attr>>
|
||||
where
|
||||
Attr: syn::parse::Parse,
|
||||
{
|
||||
let attrs = if let Some(attrs) = item.mut_item_attrs() { attrs } else { return Ok(None) };
|
||||
|
||||
if let Some(index) = attrs.iter().position(|attr| {
|
||||
attr.path().segments.first().map_or(false, |segment| segment.ident == "runtime")
|
||||
}) {
|
||||
let runtime_attr = attrs.remove(index);
|
||||
Ok(Some(syn::parse2(runtime_attr.into_token_stream())?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
pub mod helper;
|
||||
pub mod pallet;
|
||||
pub mod pallet_decl;
|
||||
pub mod runtime_struct;
|
||||
pub mod runtime_types;
|
||||
|
||||
use crate::construct_runtime::parse::Pallet;
|
||||
use pallet_decl::PalletDeclaration;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::ToTokens;
|
||||
use std::collections::HashMap;
|
||||
use syn::{spanned::Spanned, Ident, Token};
|
||||
|
||||
use frame_support_procedural_tools::syn_ext as ext;
|
||||
use runtime_types::RuntimeType;
|
||||
|
||||
mod keyword {
|
||||
use syn::custom_keyword;
|
||||
|
||||
custom_keyword!(runtime);
|
||||
custom_keyword!(derive);
|
||||
custom_keyword!(pallet_index);
|
||||
custom_keyword!(disable_call);
|
||||
custom_keyword!(disable_unsigned);
|
||||
}
|
||||
|
||||
enum RuntimeAttr {
|
||||
Runtime(proc_macro2::Span),
|
||||
Derive(proc_macro2::Span, Vec<RuntimeType>),
|
||||
PalletIndex(proc_macro2::Span, u8),
|
||||
DisableCall(proc_macro2::Span),
|
||||
DisableUnsigned(proc_macro2::Span),
|
||||
}
|
||||
|
||||
impl RuntimeAttr {
|
||||
fn span(&self) -> proc_macro2::Span {
|
||||
match self {
|
||||
Self::Runtime(span) => *span,
|
||||
Self::Derive(span, _) => *span,
|
||||
Self::PalletIndex(span, _) => *span,
|
||||
Self::DisableCall(span) => *span,
|
||||
Self::DisableUnsigned(span) => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for RuntimeAttr {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
input.parse::<syn::Token![#]>()?;
|
||||
let content;
|
||||
syn::bracketed!(content in input);
|
||||
content.parse::<keyword::runtime>()?;
|
||||
content.parse::<syn::Token![::]>()?;
|
||||
|
||||
let lookahead = content.lookahead1();
|
||||
if lookahead.peek(keyword::runtime) {
|
||||
Ok(RuntimeAttr::Runtime(content.parse::<keyword::runtime>()?.span()))
|
||||
} else if lookahead.peek(keyword::derive) {
|
||||
let _ = content.parse::<keyword::derive>();
|
||||
let derive_content;
|
||||
syn::parenthesized!(derive_content in content);
|
||||
let runtime_types =
|
||||
derive_content.parse::<ext::Punctuated<RuntimeType, Token![,]>>()?;
|
||||
let runtime_types = runtime_types.inner.into_iter().collect();
|
||||
Ok(RuntimeAttr::Derive(derive_content.span(), runtime_types))
|
||||
} else if lookahead.peek(keyword::pallet_index) {
|
||||
let _ = content.parse::<keyword::pallet_index>();
|
||||
let pallet_index_content;
|
||||
syn::parenthesized!(pallet_index_content in content);
|
||||
let pallet_index = pallet_index_content.parse::<syn::LitInt>()?;
|
||||
if !pallet_index.suffix().is_empty() {
|
||||
let msg = "Number literal must not have a suffix";
|
||||
return Err(syn::Error::new(pallet_index.span(), msg))
|
||||
}
|
||||
Ok(RuntimeAttr::PalletIndex(pallet_index.span(), pallet_index.base10_parse()?))
|
||||
} else if lookahead.peek(keyword::disable_call) {
|
||||
Ok(RuntimeAttr::DisableCall(content.parse::<keyword::disable_call>()?.span()))
|
||||
} else if lookahead.peek(keyword::disable_unsigned) {
|
||||
Ok(RuntimeAttr::DisableUnsigned(content.parse::<keyword::disable_unsigned>()?.span()))
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AllPalletsDeclaration {
|
||||
Implicit(ImplicitAllPalletsDeclaration),
|
||||
Explicit(ExplicitAllPalletsDeclaration),
|
||||
}
|
||||
|
||||
/// Declaration of a runtime with some pallet with implicit declaration of parts.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImplicitAllPalletsDeclaration {
|
||||
pub name: Ident,
|
||||
pub pallet_decls: Vec<PalletDeclaration>,
|
||||
pub pallet_count: usize,
|
||||
}
|
||||
|
||||
/// Declaration of a runtime with all pallet having explicit declaration of parts.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExplicitAllPalletsDeclaration {
|
||||
pub name: Ident,
|
||||
pub pallets: Vec<Pallet>,
|
||||
}
|
||||
|
||||
pub struct Def {
|
||||
pub input: TokenStream2,
|
||||
pub item: syn::ItemMod,
|
||||
pub runtime_struct: runtime_struct::RuntimeStructDef,
|
||||
pub pallets: AllPalletsDeclaration,
|
||||
pub runtime_types: Vec<RuntimeType>,
|
||||
}
|
||||
|
||||
impl Def {
|
||||
pub fn try_from(mut item: syn::ItemMod) -> syn::Result<Self> {
|
||||
let input: TokenStream2 = item.to_token_stream().into();
|
||||
let item_span = item.span();
|
||||
let items = &mut item
|
||||
.content
|
||||
.as_mut()
|
||||
.ok_or_else(|| {
|
||||
let msg = "Invalid runtime definition, expected mod to be inlined.";
|
||||
syn::Error::new(item_span, msg)
|
||||
})?
|
||||
.1;
|
||||
|
||||
let mut runtime_struct = None;
|
||||
let mut runtime_types = None;
|
||||
|
||||
let mut indices = HashMap::new();
|
||||
let mut names = HashMap::new();
|
||||
|
||||
let mut pallet_decls = vec![];
|
||||
let mut pallets = vec![];
|
||||
|
||||
for item in items.iter_mut() {
|
||||
let mut pallet_item = None;
|
||||
let mut pallet_index = 0;
|
||||
|
||||
let mut disable_call = false;
|
||||
let mut disable_unsigned = false;
|
||||
|
||||
while let Some(runtime_attr) =
|
||||
helper::take_first_item_runtime_attr::<RuntimeAttr>(item)?
|
||||
{
|
||||
match runtime_attr {
|
||||
RuntimeAttr::Runtime(span) if runtime_struct.is_none() => {
|
||||
let p = runtime_struct::RuntimeStructDef::try_from(span, item)?;
|
||||
runtime_struct = Some(p);
|
||||
},
|
||||
RuntimeAttr::Derive(_, types) if runtime_types.is_none() => {
|
||||
runtime_types = Some(types);
|
||||
},
|
||||
RuntimeAttr::PalletIndex(span, index) => {
|
||||
pallet_index = index;
|
||||
pallet_item = if let syn::Item::Type(item) = item {
|
||||
Some(item.clone())
|
||||
} else {
|
||||
let msg = "Invalid runtime::pallet_index, expected type definition";
|
||||
return Err(syn::Error::new(span, msg))
|
||||
};
|
||||
},
|
||||
RuntimeAttr::DisableCall(_) => disable_call = true,
|
||||
RuntimeAttr::DisableUnsigned(_) => disable_unsigned = true,
|
||||
attr => {
|
||||
let msg = "Invalid duplicated attribute";
|
||||
return Err(syn::Error::new(attr.span(), msg))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pallet_item) = pallet_item {
|
||||
match *pallet_item.ty.clone() {
|
||||
syn::Type::Path(ref path) => {
|
||||
let pallet_decl =
|
||||
PalletDeclaration::try_from(item.span(), &pallet_item, path)?;
|
||||
|
||||
if let Some(used_pallet) =
|
||||
names.insert(pallet_decl.name.clone(), pallet_decl.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_decl.name.span(), &msg));
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
pallet_decls.push(pallet_decl);
|
||||
},
|
||||
syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => {
|
||||
let pallet = Pallet::try_from(
|
||||
item.span(),
|
||||
&pallet_item,
|
||||
pallet_index,
|
||||
disable_call,
|
||||
disable_unsigned,
|
||||
&bounds,
|
||||
)?;
|
||||
|
||||
if let Some(used_pallet) = indices.insert(pallet.index, pallet.name.clone())
|
||||
{
|
||||
let msg = format!(
|
||||
"Pallet indices are conflicting: Both pallets {} and {} are at index {}",
|
||||
used_pallet, pallet.name, pallet.index,
|
||||
);
|
||||
let mut err = syn::Error::new(used_pallet.span(), &msg);
|
||||
err.combine(syn::Error::new(pallet.name.span(), msg));
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
pallets.push(pallet);
|
||||
},
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let name = item.ident.clone();
|
||||
let decl_count = pallet_decls.len();
|
||||
let pallets = if decl_count > 0 {
|
||||
AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration {
|
||||
name,
|
||||
pallet_decls,
|
||||
pallet_count: decl_count.saturating_add(pallets.len()),
|
||||
})
|
||||
} else {
|
||||
AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { name, pallets })
|
||||
};
|
||||
|
||||
let def = Def {
|
||||
input,
|
||||
item,
|
||||
runtime_struct: runtime_struct.ok_or_else(|| {
|
||||
syn::Error::new(item_span,
|
||||
"Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]`"
|
||||
)
|
||||
})?,
|
||||
pallets,
|
||||
runtime_types: runtime_types.ok_or_else(|| {
|
||||
syn::Error::new(item_span,
|
||||
"Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]`"
|
||||
)
|
||||
})?,
|
||||
};
|
||||
|
||||
Ok(def)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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::construct_runtime::parse::{Pallet, PalletPart, PalletPartKeyword, PalletPath};
|
||||
use quote::ToTokens;
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, token, Error, Ident, PathArguments};
|
||||
|
||||
impl Pallet {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
item: &syn::ItemType,
|
||||
pallet_index: u8,
|
||||
disable_call: bool,
|
||||
disable_unsigned: bool,
|
||||
bounds: &Punctuated<syn::TypeParamBound, token::Plus>,
|
||||
) -> syn::Result<Self> {
|
||||
let name = item.ident.clone();
|
||||
|
||||
let mut pallet_path = None;
|
||||
let mut pallet_parts = vec![];
|
||||
|
||||
for (index, bound) in bounds.into_iter().enumerate() {
|
||||
if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound {
|
||||
if index == 0 {
|
||||
pallet_path = Some(PalletPath { inner: path.clone() });
|
||||
} else {
|
||||
let pallet_part = syn::parse2::<PalletPart>(bound.into_token_stream())?;
|
||||
pallet_parts.push(pallet_part);
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
attr_span,
|
||||
"Invalid pallet declaration, expected a path or a trait object",
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
let mut path = pallet_path.ok_or(Error::new(
|
||||
attr_span,
|
||||
"Invalid pallet declaration, expected a path or a trait object",
|
||||
))?;
|
||||
|
||||
let mut instance = None;
|
||||
if let Some(segment) = path.inner.segments.iter_mut().find(|seg| !seg.arguments.is_empty())
|
||||
{
|
||||
if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
||||
args, ..
|
||||
}) = segment.arguments.clone()
|
||||
{
|
||||
if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() {
|
||||
instance =
|
||||
Some(Ident::new(&arg_path.to_token_stream().to_string(), arg_path.span()));
|
||||
segment.arguments = PathArguments::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pallet_parts = pallet_parts
|
||||
.into_iter()
|
||||
.filter(|part| {
|
||||
if let (true, &PalletPartKeyword::Call(_)) = (disable_call, &part.keyword) {
|
||||
false
|
||||
} else if let (true, &PalletPartKeyword::ValidateUnsigned(_)) =
|
||||
(disable_unsigned, &part.keyword)
|
||||
{
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let cfg_pattern = vec![];
|
||||
|
||||
Ok(Pallet {
|
||||
is_expanded: true,
|
||||
name,
|
||||
index: pallet_index,
|
||||
path,
|
||||
instance,
|
||||
cfg_pattern,
|
||||
pallet_parts,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 quote::ToTokens;
|
||||
use syn::{spanned::Spanned, Attribute, Ident, PathArguments};
|
||||
|
||||
/// The declaration of a pallet.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PalletDeclaration {
|
||||
/// The name of the pallet, e.g.`System` in `System: frame_system`.
|
||||
pub name: Ident,
|
||||
/// Optional attributes tagged right above a pallet declaration.
|
||||
pub attrs: Vec<Attribute>,
|
||||
/// The path of the pallet, e.g. `frame_system` in `System: frame_system`.
|
||||
pub path: syn::Path,
|
||||
/// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::<Instance1>`.
|
||||
pub instance: Option<Ident>,
|
||||
}
|
||||
|
||||
impl PalletDeclaration {
|
||||
pub fn try_from(
|
||||
_attr_span: proc_macro2::Span,
|
||||
item: &syn::ItemType,
|
||||
path: &syn::TypePath,
|
||||
) -> syn::Result<Self> {
|
||||
let name = item.ident.clone();
|
||||
|
||||
let mut path = path.path.clone();
|
||||
|
||||
let mut instance = None;
|
||||
if let Some(segment) = path.segments.iter_mut().find(|seg| !seg.arguments.is_empty()) {
|
||||
if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
||||
args, ..
|
||||
}) = segment.arguments.clone()
|
||||
{
|
||||
if let Some(syn::GenericArgument::Type(syn::Type::Path(arg_path))) = args.first() {
|
||||
instance =
|
||||
Some(Ident::new(&arg_path.to_token_stream().to_string(), arg_path.span()));
|
||||
segment.arguments = PathArguments::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { name, path, instance, attrs: item.attrs.clone() })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 syn::spanned::Spanned;
|
||||
pub struct RuntimeStructDef {
|
||||
pub ident: syn::Ident,
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
impl RuntimeStructDef {
|
||||
pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Struct(item) = item {
|
||||
item
|
||||
} else {
|
||||
let msg = "Invalid runtime::runtime, expected struct definition";
|
||||
return Err(syn::Error::new(item.span(), msg))
|
||||
};
|
||||
|
||||
Ok(Self { ident: item.ident.clone(), attr_span })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
Result,
|
||||
};
|
||||
|
||||
mod keyword {
|
||||
use syn::custom_keyword;
|
||||
|
||||
custom_keyword!(RuntimeCall);
|
||||
custom_keyword!(RuntimeEvent);
|
||||
custom_keyword!(RuntimeError);
|
||||
custom_keyword!(RuntimeOrigin);
|
||||
custom_keyword!(RuntimeFreezeReason);
|
||||
custom_keyword!(RuntimeHoldReason);
|
||||
custom_keyword!(RuntimeSlashReason);
|
||||
custom_keyword!(RuntimeLockId);
|
||||
custom_keyword!(RuntimeTask);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RuntimeType {
|
||||
RuntimeCall(keyword::RuntimeCall),
|
||||
RuntimeEvent(keyword::RuntimeEvent),
|
||||
RuntimeError(keyword::RuntimeError),
|
||||
RuntimeOrigin(keyword::RuntimeOrigin),
|
||||
RuntimeFreezeReason(keyword::RuntimeFreezeReason),
|
||||
RuntimeHoldReason(keyword::RuntimeHoldReason),
|
||||
RuntimeSlashReason(keyword::RuntimeSlashReason),
|
||||
RuntimeLockId(keyword::RuntimeLockId),
|
||||
RuntimeTask(keyword::RuntimeTask),
|
||||
}
|
||||
|
||||
impl Parse for RuntimeType {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
|
||||
if lookahead.peek(keyword::RuntimeCall) {
|
||||
Ok(Self::RuntimeCall(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeEvent) {
|
||||
Ok(Self::RuntimeEvent(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeError) {
|
||||
Ok(Self::RuntimeError(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeOrigin) {
|
||||
Ok(Self::RuntimeOrigin(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeFreezeReason) {
|
||||
Ok(Self::RuntimeFreezeReason(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeHoldReason) {
|
||||
Ok(Self::RuntimeHoldReason(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeSlashReason) {
|
||||
Ok(Self::RuntimeSlashReason(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeLockId) {
|
||||
Ok(Self::RuntimeLockId(input.parse()?))
|
||||
} else if lookahead.peek(keyword::RuntimeTask) {
|
||||
Ok(Self::RuntimeTask(input.parse()?))
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -510,6 +510,9 @@ pub use frame_support_procedural::{
|
||||
construct_runtime, match_and_insert, transactional, PalletError, RuntimeDebugNoBound,
|
||||
};
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
pub use frame_support_procedural::runtime;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use frame_support_procedural::{__create_tt_macro, __generate_dummy_part_checker};
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ sp-api = { path = "../../../primitives/api", default-features = false }
|
||||
sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false }
|
||||
sp-io = { path = "../../../primitives/io", default-features = false }
|
||||
sp-state-machine = { path = "../../../primitives/state-machine", optional = true }
|
||||
frame-support = { path = "..", default-features = false }
|
||||
frame-support = { path = "..", default-features = false, features = ["experimental"] }
|
||||
frame-benchmarking = { path = "../../benchmarking", default-features = false }
|
||||
sp-runtime = { path = "../../../primitives/runtime", default-features = false }
|
||||
sp-core = { path = "../../../primitives/core", default-features = false }
|
||||
|
||||
+189
-93
@@ -30,7 +30,7 @@ use scale_info::TypeInfo;
|
||||
use sp_core::{sr25519, ConstU64};
|
||||
use sp_runtime::{
|
||||
generic,
|
||||
traits::{BlakeTwo256, Verify},
|
||||
traits::{BlakeTwo256, ValidateUnsigned, Verify},
|
||||
DispatchError, ModuleError,
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
@@ -176,6 +176,17 @@ mod nested {
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {}
|
||||
}
|
||||
|
||||
#[pallet::validate_unsigned]
|
||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
_call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +258,20 @@ pub mod module3 {
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {}
|
||||
}
|
||||
|
||||
#[pallet::storage]
|
||||
pub type Storage<T> = StorageValue<_, u32>;
|
||||
|
||||
#[pallet::validate_unsigned]
|
||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
_call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type BlockNumber = u64;
|
||||
@@ -256,24 +281,64 @@ pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, RuntimeCall, Signature, ()>;
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
|
||||
frame_support::construct_runtime!(
|
||||
pub struct Runtime
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Event<T>, Origin<T>} = 30,
|
||||
Module1_1: module1::<Instance1>::{Pallet, Call, Storage, Event<T>, Origin<T>},
|
||||
Module2: module2::{Pallet, Call, Storage, Event<T>, Origin},
|
||||
Module1_2: module1::<Instance2>::{Pallet, Call, Storage, Event<T>, Origin<T>},
|
||||
NestedModule3: nested::module3::{Pallet, Call, Config<T>, Storage, Event<T>, Origin},
|
||||
Module3: self::module3::{Pallet, Call, Config<T>, Storage, Event<T>, Origin<T>},
|
||||
Module1_3: module1::<Instance3>::{Pallet, Storage, Event<T> } = 6,
|
||||
Module1_4: module1::<Instance4>::{Pallet, Call, Event<T> } = 3,
|
||||
Module1_5: module1::<Instance5>::{Pallet, Event<T>},
|
||||
Module1_6: module1::<Instance6>::{Pallet, Call, Storage, Event<T>, Origin<T>} = 1,
|
||||
Module1_7: module1::<Instance7>::{Pallet, Call, Storage, Event<T>, Origin<T>},
|
||||
Module1_8: module1::<Instance8>::{Pallet, Call, Storage, Event<T>, Origin<T>} = 12,
|
||||
Module1_9: module1::<Instance9>::{Pallet, Call, Storage, Event<T>, Origin<T>},
|
||||
}
|
||||
);
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(
|
||||
RuntimeCall,
|
||||
RuntimeEvent,
|
||||
RuntimeError,
|
||||
RuntimeOrigin,
|
||||
RuntimeFreezeReason,
|
||||
RuntimeHoldReason,
|
||||
RuntimeSlashReason,
|
||||
RuntimeLockId,
|
||||
RuntimeTask
|
||||
)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index(30)]
|
||||
pub type System = frame_system + Pallet + Call + Event<T> + Origin<T>;
|
||||
|
||||
#[runtime::pallet_index(31)]
|
||||
pub type Module1_1 = module1<Instance1>;
|
||||
|
||||
#[runtime::pallet_index(32)]
|
||||
pub type Module2 = module2;
|
||||
|
||||
#[runtime::pallet_index(33)]
|
||||
pub type Module1_2 = module1<Instance2>;
|
||||
|
||||
#[runtime::pallet_index(34)]
|
||||
pub type NestedModule3 = nested::module3;
|
||||
|
||||
#[runtime::pallet_index(35)]
|
||||
#[runtime::disable_unsigned]
|
||||
pub type Module3 = self::module3;
|
||||
|
||||
#[runtime::pallet_index(6)]
|
||||
#[runtime::disable_call]
|
||||
pub type Module1_3 = module1<Instance3>;
|
||||
|
||||
#[runtime::pallet_index(3)]
|
||||
pub type Module1_4 = module1<Instance4>;
|
||||
|
||||
#[runtime::pallet_index(4)]
|
||||
#[runtime::disable_call]
|
||||
pub type Module1_5 = module1<Instance5>;
|
||||
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type Module1_6 = module1<Instance6>;
|
||||
|
||||
#[runtime::pallet_index(2)]
|
||||
pub type Module1_7 = module1<Instance7>;
|
||||
|
||||
#[runtime::pallet_index(12)]
|
||||
pub type Module1_8 = module1<Instance8>;
|
||||
|
||||
#[runtime::pallet_index(13)]
|
||||
pub type Module1_9 = module1<Instance9>;
|
||||
}
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
@@ -605,17 +670,17 @@ fn get_module_names() {
|
||||
let module_names = RuntimeCall::get_module_names();
|
||||
assert_eq!(
|
||||
[
|
||||
"Module1_6",
|
||||
"Module1_7",
|
||||
"Module1_4",
|
||||
"Module1_8",
|
||||
"Module1_9",
|
||||
"System",
|
||||
"Module1_1",
|
||||
"Module2",
|
||||
"Module1_2",
|
||||
"NestedModule3",
|
||||
"Module3",
|
||||
"Module1_4",
|
||||
"Module1_6",
|
||||
"Module1_7",
|
||||
"Module1_8",
|
||||
"Module1_9",
|
||||
],
|
||||
module_names
|
||||
);
|
||||
@@ -636,9 +701,13 @@ fn call_subtype_conversion() {
|
||||
|
||||
#[test]
|
||||
fn test_metadata() {
|
||||
use frame_metadata::{v14::*, *};
|
||||
use frame_metadata::{
|
||||
v14::{StorageEntryType::Plain, *},
|
||||
*,
|
||||
};
|
||||
use scale_info::meta_type;
|
||||
use sp_core::Encode;
|
||||
use sp_metadata_ir::StorageEntryModifierIR::Optional;
|
||||
|
||||
fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> {
|
||||
if cfg!(feature = "no-metadata-docs") {
|
||||
@@ -649,6 +718,69 @@ fn test_metadata() {
|
||||
}
|
||||
|
||||
let pallets = vec![
|
||||
PalletMetadata {
|
||||
name: "Module1_6",
|
||||
storage:None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance6>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance6>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance6>>().into()),
|
||||
index: 1,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_7",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance7>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance7>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance7>>().into()),
|
||||
index: 2,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_4",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance4>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance4>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance4>>().into()),
|
||||
index: 3,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_5",
|
||||
storage: None,
|
||||
calls: None,
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance5>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance5>>().into()),
|
||||
index: 4,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_3",
|
||||
storage: None,
|
||||
calls: None,
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance3>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance3>>().into()),
|
||||
index: 6,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_8",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance8>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance8>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance8>>().into()),
|
||||
index: 12,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_9",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance9>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance9>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance9>>().into()),
|
||||
index: 13,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "System",
|
||||
storage: None,
|
||||
@@ -703,7 +835,7 @@ fn test_metadata() {
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_1",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_1", entries: vec![] }),
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance1>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance1>>().into()),
|
||||
constants: vec![],
|
||||
@@ -712,7 +844,7 @@ fn test_metadata() {
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module2",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module2", entries: vec![] }),
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module2::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<module2::Event<Runtime>>().into()),
|
||||
constants: vec![],
|
||||
@@ -721,7 +853,7 @@ fn test_metadata() {
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_2",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_2", entries: vec![] }),
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance2>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance2>>().into()),
|
||||
constants: vec![],
|
||||
@@ -730,7 +862,7 @@ fn test_metadata() {
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "NestedModule3",
|
||||
storage: Some(PalletStorageMetadata { prefix: "NestedModule3", entries: vec![] }),
|
||||
storage: None,
|
||||
calls: Some(meta_type::<nested::module3::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<nested::module3::Event<Runtime>>().into()),
|
||||
constants: vec![],
|
||||
@@ -739,76 +871,24 @@ fn test_metadata() {
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module3",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module3", entries: vec![] }),
|
||||
storage: Some(PalletStorageMetadata {
|
||||
prefix: "Module3",
|
||||
entries: vec![
|
||||
StorageEntryMetadata {
|
||||
name: "Storage",
|
||||
modifier: Optional.into(),
|
||||
ty: Plain(meta_type::<u32>().into()),
|
||||
default: vec![0],
|
||||
docs: vec![],
|
||||
},
|
||||
]
|
||||
}),
|
||||
calls: Some(meta_type::<module3::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<module3::Event<Runtime>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module3::Error<Runtime>>().into()),
|
||||
index: 35,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_3",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_3", entries: vec![] }),
|
||||
calls: None,
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance3>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance3>>().into()),
|
||||
index: 6,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_4",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance4>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance4>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance4>>().into()),
|
||||
index: 3,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_5",
|
||||
storage: None,
|
||||
calls: None,
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance5>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance5>>().into()),
|
||||
index: 4,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_6",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_6", entries: vec![] }),
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance6>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance6>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance6>>().into()),
|
||||
index: 1,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_7",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_7", entries: vec![] }),
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance7>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance7>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance7>>().into()),
|
||||
index: 2,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_8",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_8", entries: vec![] }),
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance8>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance8>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance8>>().into()),
|
||||
index: 12,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_9",
|
||||
storage: Some(PalletStorageMetadata { prefix: "Module1_9", entries: vec![] }),
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance9>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance9>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance9>>().into()),
|
||||
index: 13,
|
||||
},
|
||||
];
|
||||
|
||||
let extrinsic = ExtrinsicMetadata {
|
||||
@@ -895,3 +975,19 @@ fn pallet_in_runtime_is_correct() {
|
||||
assert_eq!(PalletInfo::module_name::<Module1_9>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_9>().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_unsigned() {
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
let call = RuntimeCall::NestedModule3(nested::module3::Call::fail {});
|
||||
let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err();
|
||||
assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call));
|
||||
|
||||
let call = RuntimeCall::Module3(module3::Call::fail {});
|
||||
let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err();
|
||||
assert_eq!(
|
||||
validity,
|
||||
TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,993 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
//! General tests for construct_runtime macro, test for:
|
||||
//! * error declared with decl_error works
|
||||
//! * integrity test is generated
|
||||
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
use codec::MaxEncodedLen;
|
||||
use frame_support::{
|
||||
derive_impl, parameter_types, traits::PalletInfo as _, weights::RuntimeDbWeight,
|
||||
};
|
||||
use frame_system::limits::{BlockLength, BlockWeights};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::{sr25519, ConstU64};
|
||||
use sp_runtime::{
|
||||
generic,
|
||||
traits::{BlakeTwo256, ValidateUnsigned, Verify},
|
||||
DispatchError, ModuleError,
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
parameter_types! {
|
||||
pub static IntegrityTestExec: u32 = 0;
|
||||
}
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
mod module1 {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T, I = ()>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config<I: 'static = ()>: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self, I>>
|
||||
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
pub fn fail(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Err(Error::<T, I>::Something.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::origin]
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[scale_info(skip_type_params(I))]
|
||||
pub struct Origin<T, I = ()>(pub PhantomData<(T, I)>);
|
||||
|
||||
#[pallet::event]
|
||||
pub enum Event<T: Config<I>, I: 'static = ()> {
|
||||
A(<T as frame_system::Config>::AccountId),
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T, I = ()> {
|
||||
Something,
|
||||
}
|
||||
}
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
mod module2 {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn integrity_test() {
|
||||
IntegrityTestExec::mutate(|i| *i += 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn fail(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Err(Error::<T>::Something.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::origin]
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
pub struct Origin;
|
||||
|
||||
#[pallet::event]
|
||||
pub enum Event<T> {
|
||||
A,
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
Something,
|
||||
}
|
||||
}
|
||||
|
||||
mod nested {
|
||||
use super::*;
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod module3 {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self>>
|
||||
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn integrity_test() {
|
||||
IntegrityTestExec::mutate(|i| *i += 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn fail(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Err(Error::<T>::Something.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::origin]
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
pub struct Origin;
|
||||
|
||||
#[pallet::event]
|
||||
pub enum Event<T> {
|
||||
A,
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
Something,
|
||||
}
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(frame_support::DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
#[serde(skip)]
|
||||
pub _config: sp_std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {}
|
||||
}
|
||||
|
||||
#[pallet::validate_unsigned]
|
||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
_call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod module3 {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn fail(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Err(Error::<T>::Something.into())
|
||||
}
|
||||
pub fn aux_1(_origin: OriginFor<T>, #[pallet::compact] _data: u32) -> DispatchResult {
|
||||
unreachable!()
|
||||
}
|
||||
pub fn aux_2(
|
||||
_origin: OriginFor<T>,
|
||||
_data: i32,
|
||||
#[pallet::compact] _data2: u32,
|
||||
) -> DispatchResult {
|
||||
unreachable!()
|
||||
}
|
||||
#[pallet::weight(0)]
|
||||
pub fn aux_3(_origin: OriginFor<T>, _data: i32, _data2: String) -> DispatchResult {
|
||||
unreachable!()
|
||||
}
|
||||
#[pallet::weight(3)]
|
||||
pub fn aux_4(_origin: OriginFor<T>) -> DispatchResult {
|
||||
unreachable!()
|
||||
}
|
||||
#[pallet::weight((5, DispatchClass::Operational))]
|
||||
pub fn operational(_origin: OriginFor<T>) -> DispatchResult {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::origin]
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
pub struct Origin<T>(pub PhantomData<T>);
|
||||
|
||||
#[pallet::event]
|
||||
pub enum Event<T> {
|
||||
A,
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
Something,
|
||||
}
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[derive(frame_support::DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
#[serde(skip)]
|
||||
pub _config: sp_std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {}
|
||||
}
|
||||
|
||||
#[pallet::storage]
|
||||
pub type Storage<T> = StorageValue<_, u32>;
|
||||
|
||||
#[pallet::validate_unsigned]
|
||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
_call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type BlockNumber = u64;
|
||||
pub type Signature = sr25519::Signature;
|
||||
pub type AccountId = <Signature as Verify>::Signer;
|
||||
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, RuntimeCall, Signature, ()>;
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
|
||||
#[frame_support::runtime(legacy_ordering)]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(
|
||||
RuntimeCall,
|
||||
RuntimeEvent,
|
||||
RuntimeError,
|
||||
RuntimeOrigin,
|
||||
RuntimeFreezeReason,
|
||||
RuntimeHoldReason,
|
||||
RuntimeSlashReason,
|
||||
RuntimeLockId,
|
||||
RuntimeTask
|
||||
)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index(30)]
|
||||
pub type System = frame_system + Pallet + Call + Event<T> + Origin<T>;
|
||||
|
||||
#[runtime::pallet_index(31)]
|
||||
pub type Module1_1 = module1<Instance1>;
|
||||
|
||||
#[runtime::pallet_index(32)]
|
||||
pub type Module2 = module2;
|
||||
|
||||
#[runtime::pallet_index(33)]
|
||||
pub type Module1_2 = module1<Instance2>;
|
||||
|
||||
#[runtime::pallet_index(34)]
|
||||
pub type NestedModule3 = nested::module3;
|
||||
|
||||
#[runtime::pallet_index(35)]
|
||||
#[runtime::disable_unsigned]
|
||||
pub type Module3 = self::module3;
|
||||
|
||||
#[runtime::pallet_index(6)]
|
||||
#[runtime::disable_call]
|
||||
pub type Module1_3 = module1<Instance3>;
|
||||
|
||||
#[runtime::pallet_index(3)]
|
||||
pub type Module1_4 = module1<Instance4>;
|
||||
|
||||
#[runtime::pallet_index(4)]
|
||||
#[runtime::disable_call]
|
||||
pub type Module1_5 = module1<Instance5>;
|
||||
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type Module1_6 = module1<Instance6>;
|
||||
|
||||
#[runtime::pallet_index(2)]
|
||||
pub type Module1_7 = module1<Instance7>;
|
||||
|
||||
#[runtime::pallet_index(12)]
|
||||
pub type Module1_8 = module1<Instance8>;
|
||||
|
||||
#[runtime::pallet_index(13)]
|
||||
pub type Module1_9 = module1<Instance9>;
|
||||
}
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
type AccountId = AccountId;
|
||||
type Lookup = sp_runtime::traits::IdentityLookup<AccountId>;
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type PalletInfo = PalletInfo;
|
||||
type OnSetCode = ();
|
||||
type Block = Block;
|
||||
type BlockHashCount = ConstU64<10>;
|
||||
}
|
||||
|
||||
impl module1::Config<module1::Instance1> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance2> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance3> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance4> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance5> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance6> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance7> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance8> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module1::Config<module1::Instance9> for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module2::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl nested::module3::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
impl module3::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
|
||||
fn test_pub() -> AccountId {
|
||||
AccountId::from_raw([0; 32])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_modules_error_type() {
|
||||
sp_io::TestExternalities::default().execute_with(|| {
|
||||
assert_eq!(
|
||||
Module1_1::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 31,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module2::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 32,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_2::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 33,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
NestedModule3::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 34,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_3::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 6,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_4::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 3,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_5::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 4,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_6::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 1,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_7::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 2,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_8::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 12,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
assert_eq!(
|
||||
Module1_9::fail(frame_system::Origin::<Runtime>::Root.into()),
|
||||
Err(DispatchError::Module(ModuleError {
|
||||
index: 13,
|
||||
error: [0; 4],
|
||||
message: Some("Something")
|
||||
})),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integrity_test_works() {
|
||||
__construct_runtime_integrity_test::runtime_integrity_tests();
|
||||
assert_eq!(IntegrityTestExec::get(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn origin_codec() {
|
||||
use codec::Encode;
|
||||
|
||||
let origin = OriginCaller::system(frame_system::RawOrigin::None);
|
||||
assert_eq!(origin.encode()[0], 30);
|
||||
|
||||
let origin = OriginCaller::Module1_1(module1::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 31);
|
||||
|
||||
let origin = OriginCaller::Module2(module2::Origin);
|
||||
assert_eq!(origin.encode()[0], 32);
|
||||
|
||||
let origin = OriginCaller::Module1_2(module1::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 33);
|
||||
|
||||
let origin = OriginCaller::NestedModule3(nested::module3::Origin);
|
||||
assert_eq!(origin.encode()[0], 34);
|
||||
|
||||
let origin = OriginCaller::Module3(module3::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 35);
|
||||
|
||||
let origin = OriginCaller::Module1_6(module1::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 1);
|
||||
|
||||
let origin = OriginCaller::Module1_7(module1::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 2);
|
||||
|
||||
let origin = OriginCaller::Module1_8(module1::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 12);
|
||||
|
||||
let origin = OriginCaller::Module1_9(module1::Origin(Default::default()));
|
||||
assert_eq!(origin.encode()[0], 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn event_codec() {
|
||||
use codec::Encode;
|
||||
|
||||
let event =
|
||||
frame_system::Event::<Runtime>::ExtrinsicSuccess { dispatch_info: Default::default() };
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 30);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance1>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 31);
|
||||
|
||||
let event = module2::Event::A;
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 32);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance2>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 33);
|
||||
|
||||
let event = nested::module3::Event::A;
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 34);
|
||||
|
||||
let event = module3::Event::A;
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 35);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance5>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 4);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance6>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 1);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance7>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 2);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance8>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 12);
|
||||
|
||||
let event = module1::Event::<Runtime, module1::Instance9>::A(test_pub());
|
||||
assert_eq!(RuntimeEvent::from(event).encode()[0], 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_codec() {
|
||||
use codec::Encode;
|
||||
assert_eq!(RuntimeCall::System(frame_system::Call::remark { remark: vec![1] }).encode()[0], 30);
|
||||
assert_eq!(RuntimeCall::Module1_1(module1::Call::fail {}).encode()[0], 31);
|
||||
assert_eq!(RuntimeCall::Module2(module2::Call::fail {}).encode()[0], 32);
|
||||
assert_eq!(RuntimeCall::Module1_2(module1::Call::fail {}).encode()[0], 33);
|
||||
assert_eq!(RuntimeCall::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34);
|
||||
assert_eq!(RuntimeCall::Module3(module3::Call::fail {}).encode()[0], 35);
|
||||
assert_eq!(RuntimeCall::Module1_4(module1::Call::fail {}).encode()[0], 3);
|
||||
assert_eq!(RuntimeCall::Module1_6(module1::Call::fail {}).encode()[0], 1);
|
||||
assert_eq!(RuntimeCall::Module1_7(module1::Call::fail {}).encode()[0], 2);
|
||||
assert_eq!(RuntimeCall::Module1_8(module1::Call::fail {}).encode()[0], 12);
|
||||
assert_eq!(RuntimeCall::Module1_9(module1::Call::fail {}).encode()[0], 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_compact_attr() {
|
||||
use codec::Encode;
|
||||
let call: module3::Call<Runtime> = module3::Call::aux_1 { data: 1 };
|
||||
let encoded = call.encode();
|
||||
assert_eq!(2, encoded.len());
|
||||
assert_eq!(vec![1, 4], encoded);
|
||||
|
||||
let call: module3::Call<Runtime> = module3::Call::aux_2 { data: 1, data2: 2 };
|
||||
let encoded = call.encode();
|
||||
assert_eq!(6, encoded.len());
|
||||
assert_eq!(vec![2, 1, 0, 0, 0, 8], encoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_encode_is_correct_and_decode_works() {
|
||||
use codec::{Decode, Encode};
|
||||
let call: module3::Call<Runtime> = module3::Call::fail {};
|
||||
let encoded = call.encode();
|
||||
assert_eq!(vec![0], encoded);
|
||||
let decoded = module3::Call::<Runtime>::decode(&mut &encoded[..]).unwrap();
|
||||
assert_eq!(decoded, call);
|
||||
|
||||
let call: module3::Call<Runtime> = module3::Call::aux_3 { data: 32, data2: "hello".into() };
|
||||
let encoded = call.encode();
|
||||
assert_eq!(vec![3, 32, 0, 0, 0, 20, 104, 101, 108, 108, 111], encoded);
|
||||
let decoded = module3::Call::<Runtime>::decode(&mut &encoded[..]).unwrap();
|
||||
assert_eq!(decoded, call);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_weight_should_attach_to_call_enum() {
|
||||
use frame_support::{
|
||||
dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays},
|
||||
weights::Weight,
|
||||
};
|
||||
// operational.
|
||||
assert_eq!(
|
||||
module3::Call::<Runtime>::operational {}.get_dispatch_info(),
|
||||
DispatchInfo {
|
||||
weight: Weight::from_parts(5, 0),
|
||||
class: DispatchClass::Operational,
|
||||
pays_fee: Pays::Yes
|
||||
},
|
||||
);
|
||||
// custom basic
|
||||
assert_eq!(
|
||||
module3::Call::<Runtime>::aux_4 {}.get_dispatch_info(),
|
||||
DispatchInfo {
|
||||
weight: Weight::from_parts(3, 0),
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_name() {
|
||||
use frame_support::traits::GetCallName;
|
||||
let name = module3::Call::<Runtime>::aux_4 {}.get_call_name();
|
||||
assert_eq!("aux_4", name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_metadata() {
|
||||
use frame_support::traits::{CallMetadata, GetCallMetadata};
|
||||
let call = RuntimeCall::Module3(module3::Call::<Runtime>::aux_4 {});
|
||||
let metadata = call.get_call_metadata();
|
||||
let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() };
|
||||
assert_eq!(metadata, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_call_names() {
|
||||
use frame_support::traits::GetCallName;
|
||||
let call_names = module3::Call::<Runtime>::get_call_names();
|
||||
assert_eq!(["fail", "aux_1", "aux_2", "aux_3", "aux_4", "operational"], call_names);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_module_names() {
|
||||
use frame_support::traits::GetCallMetadata;
|
||||
let module_names = RuntimeCall::get_module_names();
|
||||
assert_eq!(
|
||||
[
|
||||
"System",
|
||||
"Module1_1",
|
||||
"Module2",
|
||||
"Module1_2",
|
||||
"NestedModule3",
|
||||
"Module3",
|
||||
"Module1_4",
|
||||
"Module1_6",
|
||||
"Module1_7",
|
||||
"Module1_8",
|
||||
"Module1_9",
|
||||
],
|
||||
module_names
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_subtype_conversion() {
|
||||
use frame_support::{dispatch::CallableCallFor, traits::IsSubType};
|
||||
let call = RuntimeCall::Module3(module3::Call::<Runtime>::fail {});
|
||||
let subcall: Option<&CallableCallFor<Module3, Runtime>> = call.is_sub_type();
|
||||
let subcall_none: Option<&CallableCallFor<Module2, Runtime>> = call.is_sub_type();
|
||||
assert_eq!(Some(&module3::Call::<Runtime>::fail {}), subcall);
|
||||
assert_eq!(None, subcall_none);
|
||||
|
||||
let from = RuntimeCall::from(subcall.unwrap().clone());
|
||||
assert_eq!(from, call);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_metadata() {
|
||||
use frame_metadata::{
|
||||
v14::{StorageEntryType::Plain, *},
|
||||
*,
|
||||
};
|
||||
use scale_info::meta_type;
|
||||
use sp_core::Encode;
|
||||
use sp_metadata_ir::StorageEntryModifierIR::Optional;
|
||||
|
||||
fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> {
|
||||
if cfg!(feature = "no-metadata-docs") {
|
||||
vec![]
|
||||
} else {
|
||||
doc
|
||||
}
|
||||
}
|
||||
|
||||
let pallets = vec![
|
||||
PalletMetadata {
|
||||
name: "System",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<frame_system::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<frame_system::Event<Runtime>>().into()),
|
||||
constants: vec![
|
||||
PalletConstantMetadata {
|
||||
name: "BlockWeights",
|
||||
ty: meta_type::<BlockWeights>(),
|
||||
value: BlockWeights::default().encode(),
|
||||
docs: maybe_docs(vec![" Block & extrinsics weights: base values and limits."]),
|
||||
},
|
||||
PalletConstantMetadata {
|
||||
name: "BlockLength",
|
||||
ty: meta_type::<BlockLength>(),
|
||||
value: BlockLength::default().encode(),
|
||||
docs: maybe_docs(vec![" The maximum length of a block (in bytes)."]),
|
||||
},
|
||||
PalletConstantMetadata {
|
||||
name: "BlockHashCount",
|
||||
ty: meta_type::<u64>(),
|
||||
value: 10u64.encode(),
|
||||
docs: maybe_docs(vec![" Maximum number of block number to block hash mappings to keep (oldest pruned first)."]),
|
||||
},
|
||||
PalletConstantMetadata {
|
||||
name: "DbWeight",
|
||||
ty: meta_type::<RuntimeDbWeight>(),
|
||||
value: RuntimeDbWeight::default().encode(),
|
||||
docs: maybe_docs(vec![" The weight of runtime database operations the runtime can invoke.",]),
|
||||
},
|
||||
PalletConstantMetadata {
|
||||
name: "Version",
|
||||
ty: meta_type::<RuntimeVersion>(),
|
||||
value: RuntimeVersion::default().encode(),
|
||||
docs: maybe_docs(vec![ " Get the chain's current version."]),
|
||||
},
|
||||
PalletConstantMetadata {
|
||||
name: "SS58Prefix",
|
||||
ty: meta_type::<u16>(),
|
||||
value: 0u16.encode(),
|
||||
docs: maybe_docs(vec![
|
||||
" The designated SS58 prefix of this chain.",
|
||||
"",
|
||||
" This replaces the \"ss58Format\" property declared in the chain spec. Reason is",
|
||||
" that the runtime should know about the prefix in order to make use of it as",
|
||||
" an identifier of the chain.",
|
||||
]),
|
||||
},
|
||||
],
|
||||
error: Some(meta_type::<frame_system::Error<Runtime>>().into()),
|
||||
index: 30,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_1",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance1>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance1>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime>>().into()),
|
||||
index: 31,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module2",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module2::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<module2::Event<Runtime>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module2::Error<Runtime>>().into()),
|
||||
index: 32,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_2",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance2>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance2>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance2>>().into()),
|
||||
index: 33,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "NestedModule3",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<nested::module3::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<nested::module3::Event<Runtime>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<nested::module3::Error<Runtime>>().into()),
|
||||
index: 34,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module3",
|
||||
storage: Some(PalletStorageMetadata {
|
||||
prefix: "Module3",
|
||||
entries: vec![
|
||||
StorageEntryMetadata {
|
||||
name: "Storage",
|
||||
modifier: Optional.into(),
|
||||
ty: Plain(meta_type::<u32>().into()),
|
||||
default: vec![0],
|
||||
docs: vec![],
|
||||
},
|
||||
]
|
||||
}),
|
||||
calls: Some(meta_type::<module3::Call<Runtime>>().into()),
|
||||
event: Some(meta_type::<module3::Event<Runtime>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module3::Error<Runtime>>().into()),
|
||||
index: 35,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_3",
|
||||
storage: None,
|
||||
calls: None,
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance3>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance3>>().into()),
|
||||
index: 6,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_4",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance4>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance4>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance4>>().into()),
|
||||
index: 3,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_5",
|
||||
storage: None,
|
||||
calls: None,
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance5>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance5>>().into()),
|
||||
index: 4,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_6",
|
||||
storage:None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance6>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance6>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance6>>().into()),
|
||||
index: 1,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_7",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance7>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance7>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance7>>().into()),
|
||||
index: 2,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_8",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance8>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance8>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance8>>().into()),
|
||||
index: 12,
|
||||
},
|
||||
PalletMetadata {
|
||||
name: "Module1_9",
|
||||
storage: None,
|
||||
calls: Some(meta_type::<module1::Call<Runtime, module1::Instance9>>().into()),
|
||||
event: Some(meta_type::<module1::Event<Runtime, module1::Instance9>>().into()),
|
||||
constants: vec![],
|
||||
error: Some(meta_type::<module1::Error<Runtime, module1::Instance9>>().into()),
|
||||
index: 13,
|
||||
},
|
||||
];
|
||||
|
||||
let extrinsic = ExtrinsicMetadata {
|
||||
ty: meta_type::<UncheckedExtrinsic>(),
|
||||
version: 4,
|
||||
signed_extensions: vec![SignedExtensionMetadata {
|
||||
identifier: "UnitTransactionExtension",
|
||||
ty: meta_type::<()>(),
|
||||
additional_signed: meta_type::<()>(),
|
||||
}],
|
||||
};
|
||||
|
||||
let expected_metadata: RuntimeMetadataPrefixed =
|
||||
RuntimeMetadataLastVersion::new(pallets, extrinsic, meta_type::<Runtime>()).into();
|
||||
let actual_metadata = Runtime::metadata();
|
||||
|
||||
pretty_assertions::assert_eq!(actual_metadata, expected_metadata);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pallet_in_runtime_is_correct() {
|
||||
assert_eq!(PalletInfo::index::<System>().unwrap(), 30);
|
||||
assert_eq!(PalletInfo::name::<System>().unwrap(), "System");
|
||||
assert_eq!(PalletInfo::module_name::<System>().unwrap(), "frame_system");
|
||||
assert!(PalletInfo::crate_version::<System>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_1>().unwrap(), 31);
|
||||
assert_eq!(PalletInfo::name::<Module1_1>().unwrap(), "Module1_1");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_1>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_1>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module2>().unwrap(), 32);
|
||||
assert_eq!(PalletInfo::name::<Module2>().unwrap(), "Module2");
|
||||
assert_eq!(PalletInfo::module_name::<Module2>().unwrap(), "module2");
|
||||
assert!(PalletInfo::crate_version::<Module2>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_2>().unwrap(), 33);
|
||||
assert_eq!(PalletInfo::name::<Module1_2>().unwrap(), "Module1_2");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_2>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_2>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<NestedModule3>().unwrap(), 34);
|
||||
assert_eq!(PalletInfo::name::<NestedModule3>().unwrap(), "NestedModule3");
|
||||
assert_eq!(PalletInfo::module_name::<NestedModule3>().unwrap(), "nested::module3");
|
||||
assert!(PalletInfo::crate_version::<NestedModule3>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module3>().unwrap(), 35);
|
||||
assert_eq!(PalletInfo::name::<Module3>().unwrap(), "Module3");
|
||||
assert_eq!(PalletInfo::module_name::<Module3>().unwrap(), "self::module3");
|
||||
assert!(PalletInfo::crate_version::<Module3>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_3>().unwrap(), 6);
|
||||
assert_eq!(PalletInfo::name::<Module1_3>().unwrap(), "Module1_3");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_3>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_3>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_4>().unwrap(), 3);
|
||||
assert_eq!(PalletInfo::name::<Module1_4>().unwrap(), "Module1_4");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_4>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_4>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_5>().unwrap(), 4);
|
||||
assert_eq!(PalletInfo::name::<Module1_5>().unwrap(), "Module1_5");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_5>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_5>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_6>().unwrap(), 1);
|
||||
assert_eq!(PalletInfo::name::<Module1_6>().unwrap(), "Module1_6");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_6>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_6>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_7>().unwrap(), 2);
|
||||
assert_eq!(PalletInfo::name::<Module1_7>().unwrap(), "Module1_7");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_7>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_7>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_8>().unwrap(), 12);
|
||||
assert_eq!(PalletInfo::name::<Module1_8>().unwrap(), "Module1_8");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_8>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_8>().is_some());
|
||||
|
||||
assert_eq!(PalletInfo::index::<Module1_9>().unwrap(), 13);
|
||||
assert_eq!(PalletInfo::name::<Module1_9>().unwrap(), "Module1_9");
|
||||
assert_eq!(PalletInfo::module_name::<Module1_9>().unwrap(), "module1");
|
||||
assert!(PalletInfo::crate_version::<Module1_9>().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_unsigned() {
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
let call = RuntimeCall::NestedModule3(nested::module3::Call::fail {});
|
||||
let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err();
|
||||
assert_eq!(validity, TransactionValidityError::Invalid(InvalidTransaction::Call));
|
||||
|
||||
let call = RuntimeCall::Module3(module3::Call::fail {});
|
||||
let validity = Runtime::validate_unsigned(TransactionSource::Local, &call).unwrap_err();
|
||||
assert_eq!(
|
||||
validity,
|
||||
TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[rustversion::attr(not(stable), ignore)]
|
||||
#[cfg(not(feature = "disable-ui-tests"))]
|
||||
#[test]
|
||||
fn ui() {
|
||||
// Only run the ui tests when `RUN_UI_TESTS` is set.
|
||||
if std::env::var("RUN_UI_TESTS").is_err() {
|
||||
return
|
||||
}
|
||||
|
||||
// As trybuild is using `cargo check`, we don't need the real WASM binaries.
|
||||
std::env::set_var("SKIP_WASM_BUILD", "1");
|
||||
|
||||
// Deny all warnings since we emit warnings as part of a Runtime's UI.
|
||||
std::env::set_var("RUSTFLAGS", "--deny warnings");
|
||||
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/runtime_ui/*.rs");
|
||||
t.pass("tests/runtime_ui/pass/*.rs");
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
fn construct_runtime() {}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: expected `mod`
|
||||
--> tests/runtime_ui/can_only_be_attached_to_mod.rs:19:1
|
||||
|
|
||||
19 | fn construct_runtime() {}
|
||||
| ^^
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::pallet]
|
||||
mod pallet {
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
}
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(RuntimeCall)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type System = frame_system;
|
||||
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type Pallet = pallet;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,11 @@
|
||||
error: Pallet indices are conflicting: Both pallets System and Pallet are at index 0
|
||||
--> tests/runtime_ui/conflicting_pallet_index.rs:37:14
|
||||
|
|
||||
37 | pub type System = frame_system;
|
||||
| ^^^^^^
|
||||
|
||||
error: Pallet indices are conflicting: Both pallets System and Pallet are at index 0
|
||||
--> tests/runtime_ui/conflicting_pallet_index.rs:40:14
|
||||
|
|
||||
40 | pub type Pallet = pallet;
|
||||
| ^^^^^^
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::pallet]
|
||||
mod pallet {
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
}
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(RuntimeCall)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type System = frame_system;
|
||||
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type System = pallet;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,11 @@
|
||||
error: Two pallets with the same name!
|
||||
--> tests/runtime_ui/conflicting_pallet_name.rs:37:14
|
||||
|
|
||||
37 | pub type System = frame_system;
|
||||
| ^^^^^^
|
||||
|
||||
error: Two pallets with the same name!
|
||||
--> tests/runtime_ui/conflicting_pallet_name.rs:40:14
|
||||
|
|
||||
40 | pub type System = pallet;
|
||||
| ^^^^^^
|
||||
@@ -0,0 +1,23 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime(dummy)]
|
||||
mod runtime {
|
||||
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: Invalid runtime macro call: unexpected attribute. Macro call must be bare, such as `#[frame_support::runtime]` or `#[runtime]`, or must specify the `legacy_ordering` attribute, such as `#[frame_support::runtime(legacy_ordering)]` or #[runtime(legacy_ordering)].
|
||||
--> tests/runtime_ui/invalid_attribute.rs:18:26
|
||||
|
|
||||
18 | #[frame_support::runtime(dummy)]
|
||||
| ^^^^^
|
||||
@@ -0,0 +1,28 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(RuntimeCall)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index("0")]
|
||||
pub type System = frame_system;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: expected integer literal
|
||||
--> tests/runtime_ui/invalid_pallet_index.rs:24:29
|
||||
|
|
||||
24 | #[runtime::pallet_index("0")]
|
||||
| ^^^
|
||||
@@ -0,0 +1,25 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(RuntimeInfo)]
|
||||
pub struct Runtime;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: expected one of: `RuntimeCall`, `RuntimeEvent`, `RuntimeError`, `RuntimeOrigin`, `RuntimeFreezeReason`, `RuntimeHoldReason`, `RuntimeSlashReason`, `RuntimeLockId`, `RuntimeTask`
|
||||
--> tests/runtime_ui/invalid_runtime_type_derive.rs:21:23
|
||||
|
|
||||
21 | #[runtime::derive(RuntimeInfo)]
|
||||
| ^^^^^^^^^^^
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]`
|
||||
--> tests/runtime_ui/missing_runtime.rs:19:1
|
||||
|
|
||||
19 | mod runtime {}
|
||||
| ^^^
|
||||
@@ -0,0 +1,24 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
pub struct Runtime;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]`
|
||||
--> tests/runtime_ui/missing_runtime_types_derive.rs:19:1
|
||||
|
|
||||
19 | mod runtime {
|
||||
| ^^^
|
||||
@@ -0,0 +1,25 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(RuntimeCall)]
|
||||
pub struct Runtime;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: `System` pallet declaration is missing. Please add this line: `pub type System = frame_system;`
|
||||
--> tests/runtime_ui/missing_system_pallet.rs:19:5
|
||||
|
|
||||
19 | mod runtime {
|
||||
| ^^^^^^^
|
||||
@@ -0,0 +1,37 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 frame_support::derive_impl;
|
||||
|
||||
pub type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
type Block = Block;
|
||||
}
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(RuntimeCall, RuntimeEvent, RuntimeOrigin, RuntimeError, RuntimeTask)]
|
||||
pub struct Runtime;
|
||||
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type System = frame_system;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
pub enum Runtime {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: Invalid runtime::runtime, expected struct definition
|
||||
--> tests/runtime_ui/runtime_struct.rs:21:5
|
||||
|
|
||||
21 | pub enum Runtime {}
|
||||
| ^^^
|
||||
@@ -25,7 +25,7 @@ scale-info = { version = "2.10.0", default-features = false, features = [
|
||||
] }
|
||||
|
||||
# frame
|
||||
frame-support = { path = "../../../substrate/frame/support", default-features = false }
|
||||
frame-support = { path = "../../../substrate/frame/support", default-features = false, features = ["experimental"] }
|
||||
frame-system = { path = "../../../substrate/frame/system", default-features = false }
|
||||
frame-try-runtime = { path = "../../../substrate/frame/try-runtime", default-features = false, optional = true }
|
||||
frame-executive = { path = "../../../substrate/frame/executive", default-features = false }
|
||||
|
||||
@@ -253,20 +253,47 @@ impl pallet_template::Config for Runtime {
|
||||
}
|
||||
|
||||
// Create the runtime by composing the FRAME pallets that were previously configured.
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Timestamp: pallet_timestamp,
|
||||
Aura: pallet_aura,
|
||||
Grandpa: pallet_grandpa,
|
||||
Balances: pallet_balances,
|
||||
TransactionPayment: pallet_transaction_payment,
|
||||
Sudo: pallet_sudo,
|
||||
#[frame_support::runtime]
|
||||
mod runtime {
|
||||
#[runtime::runtime]
|
||||
#[runtime::derive(
|
||||
RuntimeCall,
|
||||
RuntimeEvent,
|
||||
RuntimeError,
|
||||
RuntimeOrigin,
|
||||
RuntimeFreezeReason,
|
||||
RuntimeHoldReason,
|
||||
RuntimeSlashReason,
|
||||
RuntimeLockId,
|
||||
RuntimeTask
|
||||
)]
|
||||
pub struct Runtime;
|
||||
|
||||
// Include the custom logic from the pallet-template in the runtime.
|
||||
TemplateModule: pallet_template,
|
||||
}
|
||||
);
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type System = frame_system;
|
||||
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type Timestamp = pallet_timestamp;
|
||||
|
||||
#[runtime::pallet_index(2)]
|
||||
pub type Aura = pallet_aura;
|
||||
|
||||
#[runtime::pallet_index(3)]
|
||||
pub type Grandpa = pallet_grandpa;
|
||||
|
||||
#[runtime::pallet_index(4)]
|
||||
pub type Balances = pallet_balances;
|
||||
|
||||
#[runtime::pallet_index(5)]
|
||||
pub type TransactionPayment = pallet_transaction_payment;
|
||||
|
||||
#[runtime::pallet_index(6)]
|
||||
pub type Sudo = pallet_sudo;
|
||||
|
||||
// Include the custom logic from the pallet-template in the runtime.
|
||||
#[runtime::pallet_index(7)]
|
||||
pub type TemplateModule = pallet_template;
|
||||
}
|
||||
|
||||
/// The address format for describing accounts.
|
||||
pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
|
||||
|
||||
Reference in New Issue
Block a user