frame_support/traits/metadata.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Traits for managing information attached to pallets and their constituents.
19
20use alloc::{vec, vec::Vec};
21use codec::{Decode, Encode};
22use core::ops::Add;
23use impl_trait_for_tuples::impl_for_tuples;
24use sp_runtime::RuntimeDebug;
25
26/// Provides information about the pallet itself and its setup in the runtime.
27///
28/// An implementor should be able to provide information about each pallet that
29/// is configured in `construct_runtime!`.
30pub trait PalletInfo {
31 /// Convert the given pallet `P` into its index as configured in the runtime.
32 fn index<P: 'static>() -> Option<usize>;
33 /// Convert the given pallet `P` into its name as configured in the runtime.
34 fn name<P: 'static>() -> Option<&'static str>;
35 /// The two128 hash of name.
36 fn name_hash<P: 'static>() -> Option<[u8; 16]>;
37 /// Convert the given pallet `P` into its Rust module name as used in `construct_runtime!`.
38 fn module_name<P: 'static>() -> Option<&'static str>;
39 /// Convert the given pallet `P` into its containing crate version.
40 fn crate_version<P: 'static>() -> Option<CrateVersion>;
41}
42
43/// Information regarding an instance of a pallet.
44#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
45pub struct PalletInfoData {
46 /// Index of the pallet as configured in the runtime.
47 pub index: usize,
48 /// Name of the pallet as configured in the runtime.
49 pub name: &'static str,
50 /// Name of the Rust module containing the pallet.
51 pub module_name: &'static str,
52 /// Version of the crate containing the pallet.
53 pub crate_version: CrateVersion,
54}
55
56/// Provides information about the pallet itself and its setup in the runtime.
57///
58/// Declare some information and access the information provided by [`PalletInfo`] for a specific
59/// pallet.
60pub trait PalletInfoAccess {
61 /// Index of the pallet as configured in the runtime.
62 fn index() -> usize;
63 /// Name of the pallet as configured in the runtime.
64 fn name() -> &'static str;
65 /// Two128 hash of name.
66 fn name_hash() -> [u8; 16];
67 /// Name of the Rust module containing the pallet.
68 fn module_name() -> &'static str;
69 /// Version of the crate containing the pallet.
70 fn crate_version() -> CrateVersion;
71}
72
73/// Provide information about a bunch of pallets.
74pub trait PalletsInfoAccess {
75 /// The number of pallets' information that this type represents.
76 ///
77 /// You probably don't want this function but `infos()` instead.
78 fn count() -> usize {
79 // for backwards compatibility with XCM-3, Mark as deprecated.
80 Self::infos().len()
81 }
82
83 /// All of the pallets' information that this type represents.
84 fn infos() -> Vec<PalletInfoData>;
85}
86
87#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))]
88#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
89#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
90impl PalletsInfoAccess for Tuple {
91 fn infos() -> Vec<PalletInfoData> {
92 let mut res = vec![];
93 for_tuples!( #( res.extend(Tuple::infos()); )* );
94 res
95 }
96}
97
98/// The function and pallet name of the Call.
99#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug)]
100pub struct CallMetadata {
101 /// Name of the function.
102 pub function_name: &'static str,
103 /// Name of the pallet to which the function belongs.
104 pub pallet_name: &'static str,
105}
106
107/// Gets the function name of the Call.
108pub trait GetCallName {
109 /// Return all function names in the same order as [`GetCallIndex`].
110 fn get_call_names() -> &'static [&'static str];
111 /// Return the function name of the Call.
112 fn get_call_name(&self) -> &'static str;
113}
114
115/// Gets the function index of the Call.
116pub trait GetCallIndex {
117 /// Return all call indices in the same order as [`GetCallName`].
118 fn get_call_indices() -> &'static [u8];
119 /// Return the index of this Call.
120 fn get_call_index(&self) -> u8;
121}
122
123/// Gets the metadata for the Call - function name and pallet name.
124pub trait GetCallMetadata {
125 /// Return all module names.
126 fn get_module_names() -> &'static [&'static str];
127 /// Return all function names for the given `module`.
128 fn get_call_names(module: &str) -> &'static [&'static str];
129 /// Return a [`CallMetadata`], containing function and pallet name of the Call.
130 fn get_call_metadata(&self) -> CallMetadata;
131}
132
133/// The version of a crate.
134#[derive(Debug, Eq, PartialEq, Encode, Decode, Clone, Copy, Default)]
135pub struct CrateVersion {
136 /// The major version of the crate.
137 pub major: u16,
138 /// The minor version of the crate.
139 pub minor: u8,
140 /// The patch version of the crate.
141 pub patch: u8,
142}
143
144impl CrateVersion {
145 pub const fn new(major: u16, minor: u8, patch: u8) -> Self {
146 Self { major, minor, patch }
147 }
148}
149
150impl Ord for CrateVersion {
151 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
152 self.major
153 .cmp(&other.major)
154 .then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch)))
155 }
156}
157
158impl PartialOrd for CrateVersion {
159 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
160 Some(<Self as Ord>::cmp(self, other))
161 }
162}
163
164/// The storage key postfix that is used to store the [`StorageVersion`] per pallet.
165///
166/// The full storage key is built by using:
167/// Twox128([`PalletInfo::name`]) ++ Twox128([`STORAGE_VERSION_STORAGE_KEY_POSTFIX`])
168pub const STORAGE_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__STORAGE_VERSION__:";
169
170/// The storage version of a pallet.
171///
172/// Each storage version of a pallet is stored in the state under a fixed key. See
173/// [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] for how this key is built.
174#[derive(Debug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, PartialOrd, Default)]
175pub struct StorageVersion(u16);
176
177impl StorageVersion {
178 /// Creates a new instance of `Self`.
179 pub const fn new(version: u16) -> Self {
180 Self(version)
181 }
182
183 /// Returns the storage key for a storage version.
184 ///
185 /// See [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] on how this key is built.
186 pub fn storage_key<P: PalletInfoAccess>() -> [u8; 32] {
187 let pallet_name = P::name();
188 crate::storage::storage_prefix(pallet_name.as_bytes(), STORAGE_VERSION_STORAGE_KEY_POSTFIX)
189 }
190
191 /// Put this storage version for the given pallet into the storage.
192 ///
193 /// It will use the storage key that is associated with the given `Pallet`.
194 ///
195 /// # Panics
196 ///
197 /// This function will panic iff `Pallet` can not be found by `PalletInfo`.
198 /// In a runtime that is put together using
199 /// [`construct_runtime!`](crate::construct_runtime) this should never happen.
200 ///
201 /// It will also panic if this function isn't executed in an externalities
202 /// provided environment.
203 pub fn put<P: PalletInfoAccess>(&self) {
204 let key = Self::storage_key::<P>();
205
206 crate::storage::unhashed::put(&key, self);
207 }
208
209 /// Get the storage version of the given pallet from the storage.
210 ///
211 /// It will use the storage key that is associated with the given `Pallet`.
212 ///
213 /// # Panics
214 ///
215 /// This function will panic iff `Pallet` can not be found by `PalletInfo`.
216 /// In a runtime that is put together using
217 /// [`construct_runtime!`](crate::construct_runtime) this should never happen.
218 ///
219 /// It will also panic if this function isn't executed in an externalities
220 /// provided environment.
221 pub fn get<P: PalletInfoAccess>() -> Self {
222 let key = Self::storage_key::<P>();
223
224 crate::storage::unhashed::get_or_default(&key)
225 }
226
227 /// Returns if the storage version key for the given pallet exists in storage.
228 ///
229 /// See [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] on how this key is built.
230 ///
231 /// # Panics
232 ///
233 /// This function will panic iff `Pallet` can not be found by `PalletInfo`.
234 /// In a runtime that is put together using
235 /// [`construct_runtime!`](crate::construct_runtime) this should never happen.
236 ///
237 /// It will also panic if this function isn't executed in an externalities
238 /// provided environment.
239 pub fn exists<P: PalletInfoAccess>() -> bool {
240 let key = Self::storage_key::<P>();
241 crate::storage::unhashed::exists(&key)
242 }
243}
244
245impl PartialEq<u16> for StorageVersion {
246 fn eq(&self, other: &u16) -> bool {
247 self.0 == *other
248 }
249}
250
251impl PartialOrd<u16> for StorageVersion {
252 fn partial_cmp(&self, other: &u16) -> Option<core::cmp::Ordering> {
253 Some(self.0.cmp(other))
254 }
255}
256
257impl Add<u16> for StorageVersion {
258 type Output = StorageVersion;
259
260 fn add(self, rhs: u16) -> Self::Output {
261 Self::new(self.0 + rhs)
262 }
263}
264
265/// Special marker struct used when [`storage_version`](crate::pallet_macros::storage_version) is
266/// not defined for a pallet.
267///
268/// If you (the reader) end up here, it probably means that you tried to compare
269/// [`GetStorageVersion::on_chain_storage_version`] against
270/// [`GetStorageVersion::in_code_storage_version`]. This basically means that the
271/// [`storage_version`](crate::pallet_macros::storage_version) is missing from the pallet where the
272/// mentioned functions are being called, and needs to be defined.
273#[derive(Debug, Default)]
274pub struct NoStorageVersionSet;
275
276/// Provides information about a pallet's storage versions.
277///
278/// Every pallet has two storage versions:
279/// 1. An in-code storage version
280/// 2. An on-chain storage version
281///
282/// The in-code storage version is the version of the pallet as defined in the runtime blob, and the
283/// on-chain storage version is the version of the pallet stored on-chain.
284///
285/// Storage versions should be only ever be out of sync when a pallet has been updated to a new
286/// version and the in-code version is incremented, but the migration has not yet been executed
287/// on-chain as part of a runtime upgrade.
288///
289/// It is the responsibility of the developer to ensure that the on-chain storage version is set
290/// correctly during a migration so that it matches the in-code storage version.
291pub trait GetStorageVersion {
292 /// This type is generated by the [`pallet`](crate::pallet) macro.
293 ///
294 /// If the [`storage_version`](crate::pallet_macros::storage_version) attribute isn't specified,
295 /// this is set to [`NoStorageVersionSet`] to signify that it is missing.
296 ///
297 /// If the [`storage_version`](crate::pallet_macros::storage_version) attribute is specified,
298 /// this is be set to a [`StorageVersion`] corresponding to the attribute.
299 ///
300 /// The intention of using [`NoStorageVersionSet`] instead of defaulting to a [`StorageVersion`]
301 /// of zero is to prevent developers from forgetting to set
302 /// [`storage_version`](crate::pallet_macros::storage_version) when it is required, like in the
303 /// case that they wish to compare the in-code storage version to the on-chain storage version.
304 type InCodeStorageVersion;
305
306 #[deprecated(
307 note = "This method has been renamed to `in_code_storage_version` and will be removed after March 2024."
308 )]
309 /// DEPRECATED: Use [`Self::current_storage_version`] instead.
310 ///
311 /// Returns the in-code storage version as specified in the
312 /// [`storage_version`](crate::pallet_macros::storage_version) attribute, or
313 /// [`NoStorageVersionSet`] if the attribute is missing.
314 fn current_storage_version() -> Self::InCodeStorageVersion {
315 Self::in_code_storage_version()
316 }
317
318 /// Returns the in-code storage version as specified in the
319 /// [`storage_version`](crate::pallet_macros::storage_version) attribute, or
320 /// [`NoStorageVersionSet`] if the attribute is missing.
321 fn in_code_storage_version() -> Self::InCodeStorageVersion;
322 /// Returns the storage version of the pallet as last set in the actual on-chain storage.
323 fn on_chain_storage_version() -> StorageVersion;
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329 use sp_crypto_hashing::twox_128;
330
331 struct Pallet1;
332 impl PalletInfoAccess for Pallet1 {
333 fn index() -> usize {
334 1
335 }
336 fn name() -> &'static str {
337 "Pallet1"
338 }
339 fn name_hash() -> [u8; 16] {
340 twox_128(Self::name().as_bytes())
341 }
342 fn module_name() -> &'static str {
343 "pallet1"
344 }
345 fn crate_version() -> CrateVersion {
346 CrateVersion::new(1, 0, 0)
347 }
348 }
349 struct Pallet2;
350 impl PalletInfoAccess for Pallet2 {
351 fn index() -> usize {
352 2
353 }
354 fn name() -> &'static str {
355 "Pallet2"
356 }
357
358 fn name_hash() -> [u8; 16] {
359 twox_128(Self::name().as_bytes())
360 }
361
362 fn module_name() -> &'static str {
363 "pallet2"
364 }
365 fn crate_version() -> CrateVersion {
366 CrateVersion::new(1, 0, 0)
367 }
368 }
369
370 #[test]
371 fn check_storage_version_ordering() {
372 let version = StorageVersion::new(1);
373 assert!(version == StorageVersion::new(1));
374 assert!(version < StorageVersion::new(2));
375 assert!(version < StorageVersion::new(3));
376
377 let version = StorageVersion::new(2);
378 assert!(version < StorageVersion::new(3));
379 assert!(version > StorageVersion::new(1));
380 assert!(version < StorageVersion::new(5));
381 }
382}