Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
/// unimplemented!();
/// }
/// }
///
/// #[pallet::error]
/// pub enum Error<T, I = ()> {
/// /// doc comment put into metadata
/// InsufficientProposersBalance,
/// }
///
/// #[pallet::event]
/// #[pallet::metadata(BalanceOf<T> = "Balance", u32 = "Other")]
/// #[pallet::generate_deposit(pub(super) fn deposit_event)]
/// pub enum Event<T: Config<I>, I: 'static = ()> {
/// /// doc comment put in metadata
/// Proposed(<T as frame_system::Config>::AccountId),
/// /// doc
/// Spending(BalanceOf<T, I>),
/// Something(u32),
/// }
///
/// #[pallet::type_value]
/// pub(super) fn MyDefault<T: Config<I>, I: 'static>() -> T::Balance { 3.into() }
///
/// #[pallet::storage]
/// pub(super) type MyStorageValue<T: Config<I>, I: 'static = ()> =
/// StorageValue<_, T::Balance, ValueQuery, MyDefault<T, I>>;
///
/// #[pallet::storage]
/// #[pallet::getter(fn my_storage)]
/// pub(super) type MyStorage<T, I = ()> =
/// StorageMap<_, Blake2_128Concat, u32, u32>;
///
/// #[pallet::genesis_config]
/// #[derive(Default)]
/// pub struct GenesisConfig {
/// _myfield: u32,
/// }
///
/// #[pallet::genesis_build]
/// impl<T: Config<I>, I: 'static> GenesisBuild<T, I> for GenesisConfig {
/// fn build(&self) {}
/// }
///
/// #[pallet::origin]
/// pub struct Origin<T, I = ()>(PhantomData<(T, I)>);
///
/// #[pallet::validate_unsigned]
/// impl<T: Config<I>, I: 'static> ValidateUnsigned for Pallet<T, I> {
/// type Call = Call<T, I>;
/// fn validate_unsigned(
/// source: TransactionSource,
/// call: &Self::Call
/// ) -> TransactionValidity {
/// Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
/// }
/// }
///
/// #[pallet::inherent]
/// impl<T: Config<I>, I: 'static> ProvideInherent for Pallet<T, I> {
/// type Call = Call<T, I>;
/// type Error = InherentError;
///
/// const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
///
/// fn create_inherent(_data: &InherentData) -> Option<Self::Call> {
/// unimplemented!();
/// }
/// }
///
/// // Regular rust code needed for implementing ProvideInherent trait
///
/// #[derive(codec::Encode, sp_runtime::RuntimeDebug)]
/// #[cfg_attr(feature = "std", derive(codec::Decode))]
/// pub enum InherentError {
/// }
///
/// impl sp_inherents::IsFatalError for InherentError {
/// fn is_fatal_error(&self) -> bool {
/// unimplemented!();
/// }
/// }
///
/// pub const INHERENT_IDENTIFIER: sp_inherents::InherentIdentifier = *b"testpall";
/// }
/// ```
///
/// ## Upgrade guidelines:
///
/// 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 environment variable `PRINT_PALLET_UPGRADE`:
/// `PRINT_PALLET_UPGRADE=1 cargo check -p my_pallet` This template can be
/// used as information it contains all information for storages, genesis
/// config and genesis build.
/// 3. reorganize pallet to have trait `Config`, `decl_*` macros, `ValidateUnsigned`,
/// `ProvideInherent`, `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.
![thiolliere thiolliere's avatar](/assets/no_avatar-849f9c04a3a0d0cea2424ae97b27447dc64a7dbfae83c036c45b403392f0e8ba.png)
thiolliere
committed
/// pub struct Pallet<T>(_);
/// // 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]`
/// * add bound `IsType<<Self as frame_system::Config>::Event>` to `type Event`
/// 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/integrity_test
///
/// then write:
/// ```ignore
/// #[pallet::call]
/// }
/// ```
/// 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]`
/// - `#[weight = ..]` must now be written `#[pallet::weight(..)]`
///
/// rewrite as a simple enum under with the attribute `#[pallet::event]`,
/// use `#[pallet::generate_deposit($vis fn deposit_event)]` to generate deposit_event,
/// use `#[pallet::metadata(...)]` to configure the metadata for types in order not to break them.
/// 8. **migrate error**: rewrite it with attribute `#[pallet::error]`.
/// 9. **migrate storage**:
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
/// 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 {
/// // impl<T: Config, I: 'static> GenesisBuild<T, I> for GenesisConfig { for instantiable pallet
/// fn build() {
/// // The add_extra_genesis build logic
/// }
/// }
/// ```
/// for each storages, if it contains config(..) then add a fields, and make its 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 storages if it contains build(..) then add the logic to genesis_build.
///
/// NOTE: in decl_storage: is executed first the individual config and build and at the end the
/// add_extra_genesis build
///
/// Once this is done you can migrate storage individually, a few notes:
/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing,
/// - for storage with `get(fn ..)` use `#[pallet::getter(fn ...)]`
/// - for storage 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 storage 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 functions `assimilate_storage` and `build_storage`
/// directly on GenesisConfig, those are sometimes used in tests. In order not to break they
/// can be implemented manually, one can implement those functions by calling `GenesisBuild`
/// implementation.
///
/// 10. **migrate origin**: move the origin to the pallet module under `#[pallet::origin]`
/// 11. **migrate validate_unsigned**: move the `ValidateUnsigned` implementation to the pallet
/// module under `#[pallet::validate_unsigned]`
/// 12. **migrate provide_inherent**: move the `ProvideInherent` implementation to the pallet
/// module under `#[pallet::inherent]`
/// 13. rename the usage of `Module` to `Pallet` inside the crate.
/// 14. migration is done, now double check migration with the checking migration guidelines.
///
/// ## Checking upgrade guidelines:
///
/// * 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` is moved inside the macro under `#[pallet::origin]` if it exists
/// * `ValidateUnsigned` is moved inside the macro under `#[pallet::validate_unsigned)]` if it exists
/// * `ProvideInherent` is moved inside macro under `#[pallet::inherent)]` if it exists
/// * `on_initialize`/`on_finalize`/`on_runtime_upgrade`/`offchain_worker` are moved to `Hooks`
/// implementation
/// * storages with `config(..)` are converted to `GenesisConfig` field, and their default is
/// `= $expr;` if the storage have default value
/// * storages with `build($expr)` or `config(..)` are built in `GenesisBuild::build`
/// * `add_extra_genesis` fields are converted to `GenesisConfig` field with their correct
/// default if specified
/// * `add_extra_genesis` build is 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 the metadata. Thus, ensuring the metadata hasn't
/// changed does ensure 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;