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}