referrerpolicy=no-referrer-when-downgrade

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}