referrerpolicy=no-referrer-when-downgrade

polkadot_sdk_docs/reference_docs/
frame_storage_derives.rs

1//! # Frame storage derives
2//!
3//! > **Note:**
4//! >
5//! > In all examples, a few lines of boilerplate have been hidden from each snippet for
6//! > conciseness.
7//!
8//! Let's begin by starting to store a `NewType` in a storage item:
9//!
10//! ```compile_fail
11//! #[frame::pallet]
12//! pub mod pallet {
13//! 	# use frame::prelude::*;
14//! 	# #[pallet::config]
15//! 	# pub trait Config: frame_system::Config {}
16//! 	# #[pallet::pallet]
17//! 	# pub struct Pallet<T>(_);
18//! 	pub struct NewType(u32);
19//
20//! 	#[pallet::storage]
21//! 	pub type Something<T> = StorageValue<_, NewType>;
22//! }
23//! ```
24//! 
25//! This raises a number of compiler errors, like:
26//! ```text
27//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by
28//! `frame::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
29//! StorageInfoTrait`
30//! ```
31//! 
32//! This implies the following set of traits that need to be derived for a type to be stored in
33//! `frame` storage:
34//! ```rust
35//! #[frame::pallet]
36//! pub mod pallet {
37//! 	# use frame::prelude::*;
38//! 	# #[pallet::config]
39//! 	# pub trait Config: frame_system::Config {}
40//! 	# #[pallet::pallet]
41//! 	# pub struct Pallet<T>(_);
42//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
43//! 	pub struct NewType(u32);
44//!
45//! 	#[pallet::storage]
46//! 	pub type Something<T> = StorageValue<_, NewType>;
47//! }
48//! ```
49//! 
50//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in
51//! storage, such as [`frame::prelude::BlockNumberFor`]:
52//! ```compile_fail
53//! #[frame::pallet]
54//! pub mod pallet {
55//! 	# use frame::prelude::*;
56//! 	# #[pallet::config]
57//! 	# pub trait Config: frame_system::Config {}
58//! 	# #[pallet::pallet]
59//! 	# pub struct Pallet<T>(_);
60//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
61//! 	pub struct NewType<T: Config>(BlockNumberFor<T>);
62//!
63//! 	#[pallet::storage]
64//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>>;
65//! }
66//! ```
67//! 
68//! Surprisingly, this will also raise a number of errors, like:
69//! ```text
70//! the trait `TypeInfo` is not implemented for `T`, which is required
71//! by`frame_support::pallet_prelude::StorageValue<pallet_2::_GeneratedPrefixForStorageSomething<T>,
72//! pallet_2::NewType<T>>:StorageEntryMetadataBuilder
73//! ```
74//! 
75//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for
76//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T`
77//! in the example above.
78//!
79//! If you expand an instance of the derive, you will find something along the lines of:
80//! `impl<T> TypeInfo for NewType<T> where T: TypeInfo { ... }`. This is the reason why the
81//! `TypeInfo` trait is required for `T`.
82//!
83//! To fix this, we need to add a `#[scale_info(skip_type_params(T))]`
84//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on
85//! `T`.
86//! ```rust
87//! #[frame::pallet]
88//! pub mod pallet {
89//! 	# use frame::prelude::*;
90//! 	# #[pallet::config]
91//! 	# pub trait Config: frame_system::Config {}
92//! 	# #[pallet::pallet]
93//! 	# pub struct Pallet<T>(_);
94//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
95//! 	#[scale_info(skip_type_params(T))]
96//! 	pub struct NewType<T: Config>(BlockNumberFor<T>);
97//!
98//! 	#[pallet::storage]
99//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>>;
100//! }
101//! ```
102//! 
103//! Next, let's say we wish to store `NewType` as [`frame::prelude::ValueQuery`], which means it
104//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it,
105//! right?
106//! ```compile_fail
107//! #[frame::pallet]
108//! pub mod pallet {
109//! 	# use frame::prelude::*;
110//! 	# #[pallet::config]
111//! 	# pub trait Config: frame_system::Config {}
112//! 	# #[pallet::pallet]
113//! 	# pub struct Pallet<T>(_);
114//! 	#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)]
115//! 	#[scale_info(skip_type_params(T))]
116//! 	pub struct NewType<T: Config>(BlockNumberFor<T>);
117//!
118//! 	#[pallet::storage]
119//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
120//! }
121//! ```
122//! 
123//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as
124//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an
125//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor<T>`.
126//! `BlockNumberFor<T>` should indeed implement `Default`, but `T` implementing `Default` is rather
127//! meaningless.
128//!
129//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but
130//! work nicely on top of structs that are generic over `T: Config`. These macros are:
131//!
132//! - [`frame::prelude::DefaultNoBound`]
133//! - [`frame::prelude::DebugNoBound`]
134//! - [`frame::prelude::PartialEqNoBound`]
135//! - [`frame::prelude::EqNoBound`]
136//! - [`frame::prelude::CloneNoBound`]
137//! - [`frame::prelude::PartialOrdNoBound`]
138//! - [`frame::prelude::OrdNoBound`]
139//!
140//! The above traits are almost certainly needed for your tests - to print your type, assert equality
141//! or clone it.
142//!
143//! We can fix the following example by using [`frame::prelude::DefaultNoBound`].
144//! ```rust
145//! #[frame::pallet]
146//! pub mod pallet {
147//! 	# use frame::prelude::*;
148//! 	# #[pallet::config]
149//! 	# pub trait Config: frame_system::Config {}
150//! 	# #[pallet::pallet]
151//! 	# pub struct Pallet<T>(_);
152//! 	#[derive(
153//! 		codec::Encode,
154//! 		codec::Decode,
155//! 		codec::MaxEncodedLen,
156//! 		scale_info::TypeInfo,
157//! 		DefaultNoBound
158//!		)]
159//! 	#[scale_info(skip_type_params(T))]
160//! 	pub struct NewType<T:Config>(BlockNumberFor<T>);
161//!
162//! 	#[pallet::storage]
163//! 	pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
164//! }
165//! ```
166//! 
167//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it
168//! is subject to the same trait requirements. The following does not work:
169//! ```compile_fail
170//! #[frame::pallet]
171//! pub mod pallet {
172//! 	use frame::prelude::*;
173//! 	#[pallet::config]
174//! 	pub trait Config: frame_system::Config {
175//! 		type CustomType;
176//! 	}
177//! 	#[pallet::pallet]
178//! 	pub struct Pallet<T>(_);
179//! 	#[pallet::storage]
180//! 	pub type Something<T: Config> = StorageValue<_, T::CustomType>;
181//! }
182//! ```
183//! 
184//! But adding the right trait bounds will fix it.
185//! ```rust
186//! #[frame::pallet]
187//! pub mod pallet {
188//! 	use frame::prelude::*;
189//! 	#[pallet::config]
190//! 	pub trait Config: frame_system::Config {
191//! 		type CustomType: codec::FullCodec
192//! 			+ codec::MaxEncodedLen
193//! 			+ scale_info::TypeInfo
194//! 			+ Debug
195//! 			+ Default;
196//! 	}
197//! 	#[pallet::pallet]
198//! 	pub struct Pallet<T>(_);
199//! 	#[pallet::storage]
200//! 	pub type Something<T: Config> = StorageValue<_, T::CustomType>;
201//! }
202//! ```