pezframe_support/traits/
metadata.rs

1// This file is part of Bizinikiwi.
2
3// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
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 pezsp_runtime::RuntimeDebug;
25
26/// Provides information about the pezpallet itself and its setup in the runtime.
27///
28/// An implementor should be able to provide information about each pezpallet that
29/// is configured in `construct_runtime!`.
30pub trait PalletInfo {
31	/// Convert the given pezpallet `P` into its index as configured in the runtime.
32	fn index<P: 'static>() -> Option<usize>;
33	/// Convert the given pezpallet `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 pezpallet `P` into its Rust module name as used in `construct_runtime!`.
38	fn module_name<P: 'static>() -> Option<&'static str>;
39	/// Convert the given pezpallet `P` into its containing crate version.
40	fn crate_version<P: 'static>() -> Option<CrateVersion>;
41}
42
43/// Information regarding an instance of a pezpallet.
44#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
45pub struct PalletInfoData {
46	/// Index of the pezpallet as configured in the runtime.
47	pub index: usize,
48	/// Name of the pezpallet as configured in the runtime.
49	pub name: &'static str,
50	/// Name of the Rust module containing the pezpallet.
51	pub module_name: &'static str,
52	/// Version of the crate containing the pezpallet.
53	pub crate_version: CrateVersion,
54}
55
56/// Provides information about the pezpallet itself and its setup in the runtime.
57///
58/// Declare some information and access the information provided by [`PalletInfo`] for a specific
59/// pezpallet.
60pub trait PalletInfoAccess {
61	/// Index of the pezpallet as configured in the runtime.
62	fn index() -> usize;
63	/// Name of the pezpallet 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 pezpallet.
68	fn module_name() -> &'static str;
69	/// Version of the crate containing the pezpallet.
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 pezpallet 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 pezpallet to which the function belongs.
104	pub pezpallet_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 pezpallet 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 pezpallet 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 pezpallet.
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 pezpallet.
171///
172/// Each storage version of a pezpallet 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 pezpallet_name = P::name();
188		crate::storage::storage_prefix(
189			pezpallet_name.as_bytes(),
190			STORAGE_VERSION_STORAGE_KEY_POSTFIX,
191		)
192	}
193
194	/// Put this storage version for the given pezpallet into the storage.
195	///
196	/// It will use the storage key that is associated with the given `Pezpallet`.
197	///
198	/// # Panics
199	///
200	/// This function will panic iff `Pezpallet` can not be found by `PalletInfo`.
201	/// In a runtime that is put together using
202	/// [`construct_runtime!`](crate::construct_runtime) this should never happen.
203	///
204	/// It will also panic if this function isn't executed in an externalities
205	/// provided environment.
206	pub fn put<P: PalletInfoAccess>(&self) {
207		let key = Self::storage_key::<P>();
208
209		crate::storage::unhashed::put(&key, self);
210	}
211
212	/// Get the storage version of the given pezpallet from the storage.
213	///
214	/// It will use the storage key that is associated with the given `Pezpallet`.
215	///
216	/// # Panics
217	///
218	/// This function will panic iff `Pezpallet` can not be found by `PalletInfo`.
219	/// In a runtime that is put together using
220	/// [`construct_runtime!`](crate::construct_runtime) this should never happen.
221	///
222	/// It will also panic if this function isn't executed in an externalities
223	/// provided environment.
224	pub fn get<P: PalletInfoAccess>() -> Self {
225		let key = Self::storage_key::<P>();
226
227		crate::storage::unhashed::get_or_default(&key)
228	}
229
230	/// Returns if the storage version key for the given pezpallet exists in storage.
231	///
232	/// See [`STORAGE_VERSION_STORAGE_KEY_POSTFIX`] on how this key is built.
233	///
234	/// # Panics
235	///
236	/// This function will panic iff `Pezpallet` can not be found by `PalletInfo`.
237	/// In a runtime that is put together using
238	/// [`construct_runtime!`](crate::construct_runtime) this should never happen.
239	///
240	/// It will also panic if this function isn't executed in an externalities
241	/// provided environment.
242	pub fn exists<P: PalletInfoAccess>() -> bool {
243		let key = Self::storage_key::<P>();
244		crate::storage::unhashed::exists(&key)
245	}
246}
247
248impl PartialEq<u16> for StorageVersion {
249	fn eq(&self, other: &u16) -> bool {
250		self.0 == *other
251	}
252}
253
254impl PartialOrd<u16> for StorageVersion {
255	fn partial_cmp(&self, other: &u16) -> Option<core::cmp::Ordering> {
256		Some(self.0.cmp(other))
257	}
258}
259
260impl Add<u16> for StorageVersion {
261	type Output = StorageVersion;
262
263	fn add(self, rhs: u16) -> Self::Output {
264		Self::new(self.0 + rhs)
265	}
266}
267
268/// Special marker struct used when [`storage_version`](crate::pezpallet_macros::storage_version) is
269/// not defined for a pezpallet.
270///
271/// If you (the reader) end up here, it probably means that you tried to compare
272/// [`GetStorageVersion::on_chain_storage_version`] against
273/// [`GetStorageVersion::in_code_storage_version`]. This basically means that the
274/// [`storage_version`](crate::pezpallet_macros::storage_version) is missing from the pezpallet
275/// where the mentioned functions are being called, and needs to be defined.
276#[derive(Debug, Default)]
277pub struct NoStorageVersionSet;
278
279/// Provides information about a pezpallet's storage versions.
280///
281/// Every pezpallet has two storage versions:
282/// 1. An in-code storage version
283/// 2. An on-chain storage version
284///
285/// The in-code storage version is the version of the pezpallet as defined in the runtime blob, and
286/// the on-chain storage version is the version of the pezpallet stored on-chain.
287///
288/// Storage versions should be only ever be out of sync when a pezpallet has been updated to a new
289/// version and the in-code version is incremented, but the migration has not yet been executed
290/// on-chain as part of a runtime upgrade.
291///
292/// It is the responsibility of the developer to ensure that the on-chain storage version is set
293/// correctly during a migration so that it matches the in-code storage version.
294pub trait GetStorageVersion {
295	/// This type is generated by the [`pezpallet`](crate::pezpallet) macro.
296	///
297	/// If the [`storage_version`](crate::pezpallet_macros::storage_version) attribute isn't
298	/// specified, this is set to [`NoStorageVersionSet`] to signify that it is missing.
299	///
300	/// If the [`storage_version`](crate::pezpallet_macros::storage_version) attribute is specified,
301	/// this is be set to a [`StorageVersion`] corresponding to the attribute.
302	///
303	/// The intention of using [`NoStorageVersionSet`] instead of defaulting to a [`StorageVersion`]
304	/// of zero is to prevent developers from forgetting to set
305	/// [`storage_version`](crate::pezpallet_macros::storage_version) when it is required, like in
306	/// the case that they wish to compare the in-code storage version to the on-chain storage
307	/// version.
308	type InCodeStorageVersion;
309
310	#[deprecated(
311		note = "This method has been renamed to `in_code_storage_version` and will be removed after March 2024."
312	)]
313	/// DEPRECATED: Use [`Self::current_storage_version`] instead.
314	///
315	/// Returns the in-code storage version as specified in the
316	/// [`storage_version`](crate::pezpallet_macros::storage_version) attribute, or
317	/// [`NoStorageVersionSet`] if the attribute is missing.
318	fn current_storage_version() -> Self::InCodeStorageVersion {
319		Self::in_code_storage_version()
320	}
321
322	/// Returns the in-code storage version as specified in the
323	/// [`storage_version`](crate::pezpallet_macros::storage_version) attribute, or
324	/// [`NoStorageVersionSet`] if the attribute is missing.
325	fn in_code_storage_version() -> Self::InCodeStorageVersion;
326	/// Returns the storage version of the pezpallet as last set in the actual on-chain storage.
327	fn on_chain_storage_version() -> StorageVersion;
328}
329
330#[cfg(test)]
331mod tests {
332	use super::*;
333	use pezsp_crypto_hashing::twox_128;
334
335	#[allow(dead_code)]
336	struct Pallet1;
337	impl PalletInfoAccess for Pallet1 {
338		fn index() -> usize {
339			1
340		}
341		fn name() -> &'static str {
342			"Pallet1"
343		}
344		fn name_hash() -> [u8; 16] {
345			twox_128(Self::name().as_bytes())
346		}
347		fn module_name() -> &'static str {
348			"pallet1"
349		}
350		fn crate_version() -> CrateVersion {
351			CrateVersion::new(1, 0, 0)
352		}
353	}
354	#[allow(dead_code)]
355	struct Pallet2;
356	impl PalletInfoAccess for Pallet2 {
357		fn index() -> usize {
358			2
359		}
360		fn name() -> &'static str {
361			"Pallet2"
362		}
363
364		fn name_hash() -> [u8; 16] {
365			twox_128(Self::name().as_bytes())
366		}
367
368		fn module_name() -> &'static str {
369			"pallet2"
370		}
371		fn crate_version() -> CrateVersion {
372			CrateVersion::new(1, 0, 0)
373		}
374	}
375
376	#[test]
377	fn check_storage_version_ordering() {
378		let version = StorageVersion::new(1);
379		assert!(version == StorageVersion::new(1));
380		assert!(version < StorageVersion::new(2));
381		assert!(version < StorageVersion::new(3));
382
383		let version = StorageVersion::new(2);
384		assert!(version < StorageVersion::new(3));
385		assert!(version > StorageVersion::new(1));
386		assert!(version < StorageVersion::new(5));
387	}
388}