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
//! # Frame storage derives
//!
//! > **Note:**
//! >
//! > In all examples, a few lines of boilerplate have been hidden from each snippet for
//! > conciseness.
//!
//! Let's begin by starting to store a `NewType` in a storage item:
//!
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! pub struct NewType(u32);
//
//! #[pallet::storage]
//! pub type Something<T> = StorageValue<_, NewType>;
//! }
//! ```
//!
//! This raises a number of compiler errors, like:
//! ```text
//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by
//! `frame::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
//! StorageInfoTrait`
//! ```
//!
//! This implies the following set of traits that need to be derived for a type to be stored in
//! `frame` storage:
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
//! pub struct NewType(u32);
//!
//! #[pallet::storage]
//! pub type Something<T> = StorageValue<_, NewType>;
//! }
//! ```
//!
//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in
//! storage, such as [`frame::prelude::BlockNumberFor`]:
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
//! }
//! ```
//!
//! Surprisingly, this will also raise a number of errors, like:
//! ```text
//! the trait `TypeInfo` is not implemented for `T`, which is required
//! by`frame_support::pallet_prelude::StorageValue<pallet_2::_GeneratedPrefixForStorageSomething<T>,
//! pallet_2::NewType<T>>:StorageEntryMetadataBuilder
//! ```
//!
//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for
//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T`
//! in the example above.
//!
//! If you expand an instance of the derive, you will find something along the lines of:
//! `impl<T> TypeInfo for NewType<T> where T: TypeInfo { ... }`. This is the reason why the
//! `TypeInfo` trait is required for `T`.
//!
//! To fix this, we need to add a `#[scale_info(skip_type_params(T))]`
//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on
//! `T`.
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
//! #[scale_info(skip_type_params(T))]
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
//! }
//! ```
//!
//! Next, let's say we wish to store `NewType` as [`frame::prelude::ValueQuery`], which means it
//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it,
//! right?
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)]
//! #[scale_info(skip_type_params(T))]
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
//! }
//! ```
//!
//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as
//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an
//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor<T>`.
//! `BlockNumberFor<T>` should indeed implement `Default`, but `T` implementing `Default` is rather
//! meaningless.
//!
//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but
//! work nicely on top of structs that are generic over `T: Config`. These macros are:
//!
//! - [`frame::prelude::DefaultNoBound`]
//! - [`frame::prelude::DebugNoBound`]
//! - [`frame::prelude::PartialEqNoBound`]
//! - [`frame::prelude::EqNoBound`]
//! - [`frame::prelude::CloneNoBound`]
//! - [`frame::prelude::PartialOrdNoBound`]
//! - [`frame::prelude::OrdNoBound`]
//!
//! The above traits are almost certainly needed for your tests - to print your type, assert equality
//! or clone it.
//!
//! We can fix the following example by using [`frame::prelude::DefaultNoBound`].
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(
//! codec::Encode,
//! codec::Decode,
//! codec::MaxEncodedLen,
//! scale_info::TypeInfo,
//! DefaultNoBound
//! )]
//! #[scale_info(skip_type_params(T))]
//! pub struct NewType<T:Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
//! }
//! ```
//!
//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it
//! is subject to the same trait requirements. The following does not work:
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! use frame::prelude::*;
//! #[pallet::config]
//! pub trait Config: frame_system::Config {
//! type CustomType;
//! }
//! #[pallet::pallet]
//! pub struct Pallet<T>(_);
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
//! }
//! ```
//!
//! But adding the right trait bounds will fix it.
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! use frame::prelude::*;
//! #[pallet::config]
//! pub trait Config: frame_system::Config {
//! type CustomType: codec::FullCodec
//! + codec::MaxEncodedLen
//! + scale_info::TypeInfo
//! + Debug
//! + Default;
//! }
//! #[pallet::pallet]
//! pub struct Pallet<T>(_);
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
//! }
//! ```