lib.rs 97.8 KiB
Newer Older
/// 			unimplemented!();
/// 		}
/// 	}
///
/// 	pub const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"testpall";
/// }
/// ```
///
/// 1. Export the metadata of the pallet for later checks
///     - run your node with the pallet active
///     - query the metadata using the `state_getMetadata` RPC and curl, or use `subsee -p
///       <PALLET_NAME> > meta.json`
/// 2. Generate the template upgrade for the pallet provided by `decl_storage` with the
///    environment variable `PRINT_PALLET_UPGRADE`: `PRINT_PALLET_UPGRADE=1 cargo check -p
///    my_pallet`. This template can be used as it contains all information for storages,
///    genesis config and genesis build.
/// 3. Reorganize the pallet to have the trait `Config`, `decl_*` macros,
///    [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`),
///    [`ProvideInherent`](`pallet_prelude::ProvideInherent`), and Origin` all together in one
///    file. Suggested order:
///     * `Config`,
///     * `decl_module`,
///     * `decl_event`,
///     * `decl_error`,
///     * `decl_storage`,
///     * `origin`,
///     * `validate_unsigned`,
///     * `provide_inherent`, so far it should compile and all be correct.
/// 4. start writing the new pallet module
/// 	```ignore
/// 	pub use pallet::*;
///
/// 	#[frame_support::pallet]
/// 	pub mod pallet {
/// 		use frame_support::pallet_prelude::*;
/// 		use frame_system::pallet_prelude::*;
/// 		use super::*;
///
/// 		#[pallet::pallet]
/// 		#[pallet::generate_store($visibility_of_trait_store trait Store)]
/// 		// NOTE: if the visibility of trait store is private but you want to make it available
/// 		// in super, then use `pub(super)` or `pub(crate)` to make it available in crate.
/// 		// pub struct Pallet<T, I = ()>(PhantomData<T>); // for instantiable pallet
/// 	}
/// 	```
/// 5. **migrate Config**: move trait into the module with
///     * all const in `decl_module` to [`#[pallet::constant]`](#palletconstant)
///     * add the bound `IsType<<Self as frame_system::Config>::RuntimeEvent>` to `type
///       RuntimeEvent`
/// 7. **migrate decl_module**: write:
/// 	```ignore
/// 	#[pallet::hooks]
/// 	impl<T: Config> Hooks for Pallet<T> {
///     and write inside `on_initialize`, `on_finalize`, `on_runtime_upgrade`,
///     `offchain_worker`, and `integrity_test`.
///
/// 	then write:
/// 	```ignore
/// 	#[pallet::call]
/// 	impl<T: Config> Pallet<T> {
///     and write inside all the calls in `decl_module` with a few changes in the signature:
///     - origin must now be written completely, e.g. `origin: OriginFor<T>`
///     - result type must be `DispatchResultWithPostInfo`, you need to write it and also you
///    might need to put `Ok(().into())` at the end or the function.
///     - `#[compact]` must now be written
///       [`#[pallet::compact]`](#palletcompact-some_arg-some_type)
///     - `#[weight = ..]` must now be written [`#[pallet::weight(..)]`](#palletweightexpr)
///
/// 7. **migrate event**: rewrite as a simple enum with the attribute
///    [`#[pallet::event]`](#event-palletevent-optional), use [`#[pallet::generate_deposit($vis
///    fn deposit_event)]`](#event-palletevent-optional) to generate `deposit_event`,
/// 8. **migrate error**: rewrite it with attribute
///    [`#[pallet::error]`](#error-palleterror-optional).
/// 9. **migrate storage**: `decl_storage` provide an upgrade template (see 3.). All storages,
///    genesis config, genesis build and default implementation of genesis config can be taken
///    from it directly.
///
///     Otherwise here is the manual process:
///
///     first migrate the genesis logic. write:
/// 	```ignore
/// 	#[pallet::genesis_config]
/// 	struct GenesisConfig {
/// 		// fields of add_extra_genesis
/// 	}
/// 	impl Default for GenesisConfig {
/// 		// type default or default provided for fields
/// 	}
/// 	#[pallet::genesis_build]
/// 	impl<T: Config> GenesisBuild<T> for GenesisConfig {
/// 	// for instantiable pallet:
/// 	// `impl<T: Config, I: 'static> GenesisBuild<T, I> for GenesisConfig {
/// 		fn build() {
/// 			// The add_extra_genesis build logic
/// 		}
/// 	}
/// 	```
///     for each storage, if it contains `config(..)` then add fields, and make it default to
///     the value in `= ..;` or the type default if none, if it contains no build then also add
///     the logic to build the value. for each storage if it contains `build(..)` then add the
///     logic to `genesis_build`.
///
///     NOTE: within `decl_storage`: the individual config is executed first, followed by the
///     build and finally the `add_extra_genesis` build.
///
///     Once this is done you can migrate storages individually, a few notes:
///     - for private storage use `pub(crate) type ` or `pub(super) type` or nothing,
///     - for storages with `get(fn ..)` use [`#[pallet::getter(fn
///       ...)]`](#palletgetterfn-my_getter_fn_name-optional)
///     - for storages with value being `Option<$something>` make generic `Value` being
///       `$something` and generic `QueryKind` being `OptionQuery` (note: this is default).
///       Otherwise make `Value` the complete value type and `QueryKind` being `ValueQuery`.
///     - for storages with default value: `= $expr;` provide some specific `OnEmpty` generic.
///       To do so use of `#[pallet::type_value]` to generate the wanted struct to put.
///       example: `MyStorage: u32 = 3u32` would be written:
///
/// 	  	```ignore
/// 		#[pallet::type_value] fn MyStorageOnEmpty() -> u32 { 3u32 }
/// 		#[pallet::storage]
/// 		pub(super) type MyStorage<T> = StorageValue<_, u32, ValueQuery, MyStorageOnEmpty>;
///       NOTE: `decl_storage` also generates the functions `assimilate_storage` and
///       `build_storage` directly on `GenesisConfig`, and these are sometimes used in tests.
///       In order not to break they can be implemented manually, one can implement those
///       functions by calling the `GenesisBuild` implementation.
/// 10. **migrate origin**: move the origin to the pallet module to be under a
///     [`#[pallet::origin]`](#origin-palletorigin-optional) attribute
/// 11. **migrate validate_unsigned**: move the
///     [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) implementation to the pallet
///     module under a
///     [`#[pallet::validate_unsigned]`](#validate-unsigned-palletvalidate_unsigned-optional)
///     attribute
/// 12. **migrate provide_inherent**: move the
///     [`ProvideInherent`](`pallet_prelude::ProvideInherent`) implementation to the pallet
///     module under a [`#[pallet::inherent]`](#inherent-palletinherent-optional) attribute
/// 13. rename the usage of `Module` to `Pallet` inside the crate.
/// 14. migration is done, now double check the migration with the checking migration
///     guidelines shown below.
/// * compare metadata. Use [subsee](https://github.com/ascjones/subsee) to fetch the metadata
///   and do a diff of the resulting json before and after migration. This checks for:
/// 		* call, names, signature, docs
///     * event names, docs
///     * error names, docs
///     * storage names, hasher, prefixes, default value
///     * error, error, constant
/// * manually check that:
///     * `Origin` was moved inside the macro under
///       [`#[pallet::origin]`](#origin-palletorigin-optional) if it exists
///     * [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) was moved inside the macro
///       under
/// 	  [`#[pallet::validate_unsigned)]`](#validate-unsigned-palletvalidate_unsigned-optional)
/// 	  if it exists
///     * [`ProvideInherent`](`pallet_prelude::ProvideInherent`) was moved inside the macro
///       under [`#[pallet::inherent)]`](#inherent-palletinherent-optional) if it exists
///     * `on_initialize` / `on_finalize` / `on_runtime_upgrade` / `offchain_worker` were moved
///       to the `Hooks` implementation
///     * storages with `config(..)` were converted to `GenesisConfig` field, and their default
///       is `= $expr;` if the storage has a default value
///     * storages with `build($expr)` or `config(..)` were built in `GenesisBuild::build`
///     * `add_extra_genesis` fields were converted to `GenesisConfig` field with their correct
///       default if specified
///     * `add_extra_genesis` build was written into `GenesisBuild::build`
/// * storage items defined with [`pallet`] use the name of the pallet provided by
///   [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used
///   the `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). Thus
///   a runtime using the pallet must be careful with this change. To handle this change:
///     * either ensure that the name of the pallet given to `construct_runtime!` is the same
///       as the name the pallet was giving to `decl_storage`,
///     * or do a storage migration from the old prefix used to the new prefix used.
///
/// NOTE: The prefixes used by storage items are in metadata. Thus, ensuring the metadata
/// hasn't changed ensures that the `pallet_prefix`s used by the storage items haven't changed.
///
/// # Notes when macro fails to show proper error message spans:
///
/// Rustc loses span for some macro input. Some tips to fix it:
/// * do not use inner attribute:
/// 	```ignore
/// 	#[pallet]
/// 	pub mod pallet {
/// 		//! This inner attribute will make span fail
/// 		..
/// 	}
/// 	```
/// * use the newest nightly possible.
pub use frame_support_procedural::pallet;

/// Contains macro stubs for all of the pallet:: macros
pub mod pallet_macros {
	pub use frame_support_procedural::{
		call_index, compact, composite_enum, config, disable_frame_system_supertrait_check, error,
		event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section,
		inherent, no_default, no_default_bounds, origin, pallet_section, storage_prefix,
		storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage,

	/// Allows you to define the genesis configuration for the pallet.
	///
	/// Item is defined as either an enum or a struct. It needs to be public and implement the
	/// trait [`frame_support::traits::BuildGenesisConfig`].
	///
	/// See [`genesis_build`] for an example.
	pub use frame_support_procedural::genesis_config;

	/// Allows you to define how the state of your pallet at genesis is built. This
	/// takes as input the `GenesisConfig` type (as `self`) and constructs the pallet's initial
	/// state.
	///
	/// The fields of the `GenesisConfig` can in turn be populated by the chain-spec.
	///
	/// ## Example
	///
	/// ```
	/// #[frame_support::pallet]
	/// pub mod pallet {
	/// # 	#[pallet::config]
	/// # 	pub trait Config: frame_system::Config {}
	/// # 	#[pallet::pallet]
	/// # 	pub struct Pallet<T>(_);
	/// # 	use frame_support::traits::BuildGenesisConfig;
	///     #[pallet::genesis_config]
	///     #[derive(frame_support::DefaultNoBound)]
	///     pub struct GenesisConfig<T: Config> {
	///         foo: Vec<T::AccountId>
	///     }
	///
	///     #[pallet::genesis_build]
	///     impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
	///         fn build(&self) {
	///             // use &self to access fields.
	///             let foo = &self.foo;
	///             todo!()
	///         }
	///     }
	/// }
	/// ```
	///
	/// ## Former Usage
	///
	/// Prior to <https://github.com/paritytech/substrate/pull/14306>, the following syntax was used.
	/// This is deprecated and will soon be removed.
	///
	/// ```
	/// #[frame_support::pallet]
	/// pub mod pallet {
	/// #     #[pallet::config]
	/// #     pub trait Config: frame_system::Config {}
	/// #     #[pallet::pallet]
	/// #     pub struct Pallet<T>(_);
	/// #     use frame_support::traits::GenesisBuild;
	///     #[pallet::genesis_config]
	///     #[derive(frame_support::DefaultNoBound)]
	///     pub struct GenesisConfig<T: Config> {
	/// 		foo: Vec<T::AccountId>
	/// 	}
	///
	///     #[pallet::genesis_build]
	///     impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
	///         fn build(&self) {
	///             todo!()
	///         }
	///     }
	/// }
	/// ```
	pub use frame_support_procedural::genesis_build;

	/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded
	/// by [`Get`](frame_support::pallet_prelude::Get) from [`pallet::config`](`macro@config`)
	/// into metadata.
	///
	/// ## Example
	///
	/// ```
	/// #[frame_support::pallet]
	/// mod pallet {
	///     use frame_support::pallet_prelude::*;
	///     # #[pallet::pallet]
	///     # pub struct Pallet<T>(_);
	///     #[pallet::config]
	///     pub trait Config: frame_system::Config {
	/// 		/// This is like a normal `Get` trait, but it will be added into metadata.
	/// 		#[pallet::constant]
	/// 		type Foo: Get<u32>;
	/// 	}
	/// }
	/// ```
	pub use frame_support_procedural::constant;

	/// Declares a type alias as a storage item. Storage items are pointers to data stored
	/// on-chain (the *blockchain state*), under a specific key. The exact key is dependent on
	/// the type of the storage.
	///
	/// > From the perspective of this pallet, the entire blockchain state is abstracted behind
	/// > a key-value api, namely [`sp_io::storage`].
	///
	/// ## Storage Types
	///
	/// The following storage types are supported by the `#[storage]` macro. For specific
	/// information about each storage type, refer to the documentation of the respective type.
	///
	/// * [`StorageValue`](crate::storage::types::StorageValue)
	/// * [`StorageMap`](crate::storage::types::StorageMap)
	/// * [`CountedStorageMap`](crate::storage::types::CountedStorageMap)
	/// * [`StorageDoubleMap`](crate::storage::types::StorageDoubleMap)
	/// * [`StorageNMap`](crate::storage::types::StorageNMap)
	/// * [`CountedStorageNMap`](crate::storage::types::CountedStorageNMap)
	///
	/// ## Storage Type Usage
	///
	/// The following details are relevant to all of the aforementioned storage types.
	/// Depending on the exact storage type, it may require the following generic parameters:
	///
	/// * [`Prefix`](#prefixes) - Used to give the storage item a unique key in the underlying
	///   storage.
	/// * `Key` - Type of the keys used to store the values,
	/// * `Value` - Type of the value being stored,
	/// * [`Hasher`](#hashers) - Used to ensure the keys of a map are uniformly distributed,
	/// * [`QueryKind`](#querykind) - Used to configure how to handle queries to the underlying
	///   storage,
	/// * `OnEmpty` - Used to handle missing values when querying the underlying storage,
	/// * `MaxValues` - _not currently used_.
	///
	/// Each `Key` type requires its own designated `Hasher` declaration, so that
	/// [`StorageDoubleMap`](frame_support::storage::types::StorageDoubleMap) needs two of
	/// each, and [`StorageNMap`](frame_support::storage::types::StorageNMap) needs `N` such
	/// pairs. Since [`StorageValue`](frame_support::storage::types::StorageValue) only stores
	/// a single element, no configuration of hashers is needed.
	///
	/// ### Syntax
	///
	/// Two general syntaxes are supported, as demonstrated below:
	///
	/// 1. Named type parameters, e.g., `type Foo<T> = StorageValue<Value = u32>`.
	/// 2. Positional type parameters, e.g., `type Foo<T> = StorageValue<_, u32>`.
	///
	/// In both instances, declaring the generic parameter `<T>` is mandatory. Optionally, it
	/// can also be explicitly declared as `<T: Config>`. In the compiled code, `T` will
	/// automatically include the trait bound `Config`.
	///
	/// Note that in positional syntax, the first generic type parameter must be `_`.
	///
	/// #### Example
	///
	/// ```
	/// #[frame_support::pallet]
	/// mod pallet {
	///     # use frame_support::pallet_prelude::*;
	///     # #[pallet::config]
	///     # pub trait Config: frame_system::Config {}
	///     # #[pallet::pallet]
	///     # pub struct Pallet<T>(_);
	///     /// Positional syntax, without bounding `T`.
	///     #[pallet::storage]
	///     pub type Foo<T> = StorageValue<_, u32>;
	///
	///     /// Positional syntax, with bounding `T`.
	///     #[pallet::storage]
	///     pub type Bar<T: Config> = StorageValue<_, u32>;
	///
	///     /// Named syntax.
	///     #[pallet::storage]
	///     pub type Baz<T> = StorageMap<Hasher = Blake2_128Concat, Key = u32, Value = u32>;
	/// }
	/// ```
	///
	/// ### QueryKind
	///
	/// Every storage type mentioned above has a generic type called
	/// [`QueryKind`](frame_support::storage::types::QueryKindTrait) that determines its
	/// "query" type. This refers to the kind of value returned when querying the storage, for
	/// instance, through a `::get()` method.
	///
	/// There are three types of queries:
	///
	/// 1. [`OptionQuery`](frame_support::storage::types::OptionQuery): The default query type.
	///    It returns `Some(V)` if the value is present, or `None` if it isn't, where `V` is
	///    the value type.
	/// 2. [`ValueQuery`](frame_support::storage::types::ValueQuery): Returns the value itself
	///    if present; otherwise, it returns `Default::default()`. This behavior can be
	///    adjusted with the `OnEmpty` generic parameter, which defaults to `OnEmpty =
	///    GetDefault`.
	/// 3. [`ResultQuery`](frame_support::storage::types::ResultQuery): Returns `Result<V, E>`,
	///    where `V` is the value type.
	///
	/// See [`QueryKind`](frame_support::storage::types::QueryKindTrait) for further examples.
	///
	/// ### Optimized Appending
	///
	/// All storage items — such as
	/// [`StorageValue`](frame_support::storage::types::StorageValue),
	/// [`StorageMap`](frame_support::storage::types::StorageMap), and their variants—offer an
	/// `::append()` method optimized for collections. Using this method avoids the
	/// inefficiency of decoding and re-encoding entire collections when adding items. For
	/// instance, consider the storage declaration `type MyVal<T> = StorageValue<_, Vec<u8>,
	/// ValueQuery>`. With `MyVal` storing a large list of bytes, `::append()` lets you
	/// directly add bytes to the end in storage without processing the full list. Depending on
	/// the storage type, additional key specifications may be needed.
	///
	/// #### Example
	#[doc = docify::embed!("src/lib.rs", example_storage_value_append)]
	/// Similarly, there also exists a `::try_append()` method, which can be used when handling
	/// types where an append operation might fail, such as a
	/// [`BoundedVec`](frame_support::BoundedVec).
	///
	/// #### Example
	#[doc = docify::embed!("src/lib.rs", example_storage_value_try_append)]
	/// ### Optimized Length Decoding
	///
	/// All storage items — such as
	/// [`StorageValue`](frame_support::storage::types::StorageValue),
	/// [`StorageMap`](frame_support::storage::types::StorageMap), and their counterparts —
	/// incorporate the `::decode_len()` method. This method allows for efficient retrieval of
	/// a collection's length without the necessity of decoding the entire dataset.
	/// #### Example
	#[doc = docify::embed!("src/lib.rs", example_storage_value_decode_len)]
	/// ### Hashers
	///
	/// For all storage types, except
	/// [`StorageValue`](frame_support::storage::types::StorageValue), a set of hashers needs
	/// to be specified. The choice of hashers is crucial, especially in production chains. The
	/// purpose of storage hashers in maps is to ensure the keys of a map are
	/// uniformly distributed. An unbalanced map/trie can lead to inefficient performance.
	///
	/// In general, hashers are categorized as either cryptographically secure or not. The
	/// former is slower than the latter. `Blake2` and `Twox` serve as examples of each,
	/// respectively.
	///
	/// As a rule of thumb:
	///
	/// 1. If the map keys are not controlled by end users, or are cryptographically secure by
	/// definition (e.g., `AccountId`), then the use of cryptographically secure hashers is NOT
	/// required.
	/// 2. If the map keys are controllable by the end users, cryptographically secure hashers
	/// should be used.
	///
	/// For more information, look at the types that implement
	/// [`frame_support::StorageHasher`](frame_support::StorageHasher).
	///
	/// Lastly, it's recommended for hashers with "concat" to have reversible hashes. Refer to
	/// the implementors section of
	/// [`hash::ReversibleStorageHasher`](frame_support::hash::ReversibleStorageHasher).
	///
	/// ### Prefixes
	///
	/// Internally, every storage type generates a "prefix". This prefix serves as the initial
	/// segment of the key utilized to store values in the on-chain state (i.e., the final key
	/// used in [`sp_io::storage`](sp_io::storage)). For all storage types, the following rule
	/// applies:
	///
	/// > The storage prefix begins with `twox128(pallet_prefix) ++ twox128(STORAGE_PREFIX)`,
	/// > where
	/// > `pallet_prefix` is the name assigned to the pallet instance in
	/// > [`frame_support::construct_runtime`](frame_support::construct_runtime), and
	/// > `STORAGE_PREFIX` is the name of the `type` aliased to a particular storage type, such
	/// > as
	/// > `Foo` in `type Foo<T> = StorageValue<..>`.
	///
	/// For [`StorageValue`](frame_support::storage::types::StorageValue), no additional key is
	/// required. For map types, the prefix is extended with one or more keys defined by the
	/// map.
	///
	/// #### Example
	#[doc = docify::embed!("src/lib.rs", example_storage_value_map_prefixes)]
	/// ## Related Macros
	///
	/// The following attribute macros can be used in conjunction with the `#[storage]` macro:
	///
	/// * [`macro@getter`]: Creates a custom getter function.
	/// * [`macro@storage_prefix`]: Overrides the default prefix of the storage item.
	/// * [`macro@unbounded`]: Declares the storage item as unbounded.
	///
	/// #### Example
	/// ```
	/// #[frame_support::pallet]
	/// mod pallet {
	///     # use frame_support::pallet_prelude::*;
	///     # #[pallet::config]
	///     # pub trait Config: frame_system::Config {}
	///     # #[pallet::pallet]
	///     # pub struct Pallet<T>(_);
	/// 	/// A kitchen-sink StorageValue, with all possible additional attributes.
	///     #[pallet::storage]
	/// 	#[pallet::getter(fn foo)]
	/// 	#[pallet::storage_prefix = "OtherFoo"]
	/// 	#[pallet::unbounded]
	///     pub type Foo<T> = StorageValue<_, u32, ValueQuery>;
	/// }
	/// ```
	pub use frame_support_procedural::storage;
#[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")]
pub mod error {
	#[doc(hidden)]
	pub use sp_runtime::traits::{BadOrigin, LookupError};
}

#[doc(inline)]
pub use frame_support_procedural::register_default_impl;

// Generate a macro that will enable/disable code based on `std` feature being active.
sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $);

// Helper for implementing GenesisBuilder runtime API
pub mod genesis_builder_helper;

#[cfg(test)]
mod test {
	// use super::*;
	use crate::{
		hash::*,
		storage::types::{StorageMap, StorageValue, ValueQuery},
		traits::{ConstU32, StorageInstance},
		BoundedVec,
	};
	use sp_io::{hashing::twox_128, TestExternalities};

	struct Prefix;
	impl StorageInstance for Prefix {
		fn pallet_prefix() -> &'static str {
			"test"
		}
		const STORAGE_PREFIX: &'static str = "foo";
	}

	struct Prefix1;
	impl StorageInstance for Prefix1 {
		fn pallet_prefix() -> &'static str {
			"test"
		}
		const STORAGE_PREFIX: &'static str = "MyVal";
	}
	struct Prefix2;
	impl StorageInstance for Prefix2 {
		fn pallet_prefix() -> &'static str {
			"test"
		}
		const STORAGE_PREFIX: &'static str = "MyMap";
	}

	#[docify::export]
	#[test]
	pub fn example_storage_value_try_append() {
		type MyVal = StorageValue<Prefix, BoundedVec<u8, ConstU32<10>>, ValueQuery>;

		TestExternalities::default().execute_with(|| {
			MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap());
			assert_eq!(MyVal::get(), vec![42, 43]);
			// Try to append a single u32 to BoundedVec stored in `MyVal`
			assert_ok!(MyVal::try_append(40));
			assert_eq!(MyVal::get(), vec![42, 43, 40]);
		});
	}

	#[docify::export]
	#[test]
	pub fn example_storage_value_append() {
		type MyVal = StorageValue<Prefix, Vec<u8>, ValueQuery>;

		TestExternalities::default().execute_with(|| {
			MyVal::set(vec![42, 43]);
			assert_eq!(MyVal::get(), vec![42, 43]);
			// Append a single u32 to Vec stored in `MyVal`
			MyVal::append(40);
			assert_eq!(MyVal::get(), vec![42, 43, 40]);
		});
	}

	#[docify::export]
	#[test]
	pub fn example_storage_value_decode_len() {
		type MyVal = StorageValue<Prefix, BoundedVec<u8, ConstU32<10>>, ValueQuery>;

		TestExternalities::default().execute_with(|| {
			MyVal::set(BoundedVec::try_from(vec![42, 43]).unwrap());
			assert_eq!(MyVal::decode_len().unwrap(), 2);
		});
	}

	#[docify::export]
	#[test]
	pub fn example_storage_value_map_prefixes() {
		type MyVal = StorageValue<Prefix1, u32, ValueQuery>;
		type MyMap = StorageMap<Prefix2, Blake2_128Concat, u16, u32, ValueQuery>;
		TestExternalities::default().execute_with(|| {
			// This example assumes `pallet_prefix` to be "test"
			// Get storage key for `MyVal` StorageValue
			assert_eq!(
				MyVal::hashed_key().to_vec(),
				[twox_128(b"test"), twox_128(b"MyVal")].concat()
			);
			// Get storage key for `MyMap` StorageMap and `key` = 1
			let mut k: Vec<u8> = vec![];
			k.extend(&twox_128(b"test"));
			k.extend(&twox_128(b"MyMap"));
			k.extend(&1u16.blake2_128_concat());
			assert_eq!(MyMap::hashed_key_for(1).to_vec(), k);
		});
	}
}