Automatic pallet parts in construct_runtime (#9681)

* implement automatic parts

* ui tests

* rename

* remove unnecessary exclude

* better doc

* better doc

* fix genesis config

* fix UI tests

* fix UI test

* Revert "fix UI test"

This reverts commit a910351c0b24cfe42195cfd97d83a416640e3259.

* implemented used_parts

* Update frame/support/procedural/src/construct_runtime/mod.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* doc + fmt

* Update frame/support/procedural/src/construct_runtime/parse.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* add doc in the macro

* remove yet some more parts

* fix ui test

* more determnistic error message + fix ui tests

* fix ui test

* Apply suggestions from code review

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* do refactor + fix ui tests

* fmt

* fix test

* fix test

* fix ui test

* Apply suggestions from code review

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* refactor

* remove even more part in node-runtime

* fix test

* Add flow chart for the construct_runtime! execution flow

* Fix typo

* Ignore snippets that don't contain code

* Refactor some code in expand_after

* Rename expand_after to match_and_insert

* cargo fmt

* Fix rename

* Remove frame_support argument to construct_runtime_parts

* Make use of tt-call to simplify intermediate expansions

* cargo fmt

* Update match_and_insert documentation

* Reset cursor to 0 when no matching patterns are found

* Reorder struct fields on MatchAndInsertDef

* Add test for dependency renames and fix frame-support import

* Add more doc comments

* Update frame/support/test/compile_pass/src/lib.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Guillaume Thiolliere
2021-10-31 14:55:10 +01:00
committed by GitHub
parent 0214fde9a6
commit 4292e18e50
31 changed files with 1340 additions and 223 deletions
@@ -0,0 +1,30 @@
[package]
name = "frame-support-test-compile-pass"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
publish = false
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
sp-core = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/core" }
sp-runtime = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/runtime" }
sp-version = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/version" }
support = { package = "frame-support", version = "4.0.0-dev", default-features = false, path = "../../" }
system = { package = "frame-system", version = "4.0.0-dev", default-features = false, path = "../../../system" }
[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"support/std",
"system/std",
]
@@ -0,0 +1,92 @@
// This file is part of Substrate.
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]
//! This crate tests that `construct_runtime!` expands the pallet parts
//! correctly even when frame-support is renamed in Cargo.toml
use sp_core::{sr25519, H256};
use sp_runtime::{
create_runtime_str, generic,
traits::{BlakeTwo256, IdentityLookup, Verify},
};
use sp_version::RuntimeVersion;
use support::{construct_runtime, parameter_types};
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("frame-support-test-compile-pass"),
impl_name: create_runtime_str!("substrate-frame-support-test-compile-pass-runtime"),
authoring_version: 0,
spec_version: 0,
impl_version: 0,
apis: sp_version::create_apis_vec!([]),
transaction_version: 0,
};
pub type Signature = sr25519::Signature;
pub type AccountId = <Signature as Verify>::Signer;
pub type BlockNumber = u64;
pub type Index = u64;
parameter_types! {
pub const BlockHashCount: BlockNumber = 2400;
pub const Version: RuntimeVersion = VERSION;
pub const SS58Prefix: u8 = 0;
}
impl system::Config for Runtime {
type BaseCallFilter = support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type Index = u128;
type Hash = H256;
type Hashing = BlakeTwo256;
type Header = Header;
type Lookup = IdentityLookup<Self::AccountId>;
type BlockHashCount = BlockHashCount;
type Version = Version;
type AccountData = ();
type Origin = Origin;
type BlockNumber = BlockNumber;
type AccountId = AccountId;
type Event = Event;
type PalletInfo = PalletInfo;
type Call = Call;
type DbWeight = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type OnSetCode = ();
type SystemWeightInfo = ();
type SS58Prefix = SS58Prefix;
}
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system,
}
);
@@ -0,0 +1,33 @@
use frame_support::construct_runtime;
use sp_runtime::{generic, traits::BlakeTwo256};
use sp_core::sr25519;
#[frame_support::pallet]
mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
}
pub type Signature = sr25519::Signature;
pub type BlockNumber = u64;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
impl pallet::Config for Runtime {}
construct_runtime! {
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system::{Pallet, Call, Storage, Config, Event<T>},
Pallet: pallet exclude_parts { Pallet } use_parts { Pallet },
}
}
fn main() {}
@@ -0,0 +1,28 @@
error: Unexpected tokens, expected one of `=`, `,`
--> $DIR/both_use_and_excluded_parts.rs:29:43
|
29 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet },
| ^^^^^^^^^
error[E0412]: cannot find type `Call` in this scope
--> $DIR/both_use_and_excluded_parts.rs:18:64
|
18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
| ^^^^ not found in this scope
|
help: consider importing one of these items
|
1 | use crate::pallet::Call;
|
1 | use frame_support_test::Call;
|
1 | use frame_system::Call;
|
1 | use test_pallet::Call;
|
error[E0412]: cannot find type `Runtime` in this scope
--> $DIR/both_use_and_excluded_parts.rs:20:25
|
20 | impl pallet::Config for Runtime {}
| ^^^^^^^ not found in this scope
@@ -0,0 +1,13 @@
use frame_support::construct_runtime;
construct_runtime! {
pub enum Runtime where
UncheckedExtrinsic = UncheckedExtrinsic,
Block = Block,
NodeBlock = Block,
{
System: frame_system exclude_parts { Call, Call },
}
}
fn main() {}
@@ -0,0 +1,5 @@
error: `Call` was already declared before. Please remove the duplicate declaration
--> $DIR/duplicate_exclude.rs:9:46
|
9 | System: frame_system exclude_parts { Call, Call },
| ^^^^
@@ -0,0 +1,13 @@
use frame_support::construct_runtime;
construct_runtime! {
pub enum Runtime where
UncheckedExtrinsic = UncheckedExtrinsic,
Block = Block,
NodeBlock = Block,
{
System: frame_system exclude_part { Call },
}
}
fn main() {}
@@ -0,0 +1,5 @@
error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`
--> $DIR/exclude_missspell.rs:9:24
|
9 | System: frame_system exclude_part { Call },
| ^^^^^^^^^^^^
@@ -0,0 +1,38 @@
use frame_support::construct_runtime;
use sp_runtime::{generic, traits::BlakeTwo256};
use sp_core::sr25519;
#[frame_support::pallet]
mod pallet {
use frame_support::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::storage]
type Foo<T> = StorageValue<Value=u8>;
}
pub type Signature = sr25519::Signature;
pub type BlockNumber = u64;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
impl pallet::Config for Runtime {}
construct_runtime! {
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system::{Pallet, Call, Storage, Config, Event<T>},
Pallet: pallet exclude_parts { Call },
}
}
fn main() {}
@@ -0,0 +1,28 @@
error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`.
--> $DIR/exclude_undefined_part.rs:34:34
|
34 | Pallet: pallet exclude_parts { Call },
| ^^^^
error[E0412]: cannot find type `Call` in this scope
--> $DIR/exclude_undefined_part.rs:23:64
|
23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
| ^^^^ not found in this scope
|
help: consider importing one of these items
|
1 | use crate::pallet::Call;
|
1 | use frame_support_test::Call;
|
1 | use frame_system::Call;
|
1 | use test_pallet::Call;
|
error[E0412]: cannot find type `Runtime` in this scope
--> $DIR/exclude_undefined_part.rs:25:25
|
25 | impl pallet::Config for Runtime {}
| ^^^^^^^ not found in this scope
@@ -1,5 +1,5 @@
error: expected one of: identifier, curly braces, `<`
--> $DIR/invalid_module_details.rs:9:19
error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`
--> $DIR/invalid_module_details.rs:9:17
|
9 | system: System::(),
| ^^
| ^^
@@ -1,4 +1,4 @@
error: expected `::`
error: Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`
--> $DIR/invalid_token_after_module.rs:9:18
|
9 | system: System ?
@@ -0,0 +1,26 @@
use frame_support::construct_runtime;
mod pallet_old {
pub trait Config: frame_system::Config {}
decl_storage! {
trait Store for Module<T: Config> as Example {}
}
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin {}
}
}
construct_runtime! {
pub enum Runtime where
UncheckedExtrinsic = UncheckedExtrinsic,
Block = Block,
NodeBlock = Block,
{
System: frame_system,
OldPallet: pallet_old,
}
}
fn main() {}
@@ -0,0 +1,31 @@
error[E0433]: failed to resolve: could not find `tt_default_parts` in `pallet_old`
--> $DIR/old_unsupported_pallet_decl.rs:15:1
|
15 | / construct_runtime! {
16 | | pub enum Runtime where
17 | | UncheckedExtrinsic = UncheckedExtrinsic,
18 | | Block = Block,
... |
23 | | }
24 | | }
| |_^ could not find `tt_default_parts` in `pallet_old`
|
= note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot find macro `decl_storage` in this scope
--> $DIR/old_unsupported_pallet_decl.rs:6:2
|
6 | decl_storage! {
| ^^^^^^^^^^^^
|
= note: consider importing this macro:
frame_support::decl_storage
error: cannot find macro `decl_module` in this scope
--> $DIR/old_unsupported_pallet_decl.rs:10:2
|
10 | decl_module! {
| ^^^^^^^^^^^
|
= note: consider importing this macro:
frame_support::decl_module
@@ -0,0 +1,38 @@
use frame_support::construct_runtime;
use sp_runtime::{generic, traits::BlakeTwo256};
use sp_core::sr25519;
#[frame_support::pallet]
mod pallet {
use frame_support::pallet_prelude::*;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::storage]
type Foo<T> = StorageValue<Value=u8>;
}
pub type Signature = sr25519::Signature;
pub type BlockNumber = u64;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
impl pallet::Config for Runtime {}
construct_runtime! {
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: system::{Pallet, Call, Storage, Config, Event<T>},
Pallet: pallet use_parts { Call },
}
}
fn main() {}
@@ -0,0 +1,28 @@
error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`.
--> $DIR/use_undefined_part.rs:34:30
|
34 | Pallet: pallet use_parts { Call },
| ^^^^
error[E0412]: cannot find type `Call` in this scope
--> $DIR/use_undefined_part.rs:23:64
|
23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, Call, Signature, ()>;
| ^^^^ not found in this scope
|
help: consider importing one of these items
|
1 | use crate::pallet::Call;
|
1 | use frame_support_test::Call;
|
1 | use frame_system::Call;
|
1 | use test_pallet::Call;
|
error[E0412]: cannot find type `Runtime` in this scope
--> $DIR/use_undefined_part.rs:25:25
|
25 | impl pallet::Config for Runtime {}
| ^^^^^^^ not found in this scope
+29 -6
View File
@@ -509,6 +509,18 @@ pub mod pallet3 {
pub struct Pallet<T>(_);
}
#[frame_support::pallet]
pub mod pallet4 {
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::call]
impl<T: Config> Pallet<T> {}
}
frame_support::parameter_types!(
pub const MyGetParam: u32 = 10;
pub const MyGetParam2: u32 = 11;
@@ -553,6 +565,8 @@ impl pallet2::Config for Runtime {
type Event = Event;
}
impl pallet4::Config for Runtime {}
pub type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
pub type Block = sp_runtime::generic::Block<Header, UncheckedExtrinsic>;
pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic<u32, Call, (), ()>;
@@ -563,12 +577,21 @@ frame_support::construct_runtime!(
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system::{Call, Event<T>},
Example: pallet::{Pallet, Call, Event<T>, Config, Storage, Inherent, Origin<T>, ValidateUnsigned},
Example2: pallet2::{Pallet, Call, Event, Config<T>, Storage},
// Exclude part `Storage` in order not to check its metadata in tests.
System: frame_system exclude_parts { Pallet, Storage },
Example: pallet,
Example2: pallet2 exclude_parts { Call },
Example4: pallet4 use_parts { Call },
}
);
// Test that the part `Call` is excluded from Example2 and included in Example4.
fn _ensure_call_is_correctly_excluded_and_included(call: Call) {
match call {
Call::System(_) | Call::Example(_) | Call::Example4(_) => (),
}
}
#[test]
fn transactional_works() {
TestExternalities::default().execute_with(|| {
@@ -995,8 +1018,8 @@ fn migrate_from_pallet_version_to_storage_version() {
AllPalletsWithSystem,
>(&db_weight);
// 3 pallets, 2 writes and every write costs 5 weight.
assert_eq!(3 * 2 * 5, weight);
// 4 pallets, 2 writes and every write costs 5 weight.
assert_eq!(4 * 2 * 5, weight);
// All pallet versions should be removed
assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none());
@@ -1268,7 +1291,7 @@ fn metadata() {
},
],
}),
calls: Some(meta_type::<pallet2::Call<Runtime>>().into()),
calls: None,
event: Some(PalletEventMetadata { ty: meta_type::<pallet2::Event>() }),
constants: vec![],
error: None,
@@ -302,13 +302,12 @@ frame_support::construct_runtime!(
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system::{Pallet, Call, Event<T>},
Example: pallet::{Pallet, Call, Event<T>, Config, Storage, Inherent, Origin<T>, ValidateUnsigned},
Instance1Example: pallet::<Instance1>::{
Pallet, Call, Event<T>, Config, Storage, Inherent, Origin<T>, ValidateUnsigned
},
Example2: pallet2::{Pallet, Event<T>, Config<T>, Storage},
Instance1Example2: pallet2::<Instance1>::{Pallet, Event<T>, Config<T>, Storage},
// Exclude part `Storage` in order not to check its metadata in tests.
System: frame_system exclude_parts { Storage },
Example: pallet,
Instance1Example: pallet::<Instance1>,
Example2: pallet2,
Instance1Example2: pallet2::<Instance1>,
}
);
@@ -601,7 +600,7 @@ fn metadata() {
let system_pallet_metadata = PalletMetadata {
index: 0,
name: "System",
storage: None,
storage: None, // The storage metadatas have been excluded.
calls: Some(scale_info::meta_type::<frame_system::Call<Runtime>>().into()),
event: Some(PalletEventMetadata {
ty: scale_info::meta_type::<frame_system::Event<Runtime>>(),