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