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//! ```