pallet_default_config_example/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: MIT-0
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy of
7// this software and associated documentation files (the "Software"), to deal in
8// the Software without restriction, including without limitation the rights to
9// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10// of the Software, and to permit persons to whom the Software is furnished to do
11// so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23
24//! # Default Config Pallet Example
25//!
26//! A simple example of a FRAME pallet that utilizes [`frame_support::derive_impl`] to demonstrate
27//! the simpler way to implement `Config` trait of pallets. This example only showcases this in a
28//! `mock.rs` environment, but the same applies to a real runtime as well.
29//!
30//! See the source code of [`tests`] for a real examples.
31//!
32//! Study the following types:
33//!
34//! - [`pallet::DefaultConfig`], and how it differs from [`pallet::Config`].
35//! - [`struct@pallet::config_preludes::TestDefaultConfig`] and how it implements
36//! [`pallet::DefaultConfig`].
37//! - Notice how [`pallet::DefaultConfig`] is independent of [`frame_system::Config`].
38
39#![cfg_attr(not(feature = "std"), no_std)]
40
41extern crate alloc;
42
43#[frame_support::pallet]
44pub mod pallet {
45 use frame_support::pallet_prelude::*;
46
47 /// This pallet is annotated to have a default config. This will auto-generate
48 /// [`DefaultConfig`].
49 ///
50 /// It will be an identical, but won't have anything that is `#[pallet::no_default]`.
51 #[pallet::config(with_default)]
52 pub trait Config: frame_system::Config {
53 /// The overarching task type. This is coming from the runtime, and cannot have a default.
54 /// In general, `Runtime*`-oriented types cannot have a sensible default.
55 #[pallet::no_default] // optional. `RuntimeEvent` is automatically excluded as well.
56 type RuntimeTask: Task;
57
58 /// An input parameter to this pallet. This value can have a default, because it is not
59 /// reliant on `frame_system::Config` or the overarching runtime in any way.
60 type WithDefaultValue: Get<u32>;
61
62 /// Same as [`Config::WithDefaultValue`], but we don't intend to define a default for this
63 /// in our tests below.
64 type OverwrittenDefaultValue: Get<u32>;
65
66 /// An input parameter that relies on `<Self as frame_system::Config>::AccountId`. This can
67 /// too have a default, as long as it is present in `frame_system::DefaultConfig`.
68 type CanDeriveDefaultFromSystem: Get<Self::AccountId>;
69
70 /// We might choose to declare as one that doesn't have a default, for whatever semantical
71 /// reason.
72 #[pallet::no_default]
73 type HasNoDefault: Get<u32>;
74
75 /// Some types can technically have no default, such as those the rely on
76 /// `frame_system::Config` but are not present in `frame_system::DefaultConfig`. For
77 /// example, a `RuntimeCall` cannot reasonably have a default.
78 #[pallet::no_default] // if we skip this, there will be a compiler error.
79 type CannotHaveDefault: Get<Self::RuntimeCall>;
80
81 /// Something that is a normal type, with default.
82 type WithDefaultType;
83
84 /// Same as [`Config::WithDefaultType`], but we don't intend to define a default for this
85 /// in our tests below.
86 type OverwrittenDefaultType;
87 }
88
89 /// Container for different types that implement [`DefaultConfig`]` of this pallet.
90 pub mod config_preludes {
91 // This will help use not need to disambiguate anything when using `derive_impl`.
92 use super::*;
93 use frame_support::derive_impl;
94
95 /// A type providing default configurations for this pallet in testing environment.
96 pub struct TestDefaultConfig;
97
98 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
99 impl frame_system::DefaultConfig for TestDefaultConfig {}
100
101 #[frame_support::register_default_impl(TestDefaultConfig)]
102 impl DefaultConfig for TestDefaultConfig {
103 type WithDefaultValue = frame_support::traits::ConstU32<42>;
104 type OverwrittenDefaultValue = frame_support::traits::ConstU32<42>;
105
106 // `frame_system::config_preludes::TestDefaultConfig` declares account-id as u64.
107 type CanDeriveDefaultFromSystem = frame_support::traits::ConstU64<42>;
108
109 type WithDefaultType = u32;
110 type OverwrittenDefaultType = u32;
111 }
112
113 /// A type providing default configurations for this pallet in another environment. Examples
114 /// could be a parachain, or a solochain.
115 ///
116 /// Appropriate derive for `frame_system::DefaultConfig` needs to be provided. In this
117 /// example, we simple derive `frame_system::config_preludes::TestDefaultConfig` again.
118 pub struct OtherDefaultConfig;
119
120 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
121 impl frame_system::DefaultConfig for OtherDefaultConfig {}
122
123 #[frame_support::register_default_impl(OtherDefaultConfig)]
124 impl DefaultConfig for OtherDefaultConfig {
125 type WithDefaultValue = frame_support::traits::ConstU32<66>;
126 type OverwrittenDefaultValue = frame_support::traits::ConstU32<66>;
127 type CanDeriveDefaultFromSystem = frame_support::traits::ConstU64<42>;
128 type WithDefaultType = u32;
129 type OverwrittenDefaultType = u32;
130 }
131 }
132
133 #[pallet::pallet]
134 pub struct Pallet<T>(_);
135
136 #[pallet::event]
137 pub enum Event<T: Config> {}
138}
139
140#[cfg(any(test, doc))]
141pub mod tests {
142 use super::*;
143 use frame_support::{derive_impl, parameter_types};
144 use pallet::{self as pallet_default_config_example, config_preludes::*};
145
146 type Block = frame_system::mocking::MockBlock<Runtime>;
147
148 frame_support::construct_runtime!(
149 pub enum Runtime {
150 System: frame_system,
151 DefaultPallet: pallet_default_config_example,
152 }
153 );
154
155 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
156 impl frame_system::Config for Runtime {
157 // these items are defined by frame-system as `no_default`, so we must specify them here.
158 type Block = Block;
159
160 // all of this is coming from `frame_system::config_preludes::TestDefaultConfig`.
161
162 // type Nonce = u32;
163 // type BlockNumber = u32;
164 // type Hash = sp_core::hash::H256;
165 // type Hashing = sp_runtime::traits::BlakeTwo256;
166 // type AccountId = u64;
167 // type Lookup = sp_runtime::traits::IdentityLookup<u64>;
168 // type BlockHashCount = frame_support::traits::ConstU32<10>;
169 // type MaxConsumers = frame_support::traits::ConstU32<16>;
170 // type AccountData = ();
171 // type OnNewAccount = ();
172 // type OnKilledAccount = ();
173 // type SystemWeightInfo = ();
174 // type SS58Prefix = ();
175 // type Version = ();
176 // type BlockWeights = ();
177 // type BlockLength = ();
178 // type DbWeight = ();
179 // type BaseCallFilter = frame_support::traits::Everything;
180 // type BlockHashCount = frame_support::traits::ConstU64<10>;
181 // type OnSetCode = ();
182
183 // These are marked as `#[inject_runtime_type]`. Hence, they are being injected as
184 // types generated by `construct_runtime`.
185
186 // type RuntimeOrigin = RuntimeOrigin;
187 // type RuntimeCall = RuntimeCall;
188 // type RuntimeEvent = RuntimeEvent;
189 // type PalletInfo = PalletInfo;
190
191 // you could still overwrite any of them if desired.
192 type SS58Prefix = frame_support::traits::ConstU16<456>;
193 }
194
195 parameter_types! {
196 pub const SomeCall: RuntimeCall = RuntimeCall::System(frame_system::Call::<Runtime>::remark { remark: alloc::vec![] });
197 }
198
199 #[derive_impl(TestDefaultConfig as pallet::DefaultConfig)]
200 impl pallet_default_config_example::Config for Runtime {
201 // This cannot have default.
202 type RuntimeTask = RuntimeTask;
203
204 type HasNoDefault = frame_support::traits::ConstU32<1>;
205 type CannotHaveDefault = SomeCall;
206
207 type OverwrittenDefaultValue = frame_support::traits::ConstU32<678>;
208 type OverwrittenDefaultType = u128;
209 }
210
211 #[test]
212 fn it_works() {
213 use frame_support::traits::Get;
214 use pallet::{Config, DefaultConfig};
215
216 // assert one of the value types that is not overwritten.
217 assert_eq!(
218 <<Runtime as Config>::WithDefaultValue as Get<u32>>::get(),
219 <<TestDefaultConfig as DefaultConfig>::WithDefaultValue as Get<u32>>::get()
220 );
221
222 // assert one of the value types that is overwritten.
223 assert_eq!(<<Runtime as Config>::OverwrittenDefaultValue as Get<u32>>::get(), 678u32);
224
225 // assert one of the types that is not overwritten.
226 assert_eq!(
227 std::any::TypeId::of::<<Runtime as Config>::WithDefaultType>(),
228 std::any::TypeId::of::<<TestDefaultConfig as DefaultConfig>::WithDefaultType>()
229 );
230
231 // assert one of the types that is overwritten.
232 assert_eq!(
233 std::any::TypeId::of::<<Runtime as Config>::OverwrittenDefaultType>(),
234 std::any::TypeId::of::<u128>()
235 )
236 }
237}