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

Commit 06d8934

Browse files
kianenigmaggwpezsam0x17bkchrKiChjang
authored
Default Pallet Config Trait / derive_impl (#13454)
* first draft, probably won't work * first draft, probably won't work * good progress.. * good milestone, still a lot to do. * EVERYTHING WORKS * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Oliver Tale-Yazdi <[email protected]> * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Oliver Tale-Yazdi <[email protected]> * clean up + cargo fmt * import tokens WIP * export_tokens working with impl Trait * WIP / notes * use macro_magic 0.2.0's export_tokens to access foreign items * token importing working properly using macro_magic 0.2.5 * combine_impls almost working * successfully get foreign path via macro_magic 0.2.6 * combine_impls using implementing_type generics * working + clean up * more clean up * decrease rightwards drift and add docs to combine_impls * add support for macros to impl_item_ident in case we hit that * add docs for impl_item_ident method * fix no_std issues * re-export of macro_magic working in pallets 🎉 * clean up + fully resolve no_std issue with macro_magic with v0.2.11 * remove trait item code for different trait item types since this is now handled directly by combine_impls * clean up * remove dev comments * only generate default trait if #[pallet::default_trait] is attached * authorship and most other pallets now compiling * compiling 🎉 * add check for more than two pallet attributes on Config trait * remove unused import in nomination-pool * clean up debug code * upgrade to macro_magic v0.2.12 * add neater #[register_default_config(SomeIdent)] macro * really just a thin wrapper around #[export_tokens] * upgrade to macro_magic 0.3.1 * rewrite parsing to be compatible with syn 2.x, compiling 🎉 * remove unused keywords * macro stubs for the new pallet:: macros, preliminary docs * upgrade to macro_magic v0.3.2 * rename register_default_config => register_default_impl * bump to macro_magic v0.3.3 * custom disambiguation_path working as 2nd arg to derive_impl * overhaul docs * fixes, ident-style paths shortcut working * remove ident-style shortcut because it makes testing difficult * add passing UI tests for derive_impl * switch to `ForeignPath as DisambiguationPath` syntax + update docs * add UI test for bad foreign path * add UI test for bad disambiguation path * add UI test for missing disambiguation path * add UI test for attached to non impl * fix derive_impl_attr_args_parsing test * move tests to bottom * fix nightly issue * add doc notes on importing/re-exporting * remove explicit use of macro_magic::use_attr Co-authored-by: Bastian Köcher <[email protected]> * use explicit macro_magic::use_attr Co-authored-by: Bastian Köcher <[email protected]> * remove unneeded {} Co-authored-by: Bastian Köcher <[email protected]> * remove unneeded collect Co-authored-by: Bastian Köcher <[email protected]> * add docs for TestDefaultConfig * remove unneeded `#[export_tokens]` on `DefaultConfig` * add docs for auto-generated `DefaultConfig` * no need to clone Co-authored-by: Bastian Köcher <[email protected]> * clean up combine_impls + compiling again * remove unused dependency * simplify struct definition Co-authored-by: Bastian Köcher <[email protected]> * fix register_default_impl docs * reduce rightward drift / refactor Co-authored-by: Keith Yeung <[email protected]> * fix derive_impl after keith's changes * simplify disambiguation_path calculation Co-authored-by: Keith Yeung <[email protected]> * compiling again * simplify parsing of trait item Co-authored-by: Keith Yeung <[email protected]> * rename preludes => prelude Co-authored-by: Keith Yeung <[email protected]> * fix other places where we used preludes instead of prelude * fix indents * simplify PalletAttr parsing Co-authored-by: Keith Yeung <[email protected]> * go back to having no_default and constant as keywords * make it more clear that disambiguation_path is optional * make default_trait_items just a Vec instead of Option<Vec> * rename foreign_path => default_impl_path within substrate * fix docs * Change {} to ; Co-authored-by: Bastian Köcher <[email protected]> * highlight full end-to-end example with link * add pallet-default-config-example, start by copying dev mode code * update dev-mode specific docs * use Person and Points instead of Dummy and Bar * add docs to example pallet * revert changes to pallets other than the default config example * fix outdated references to basic example pallet * re-order docs to be a bit more clear * better errors for extra attributes * add UI tests for duplicate/extra attributes on trait items * change `#[pallet::default_config]` to option on `#[pallet::config()]` * update UI tests * add UI test covering missing `#[pallet::config(with_default)]` when `#[pallet::no_default]` is used * add note about new optional conventions * improve docs about `DefaultConfig` and link to these from a few places * fix doc comment * fix old comment referencing `pallet::default_config` * use u32 instead of u64 for block number Co-authored-by: Kian Paimani <[email protected]> * use () instead of u32 for `AccountData` Co-authored-by: Kian Paimani <[email protected]> * use ConstU32<10> for BlockHashCount instead of ConstU64<10> Co-authored-by: Kian Paimani <[email protected]> * people are not dummies Co-authored-by: Liam Aharon <[email protected]> * fix wording Co-authored-by: Just van Stam <[email protected]> * Person => People and compiling again * add docs for `prelude` module in frame_system * update Cargo.lock * cleaner example * tweaks * update docs more * update docs more * update docs more * update docs more * fix ui tests * err * Update frame/support/test/tests/pallet_ui.rs * update ui tests --------- Co-authored-by: Oliver Tale-Yazdi <[email protected]> Co-authored-by: Sam Johnson <[email protected]> Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher <[email protected]> Co-authored-by: Keith Yeung <[email protected]> Co-authored-by: Liam Aharon <[email protected]> Co-authored-by: Just van Stam <[email protected]>
1 parent a4e0813 commit 06d8934

35 files changed

+1445
-80
lines changed

Cargo.lock

+64
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ members = [
109109
"frame/examples/basic",
110110
"frame/examples/offchain-worker",
111111
"frame/examples/dev-mode",
112+
"frame/examples/default-config",
112113
"frame/executive",
113114
"frame/nis",
114115
"frame/grandpa",
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[package]
2+
name = "pallet-default-config-example"
3+
version = "4.0.0-dev"
4+
authors = ["Parity Technologies <[email protected]>"]
5+
edition = "2021"
6+
license = "MIT-0"
7+
homepage = "https://substrate.io"
8+
repository = "https://github.com/paritytech/substrate/"
9+
description = "FRAME example pallet demonstrating derive_impl / default_config in action"
10+
readme = "README.md"
11+
12+
[package.metadata.docs.rs]
13+
targets = ["x86_64-unknown-linux-gnu"]
14+
15+
[dependencies]
16+
codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false }
17+
log = { version = "0.4.17", default-features = false }
18+
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
19+
frame-support = { default-features = false, path = "../../support" }
20+
frame-system = { default-features = false, path = "../../system" }
21+
22+
sp-io = { default-features = false, path = "../../../primitives/io" }
23+
sp-runtime = { default-features = false, path = "../../../primitives/runtime" }
24+
sp-std = { default-features = false, path = "../../../primitives/std" }
25+
26+
[features]
27+
default = ["std"]
28+
std = [
29+
"codec/std",
30+
"frame-support/std",
31+
"frame-system/std",
32+
"log/std",
33+
"scale-info/std",
34+
"sp-io/std",
35+
"sp-runtime/std",
36+
"sp-std/std",
37+
]
38+
try-runtime = ["frame-support/try-runtime"]
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Default Config Example Pallet
2+
3+
An example pallet demonstrating the ability to derive default testing configs via
4+
`#[derive_impl]` and `#[pallet::config(with_default)]`.
5+
6+
Run `cargo doc --package pallet-default-config-example --open` to view this pallet's documentation.
7+
8+
License: MIT-0
+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
//! # Default Config Pallet Example
19+
//!
20+
//! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to demonstrate
21+
//! the simpler way to implement `Config` trait of pallets. This example only showcases this in a
22+
//! `mock.rs` environment, but the same applies to a real runtime as well.
23+
//!
24+
//! See the source code of [`tests`] for a real examples.
25+
//!
26+
//! Study the following types:
27+
//!
28+
//! - [`pallet::DefaultConfig`], and how it differs from [`pallet::Config`].
29+
//! - [`pallet::config_preludes::TestDefaultConfig`] and how it implements
30+
//! [`pallet::DefaultConfig`].
31+
//! - Notice how [`pallet::DefaultConfig`] is independent of [`frame_system::Config`].
32+
33+
#![cfg_attr(not(feature = "std"), no_std)]
34+
35+
#[frame_support::pallet]
36+
pub mod pallet {
37+
use frame_support::pallet_prelude::*;
38+
39+
/// This pallet is annotated to have a default config. This will auto-generate
40+
/// [`DefaultConfig`].
41+
///
42+
/// It will be an identical, but won't have anything that is `#[pallet::no_default]`.
43+
#[pallet::config(with_default)]
44+
pub trait Config: frame_system::Config {
45+
/// The overarching event type. This is coming from the runtime, and cannot have a default.
46+
/// In general, `Runtime*`-oriented types cannot have a sensible default.
47+
#[pallet::no_default] // optional. `RuntimeEvent` is automatically excluded as well.
48+
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
49+
50+
/// An input parameter to this pallet. This value can have a default, because it is not
51+
/// reliant on `frame_system::Config` or the overarching runtime in any way.
52+
type WithDefaultValue: Get<u32>;
53+
54+
/// Same as [`Config::WithDefaultValue`], but we don't intend to define a default for this
55+
/// in our tests below.
56+
type OverwrittenDefaultValue: Get<u32>;
57+
58+
/// An input parameter that relies on `<Self as frame_system::Config>::AccountId`. As of
59+
/// now, such types cannot have defaults and need to be annotated as such, iff
60+
/// `#[pallet::config(with_default)]` is enabled:
61+
#[pallet::no_default]
62+
type CannotHaveDefault: Get<Self::AccountId>;
63+
64+
/// Something that is a normal type, with default.
65+
type WithDefaultType;
66+
67+
/// Same as [`Config::WithDefaultType`], but we don't intend to define a default for this
68+
/// in our tests below.
69+
type OverwrittenDefaultType;
70+
}
71+
72+
/// Container for different types that implement [`DefaultConfig`]` of this pallet.
73+
pub mod config_preludes {
74+
// This will help use not need to disambiguate anything when using `derive_impl`.
75+
use super::*;
76+
77+
/// A type providing default configurations for this pallet in testing environment.
78+
pub struct TestDefaultConfig;
79+
#[frame_support::register_default_impl(TestDefaultConfig)]
80+
impl DefaultConfig for TestDefaultConfig {
81+
type WithDefaultValue = frame_support::traits::ConstU32<42>;
82+
type OverwrittenDefaultValue = frame_support::traits::ConstU32<42>;
83+
84+
type WithDefaultType = u32;
85+
type OverwrittenDefaultType = u32;
86+
}
87+
88+
/// A type providing default configurations for this pallet in a parachain environment.
89+
pub struct ParachainDefaultConfig;
90+
#[frame_support::register_default_impl(ParachainDefaultConfig)]
91+
impl DefaultConfig for ParachainDefaultConfig {
92+
type WithDefaultValue = frame_support::traits::ConstU32<66>;
93+
type OverwrittenDefaultValue = frame_support::traits::ConstU32<66>;
94+
type WithDefaultType = u32;
95+
type OverwrittenDefaultType = u32;
96+
}
97+
}
98+
99+
#[pallet::pallet]
100+
pub struct Pallet<T>(_);
101+
102+
#[pallet::event]
103+
pub enum Event<T: Config> {}
104+
}
105+
106+
#[cfg(any(test, doc))]
107+
pub mod tests {
108+
use super::*;
109+
110+
use frame_support::macro_magic::use_attr;
111+
// Because `derive_impl` is a [macro_magic](https://crates.io/crates/macro_magic) attribute
112+
// macro, [`#[use_attr]`](`frame_support::macro_magic::use_attr`) must be attached to any use
113+
// statement that brings it into scope.
114+
#[use_attr]
115+
use frame_support::derive_impl;
116+
117+
use super::pallet as pallet_default_config_example;
118+
119+
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
120+
type Block = frame_system::mocking::MockBlock<Test>;
121+
122+
frame_support::construct_runtime!(
123+
pub enum Test where
124+
Block = Block,
125+
NodeBlock = Block,
126+
UncheckedExtrinsic = UncheckedExtrinsic,
127+
{
128+
System: frame_system,
129+
DefaultPallet: pallet_default_config_example,
130+
}
131+
);
132+
133+
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
134+
impl frame_system::Config for Test {
135+
// these items are defined by frame-system as `no_default`, so we must specify them here.
136+
// Note that these are types that actually rely on the outer runtime, and can't sensibly
137+
// have an _independent_ default.
138+
type BaseCallFilter = frame_support::traits::Everything;
139+
type RuntimeOrigin = RuntimeOrigin;
140+
type RuntimeCall = RuntimeCall;
141+
type RuntimeEvent = RuntimeEvent;
142+
type PalletInfo = PalletInfo;
143+
type OnSetCode = ();
144+
145+
// all of this is coming from `frame_system::config_preludes::TestDefaultConfig`.
146+
147+
// type Index = u32;
148+
// type BlockNumber = u32;
149+
// type Header = sp_runtime::generic::Header<Self::BlockNumber, Self::Hashing>;
150+
// type Hash = sp_core::hash::H256;
151+
// type Hashing = sp_runtime::traits::BlakeTwo256;
152+
// type AccountId = u64;
153+
// type Lookup = sp_runtime::traits::IdentityLookup<u64>;
154+
// type BlockHashCount = frame_support::traits::ConstU32<10>;
155+
// type MaxConsumers = frame_support::traits::ConstU32<16>;
156+
// type AccountData = ();
157+
// type OnNewAccount = ();
158+
// type OnKilledAccount = ();
159+
// type SystemWeightInfo = ();
160+
// type SS58Prefix = ();
161+
// type Version = ();
162+
// type BlockWeights = ();
163+
// type BlockLength = ();
164+
// type DbWeight = ();
165+
166+
// you could still overwrite any of them if desired.
167+
type SS58Prefix = frame_support::traits::ConstU16<456>;
168+
}
169+
170+
// Similarly, we use the defaults provided by own crate as well.
171+
use pallet::config_preludes::TestDefaultConfig;
172+
#[derive_impl(TestDefaultConfig as pallet::DefaultConfig)]
173+
impl crate::pallet::Config for Test {
174+
// These two both cannot have defaults.
175+
type RuntimeEvent = RuntimeEvent;
176+
// Note that the default account-id type in
177+
// `frame_system::config_preludes::TestDefaultConfig` is `u64`.
178+
type CannotHaveDefault = frame_support::traits::ConstU64<1>;
179+
180+
type OverwrittenDefaultValue = frame_support::traits::ConstU32<678>;
181+
type OverwrittenDefaultType = u128;
182+
}
183+
184+
#[test]
185+
fn it_works() {
186+
use frame_support::traits::Get;
187+
use pallet::{Config, DefaultConfig};
188+
189+
// assert one of the value types that is not overwritten.
190+
assert_eq!(
191+
<<Test as Config>::WithDefaultValue as Get<u32>>::get(),
192+
<<TestDefaultConfig as DefaultConfig>::WithDefaultValue as Get<u32>>::get()
193+
);
194+
195+
// assert one of the value types that is overwritten.
196+
assert_eq!(<<Test as Config>::OverwrittenDefaultValue as Get<u32>>::get(), 678u32);
197+
198+
// assert one of the types that is not overwritten.
199+
assert_eq!(
200+
std::any::TypeId::of::<<Test as Config>::WithDefaultType>(),
201+
std::any::TypeId::of::<<TestDefaultConfig as DefaultConfig>::WithDefaultType>()
202+
);
203+
204+
// assert one of the types that is overwritten.
205+
assert_eq!(
206+
std::any::TypeId::of::<<Test as Config>::OverwrittenDefaultType>(),
207+
std::any::TypeId::of::<u128>()
208+
)
209+
}
210+
}

frame/support/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../pr
2929
sp-weights = { version = "5.0.0", default-features = false, path = "../../primitives/weights" }
3030
sp-debug-derive = { default-features = false, path = "../../primitives/debug-derive" }
3131
tt-call = "1.0.8"
32+
macro_magic = "0.3.3"
3233
frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" }
3334
paste = "1.0"
3435
once_cell = { version = "1", default-features = false, optional = true }

frame/support/procedural/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ quote = "1.0.28"
2424
syn = { version = "2.0.16", features = ["full"] }
2525
frame-support-procedural-tools = { version = "4.0.0-dev", path = "./tools" }
2626
proc-macro-warning = { version = "0.4.1", default-features = false }
27+
macro_magic = { version = "0.3.3", features = ["proc_support"] }
2728

2829
[features]
2930
default = ["std"]

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
//! `::{Call, ...}` or implicitly.
2525
//!
2626
//! In case a pallet defines its parts implicitly, then the pallet must provide the
27-
//! `tt_default_parts` macro. `construct_rutime` will generate some code which utilizes `tt_call`
27+
//! `tt_default_parts` macro. `construct_runtime` will generate some code which utilizes `tt_call`
2828
//! to call the `tt_default_parts` macro of the pallet. `tt_default_parts` will then return the
2929
//! default pallet parts as input tokens to the `match_and_replace` macro, which ultimately
3030
//! generates a call to `construct_runtime` again, this time with all the pallet parts explicitly

0 commit comments

Comments
 (0)