mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 15:21:08 +00:00
Runtime Upgrade ref docs and Single Block Migration example pallet (#1554)
Closes https://github.com/paritytech/polkadot-sdk-docs/issues/55 - Changes 'current storage version' terminology to less ambiguous 'in-code storage version' (suggestion by @ggwpez) - Adds a new example pallet `pallet-example-single-block-migrations` - Adds a new reference doc to replace https://docs.substrate.io/maintain/runtime-upgrades/ (temporarily living in the pallet while we wait for developer hub PR to merge) - Adds documentation for the `storage_alias` macro - Improves `trait Hooks` docs - Improves `trait GetStorageVersion` docs - Update the suggested patterns for using `VersionedMigration`, so that version unchecked migrations are never exported - Prevents accidental usage of version unchecked migrations in runtimes https://github.com/paritytech/substrate/pull/14421#discussion_r1255467895 - Unversioned migration code is kept inside `mod version_unchecked`, versioned code is kept in `pub mod versioned` - It is necessary to use modules to limit visibility because the inner migration must be `pub`. See https://github.com/rust-lang/rust/issues/30905 and https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40 for more. ### todo - [x] move to reference docs to proper place within sdk-docs (now that https://github.com/paritytech/polkadot-sdk/pull/2102 is merged) - [x] prdoc --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Juan <juangirini@gmail.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: command-bot <> Co-authored-by: gupnik <nikhilgupta.iitk@gmail.com>
This commit is contained in:
Generated
+26
@@ -9965,6 +9965,26 @@ dependencies = [
|
||||
"sp-std 14.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-example-single-block-migrations"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"docify",
|
||||
"frame-executive",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"frame-try-runtime",
|
||||
"log",
|
||||
"pallet-balances",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
"sp-std 14.0.0",
|
||||
"sp-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-example-split"
|
||||
version = "10.0.0"
|
||||
@@ -10006,6 +10026,7 @@ dependencies = [
|
||||
"pallet-example-frame-crate",
|
||||
"pallet-example-kitchensink",
|
||||
"pallet-example-offchain-worker",
|
||||
"pallet-example-single-block-migrations",
|
||||
"pallet-example-split",
|
||||
"pallet-example-tasks",
|
||||
]
|
||||
@@ -13385,6 +13406,8 @@ dependencies = [
|
||||
"cumulus-pallet-parachain-system",
|
||||
"docify",
|
||||
"frame",
|
||||
"frame-executive",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"kitchensink-runtime",
|
||||
"pallet-aura",
|
||||
@@ -13393,9 +13416,11 @@ dependencies = [
|
||||
"pallet-collective",
|
||||
"pallet-default-config-example",
|
||||
"pallet-democracy",
|
||||
"pallet-example-single-block-migrations",
|
||||
"pallet-examples",
|
||||
"pallet-multisig",
|
||||
"pallet-proxy",
|
||||
"pallet-scheduler",
|
||||
"pallet-timestamp",
|
||||
"pallet-transaction-payment",
|
||||
"pallet-utility",
|
||||
@@ -13418,6 +13443,7 @@ dependencies = [
|
||||
"sp-io",
|
||||
"sp-keyring",
|
||||
"sp-runtime",
|
||||
"sp-version",
|
||||
"staging-chain-spec-builder",
|
||||
"staging-node-cli",
|
||||
"staging-parachain-info",
|
||||
|
||||
@@ -337,6 +337,7 @@ members = [
|
||||
"substrate/frame/examples/frame-crate",
|
||||
"substrate/frame/examples/kitchensink",
|
||||
"substrate/frame/examples/offchain-worker",
|
||||
"substrate/frame/examples/single-block-migrations",
|
||||
"substrate/frame/examples/split",
|
||||
"substrate/frame/examples/tasks",
|
||||
"substrate/frame/executive",
|
||||
|
||||
@@ -118,7 +118,7 @@ pub mod pallet {
|
||||
use sp_staking::SessionIndex;
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
type BalanceOf<T> =
|
||||
|
||||
@@ -31,8 +31,8 @@ pub mod v1 {
|
||||
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
if onchain_version == 0 {
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
if on_chain_version == 0 {
|
||||
let invulnerables_len = Invulnerables::<T>::get().to_vec().len();
|
||||
<Invulnerables<T>>::mutate(|invulnerables| {
|
||||
invulnerables.sort();
|
||||
@@ -45,7 +45,7 @@ pub mod v1 {
|
||||
invulnerables_len,
|
||||
);
|
||||
// Similar complexity to `set_invulnerables` (put storage value)
|
||||
// Plus 1 read for length, 1 read for `onchain_version`, 1 write to put version
|
||||
// Plus 1 read for length, 1 read for `on_chain_version`, 1 write to put version
|
||||
T::WeightInfo::set_invulnerables(invulnerables_len as u32)
|
||||
.saturating_add(T::DbWeight::get().reads_writes(2, 1))
|
||||
} else {
|
||||
@@ -83,8 +83,8 @@ pub mod v1 {
|
||||
"after migration, there should be the same number of invulnerables"
|
||||
);
|
||||
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
frame_support::ensure!(onchain_version >= 1, "must_upgrade");
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
frame_support::ensure!(on_chain_version >= 1, "must_upgrade");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ use frame_support::{
|
||||
weights::Weight,
|
||||
};
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
|
||||
|
||||
/// Migrates the pallet storage to the most recent version.
|
||||
|
||||
@@ -24,7 +24,7 @@ use frame_support::{
|
||||
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight},
|
||||
};
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
pub const LOG: &str = "runtime::xcmp-queue-migration";
|
||||
|
||||
@@ -59,7 +59,7 @@ pub mod pallet {
|
||||
use frame_system::pallet_prelude::*;
|
||||
use sp_runtime::{traits::BadOrigin, Saturating};
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -986,37 +986,37 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions {
|
||||
let mut writes = 0;
|
||||
|
||||
if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
PolkadotXcm::current_storage_version().put::<PolkadotXcm>();
|
||||
PolkadotXcm::in_code_storage_version().put::<PolkadotXcm>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if Multisig::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
Multisig::current_storage_version().put::<Multisig>();
|
||||
Multisig::in_code_storage_version().put::<Multisig>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if Assets::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
Assets::current_storage_version().put::<Assets>();
|
||||
Assets::in_code_storage_version().put::<Assets>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if Uniques::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
Uniques::current_storage_version().put::<Uniques>();
|
||||
Uniques::in_code_storage_version().put::<Uniques>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if Nfts::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
Nfts::current_storage_version().put::<Nfts>();
|
||||
Nfts::in_code_storage_version().put::<Nfts>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if ForeignAssets::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
ForeignAssets::current_storage_version().put::<ForeignAssets>();
|
||||
ForeignAssets::in_code_storage_version().put::<ForeignAssets>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if PoolAssets::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
PoolAssets::current_storage_version().put::<PoolAssets>();
|
||||
PoolAssets::in_code_storage_version().put::<PoolAssets>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
|
||||
@@ -1037,17 +1037,17 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions {
|
||||
let mut writes = 0;
|
||||
|
||||
if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
PolkadotXcm::current_storage_version().put::<PolkadotXcm>();
|
||||
PolkadotXcm::in_code_storage_version().put::<PolkadotXcm>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if ForeignAssets::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
ForeignAssets::current_storage_version().put::<ForeignAssets>();
|
||||
ForeignAssets::in_code_storage_version().put::<ForeignAssets>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if PoolAssets::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
PoolAssets::current_storage_version().put::<PoolAssets>();
|
||||
PoolAssets::in_code_storage_version().put::<PoolAssets>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
|
||||
@@ -168,12 +168,12 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions {
|
||||
let mut writes = 0;
|
||||
|
||||
if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
PolkadotXcm::current_storage_version().put::<PolkadotXcm>();
|
||||
PolkadotXcm::in_code_storage_version().put::<PolkadotXcm>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if Balances::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
Balances::current_storage_version().put::<Balances>();
|
||||
Balances::in_code_storage_version().put::<Balances>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,12 +142,12 @@ impl frame_support::traits::OnRuntimeUpgrade for InitStorageVersions {
|
||||
let mut writes = 0;
|
||||
|
||||
if PolkadotXcm::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
PolkadotXcm::current_storage_version().put::<PolkadotXcm>();
|
||||
PolkadotXcm::in_code_storage_version().put::<PolkadotXcm>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
if Balances::on_chain_storage_version() == StorageVersion::new(0) {
|
||||
Balances::current_storage_version().put::<Balances>();
|
||||
Balances::in_code_storage_version().put::<Balances>();
|
||||
writes.saturating_inc();
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -33,6 +33,10 @@ node-cli = { package = "staging-node-cli", path = "../../substrate/bin/node/cli"
|
||||
kitchensink-runtime = { path = "../../substrate/bin/node/runtime" }
|
||||
chain-spec-builder = { package = "staging-chain-spec-builder", path = "../../substrate/bin/utils/chain-spec-builder" }
|
||||
subkey = { path = "../../substrate/bin/utils/subkey" }
|
||||
frame-system = { path = "../../substrate/frame/system", default-features = false }
|
||||
frame-support = { path = "../../substrate/frame/support", default-features = false }
|
||||
frame-executive = { path = "../../substrate/frame/executive", default-features = false }
|
||||
pallet-example-single-block-migrations = { path = "../../substrate/frame/examples/single-block-migrations" }
|
||||
|
||||
# Substrate
|
||||
sc-network = { path = "../../substrate/client/network" }
|
||||
@@ -66,7 +70,7 @@ pallet-proxy = { path = "../../substrate/frame/proxy" }
|
||||
pallet-authorship = { path = "../../substrate/frame/authorship" }
|
||||
pallet-collective = { path = "../../substrate/frame/collective" }
|
||||
pallet-democracy = { path = "../../substrate/frame/democracy" }
|
||||
frame-system = { path = "../../substrate/frame/system" }
|
||||
pallet-scheduler = { path = "../../substrate/frame/scheduler" }
|
||||
|
||||
# Primitives
|
||||
sp-io = { path = "../../substrate/primitives/io" }
|
||||
@@ -74,6 +78,7 @@ sp-api = { path = "../../substrate/primitives/api" }
|
||||
sp-core = { path = "../../substrate/primitives/core" }
|
||||
sp-keyring = { path = "../../substrate/primitives/keyring" }
|
||||
sp-runtime = { path = "../../substrate/primitives/runtime" }
|
||||
sp-version = { path = "../../substrate/primitives/version" }
|
||||
|
||||
# XCM
|
||||
xcm = { package = "staging-xcm", path = "../../polkadot/xcm" }
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//! # Runtime Runtime Upgrade and Testing
|
||||
//!
|
||||
//!
|
||||
//! Notes:
|
||||
//!
|
||||
//! - Flow of things, when does `on_runtime_upgrade` get called. Link to to `Hooks` and its diagram
|
||||
//! as source of truth.
|
||||
//! - Data migration and when it is needed.
|
||||
//! - Look into the pba-lecture.
|
||||
@@ -0,0 +1,138 @@
|
||||
//! # Runtime Upgrades
|
||||
//!
|
||||
//! At their core, blockchain logic consists of
|
||||
//!
|
||||
//! 1. on-chain state and
|
||||
//! 2. a state transition function
|
||||
//!
|
||||
//! In Substrate-based blockchains, state transition functions are referred to as
|
||||
//! [runtimes](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/blockchain_state_machines/index.html).
|
||||
//!
|
||||
//! Traditionally, before Substrate, upgrading state transition functions required node
|
||||
//! operators to download new software and restart their nodes in a process called
|
||||
//! [forking](https://en.wikipedia.org/wiki/Fork_(blockchain)).
|
||||
//!
|
||||
//! Substrate-based blockchains do not require forking, and instead upgrade runtimes
|
||||
//! in a process called "Runtime Upgrades".
|
||||
//!
|
||||
//! Forkless runtime upgrades are a defining feature of the Substrate framework. Updating the
|
||||
//! runtime logic without forking the code base enables your blockchain to seemlessly evolve
|
||||
//! over time in a deterministic, rules-based manner. It also removes ambiguity for node operators
|
||||
//! and other participants in the network about what is the canonical runtime.
|
||||
//!
|
||||
//! This capability is possible due to the runtime of a blockchain existing in on-chain storage.
|
||||
//!
|
||||
//! ## Performing a Runtime Upgrade
|
||||
//!
|
||||
//! To upgrade a runtime, an [`Origin`](frame_system::RawOrigin) with the necesarry permissions
|
||||
//! (usually via governance) changes the `:code` storage. Usually, this is performed via a call to
|
||||
//! [`set_code`] (or [`set_code_without_checks`]) with the desired new runtime blob, scheduled
|
||||
//! using [`pallet_scheduler`].
|
||||
//!
|
||||
//! Prior to building the new runtime, don't forget to update the
|
||||
//! [`RuntimeVersion`](sp_version::RuntimeVersion).
|
||||
//!
|
||||
//! # Migrations
|
||||
//!
|
||||
//! It is often desirable to define logic to execute immediately after runtime upgrades (see
|
||||
//! [this diagram](frame::traits::Hooks)).
|
||||
//!
|
||||
//! Self-contained pieces of logic that execute after a runtime upgrade are called "Migrations".
|
||||
//!
|
||||
//! The typical use case of a migration is to 'migrate' pallet storage from one layout to another,
|
||||
//! for example when the encoding of a storage item is changed. However, they can also execute
|
||||
//! arbitary logic such as:
|
||||
//!
|
||||
//! - Calling arbitrary pallet methods
|
||||
//! - Mutating arbitrary on-chain state
|
||||
//! - Cleaning up some old storage items that are no longer needed
|
||||
//!
|
||||
//! ## Single Block Migrations
|
||||
//!
|
||||
//! - Execute immediately and entirely at the beginning of the block following
|
||||
//! a runtime upgrade.
|
||||
//! - Are suitable for migrations which are guaranteed to not exceed the block weight.
|
||||
//! - Are simply implementations of [`OnRuntimeUpgrade`].
|
||||
//!
|
||||
//! To learn best practices for writing single block pallet storage migrations, see the
|
||||
//! [Single Block Migration Example Pallet](pallet_example_single_block_migrations).
|
||||
//!
|
||||
//! ### Scheduling the Single Block Migrations to Run Next Runtime Upgrade
|
||||
//!
|
||||
//! Schedule migrations to run next runtime upgrade passing them as a generic parameter to your
|
||||
//! [`Executive`](frame_executive) pallet:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! /// Tuple of migrations (structs that implement `OnRuntimeUpgrade`)
|
||||
//! type Migrations = (
|
||||
//! pallet_example_storage_migration::migrations::v1::versioned::MigrateV0ToV1,
|
||||
//! MyCustomMigration,
|
||||
//! // ...more migrations here
|
||||
//! );
|
||||
//! pub type Executive = frame_executive::Executive<
|
||||
//! Runtime,
|
||||
//! Block,
|
||||
//! frame_system::ChainContext<Runtime>,
|
||||
//! Runtime,
|
||||
//! AllPalletsWithSystem,
|
||||
//! Migrations, // <-- pass your migrations to Executive here
|
||||
//! >;
|
||||
//! ```
|
||||
//!
|
||||
//! ### Ensuring Single Block Migration Safety
|
||||
//!
|
||||
//! "My migration unit tests pass, so it should be safe to deploy right?"
|
||||
//!
|
||||
//! No! Unit tests execute the migration in a very simple test environment, and cannot account
|
||||
//! for the complexities of a real runtime or real on-chain state.
|
||||
//!
|
||||
//! Prior to deploying migrations, it is critical to perform additional checks to ensure that when
|
||||
//! run in our real runtime they will not brick the chain due to:
|
||||
//! - Panicing
|
||||
//! - Touching too many storage keys and resulting in an excessively large PoV
|
||||
//! - Taking too long to execute
|
||||
//!
|
||||
//! [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) has a sub-command
|
||||
//! [`on-runtime-upgrade`](https://paritytech.github.io/try-runtime-cli/try_runtime_core/commands/enum.Action.html#variant.OnRuntimeUpgrade)
|
||||
//! which is designed to help with exactly this.
|
||||
//!
|
||||
//! Developers MUST run this command before deploying migrations to ensure they will not
|
||||
//! inadvertently result in a bricked chain.
|
||||
//!
|
||||
//! It is recommended to run as part of your CI pipeline. See the
|
||||
//! [polkadot-sdk check-runtime-migration job](https://github.com/paritytech/polkadot-sdk/blob/4a293bc5a25be637c06ce950a34490706597615b/.gitlab/pipeline/check.yml#L103-L124)
|
||||
//! for an example of how to configure this.
|
||||
//!
|
||||
//! ### Note on the Manipulability of PoV Size and Execution Time
|
||||
//!
|
||||
//! While [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli) can help ensure with
|
||||
//! very high certainty that a migration will succeed given **existing** on-chain state, it cannot
|
||||
//! prevent a malicious actor from manipulating state in a way that will cause the migration to take
|
||||
//! longer or produce a PoV much larger than previously measured.
|
||||
//!
|
||||
//! Therefore, it is important to write migrations in such a way that the execution time or PoV size
|
||||
//! it adds to the block cannot be easily manipulated. e.g., do not iterate over storage that can
|
||||
//! quickly or cheaply be bloated.
|
||||
//!
|
||||
//! If writing your migration in such a way is not possible, a multi block migration should be used
|
||||
//! instead.
|
||||
//!
|
||||
//! ### Other useful tools
|
||||
//!
|
||||
//! [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) is another tool in the Substrate
|
||||
//! ecosystem which developers may find useful to use in addition to `try-runtime-cli` when testing
|
||||
//! their single block migrations.
|
||||
//!
|
||||
//! ## Multi Block Migrations
|
||||
//!
|
||||
//! Safely and easily execute long-running migrations across multiple blocks.
|
||||
//!
|
||||
//! Suitable for migrations which could use arbitrary amounts of block weight.
|
||||
//!
|
||||
//! TODO: Link to multi block migration example/s once PR is merged (<https://github.com/paritytech/polkadot-sdk/pull/2119>).
|
||||
//!
|
||||
//! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion
|
||||
//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade
|
||||
//! [`StorageVersion`]: frame_support::traits::StorageVersion
|
||||
//! [`set_code`]: frame_system::Call::set_code
|
||||
//! [`set_code_without_checks`]: frame_system::Call::set_code_without_checks
|
||||
@@ -92,9 +92,8 @@ pub mod cli;
|
||||
// TODO: @JoshOrndorff @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/54
|
||||
pub mod consensus_swapping;
|
||||
|
||||
/// Learn about all the advance ways to test your coordinate a rutnime upgrade and data migration.
|
||||
// TODO: @liamaharon https://github.com/paritytech/polkadot-sdk-docs/issues/55
|
||||
pub mod frame_runtime_migration;
|
||||
/// Learn about Runtime Upgrades and best practices for writing Migrations.
|
||||
pub mod frame_runtime_upgrades_and_migrations;
|
||||
|
||||
/// Learn about light nodes, how they function, and how Substrate-based chains come
|
||||
/// light-node-first out of the box.
|
||||
|
||||
@@ -93,7 +93,7 @@ pub(crate) fn try_upgrade_db(
|
||||
}
|
||||
|
||||
/// Try upgrading parachain's database to the next version.
|
||||
/// If successfull, it returns the current version.
|
||||
/// If successful, it returns the current version.
|
||||
pub(crate) fn try_upgrade_db_to_next_version(
|
||||
db_path: &Path,
|
||||
db_kind: DatabaseKind,
|
||||
|
||||
@@ -29,14 +29,14 @@ pub mod v1 {
|
||||
impl<T: Config> OnRuntimeUpgrade for VersionUncheckedMigrateToV1<T> {
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
ensure!(onchain_version < 1, "assigned_slots::MigrateToV1 migration can be deleted");
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
ensure!(on_chain_version < 1, "assigned_slots::MigrateToV1 migration can be deleted");
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
fn on_runtime_upgrade() -> frame_support::weights::Weight {
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
if onchain_version < 1 {
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
if on_chain_version < 1 {
|
||||
const MAX_PERMANENT_SLOTS: u32 = 100;
|
||||
const MAX_TEMPORARY_SLOTS: u32 = 100;
|
||||
|
||||
@@ -52,8 +52,8 @@ pub mod v1 {
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
ensure!(onchain_version == 1, "assigned_slots::MigrateToV1 needs to be run");
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
ensure!(on_chain_version == 1, "assigned_slots::MigrateToV1 needs to be run");
|
||||
assert_eq!(<MaxPermanentSlots<T>>::get(), 100);
|
||||
assert_eq!(<MaxTemporarySlots<T>>::get(), 100);
|
||||
Ok(())
|
||||
|
||||
@@ -107,7 +107,7 @@ type LeasePeriodOf<T> = <<T as Config>::Leaser as Leaser<BlockNumberFor<T>>>::Le
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -24,9 +24,9 @@ use frame_support::{
|
||||
pub struct MigrateToTrackInactiveV2<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToTrackInactiveV2<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
if onchain_version == 1 {
|
||||
if on_chain_version == 1 {
|
||||
let mut translated = 0u64;
|
||||
for item in Funds::<T>::iter_values() {
|
||||
let b =
|
||||
|
||||
@@ -180,7 +180,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::{ensure_root, ensure_signed, pallet_prelude::*};
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -106,7 +106,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -505,7 +505,7 @@ impl WeightInfo for TestWeightInfo {
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
///
|
||||
/// v0-v1: <https://github.com/paritytech/polkadot/pull/3575>
|
||||
/// v1-v2: <https://github.com/paritytech/polkadot/pull/4420>
|
||||
|
||||
@@ -379,7 +379,7 @@ pub mod pallet {
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -18,5 +18,5 @@
|
||||
|
||||
use frame_support::traits::StorageVersion;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
|
||||
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
|
||||
|
||||
title: Runtime Upgrade ref docs and Single Block Migration example pallet
|
||||
|
||||
doc:
|
||||
- audience: Runtime Dev
|
||||
description: |
|
||||
`frame_support::traits::GetStorageVersion::current_storage_version` has been renamed `frame_support::traits::GetStorageVersion::in_code_storage_version`.
|
||||
A simple find-replace is sufficient to handle this change.
|
||||
|
||||
crates:
|
||||
- name: "frame-support"
|
||||
|
||||
@@ -518,7 +518,7 @@ where
|
||||
runtime_code,
|
||||
ext,
|
||||
heap_alloc_strategy,
|
||||
|_, mut instance, _onchain_version, mut ext| {
|
||||
|_, mut instance, _on_chain_version, mut ext| {
|
||||
with_externalities_safe(&mut **ext, move || instance.call_export(method, data))
|
||||
},
|
||||
);
|
||||
@@ -682,18 +682,18 @@ impl<D: NativeExecutionDispatch + 'static> CodeExecutor for NativeElseWasmExecut
|
||||
runtime_code,
|
||||
ext,
|
||||
heap_alloc_strategy,
|
||||
|_, mut instance, onchain_version, mut ext| {
|
||||
let onchain_version =
|
||||
onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?;
|
||||
|_, mut instance, on_chain_version, mut ext| {
|
||||
let on_chain_version =
|
||||
on_chain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?;
|
||||
|
||||
let can_call_with =
|
||||
onchain_version.can_call_with(&self.native_version.runtime_version);
|
||||
on_chain_version.can_call_with(&self.native_version.runtime_version);
|
||||
|
||||
if use_native && can_call_with {
|
||||
tracing::trace!(
|
||||
target: "executor",
|
||||
native = %self.native_version.runtime_version,
|
||||
chain = %onchain_version,
|
||||
chain = %on_chain_version,
|
||||
"Request for native execution succeeded",
|
||||
);
|
||||
|
||||
@@ -705,7 +705,7 @@ impl<D: NativeExecutionDispatch + 'static> CodeExecutor for NativeElseWasmExecut
|
||||
tracing::trace!(
|
||||
target: "executor",
|
||||
native = %self.native_version.runtime_version,
|
||||
chain = %onchain_version,
|
||||
chain = %on_chain_version,
|
||||
"Request for native execution failed",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,19 +19,19 @@ use crate::{Config, Pallet, Weight, LOG_TARGET};
|
||||
use frame_support::{pallet_prelude::*, storage::migration, traits::OnRuntimeUpgrade};
|
||||
use log;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
|
||||
|
||||
/// Wrapper for all migrations of this pallet.
|
||||
pub fn migrate<T: Config<I>, I: 'static>() -> Weight {
|
||||
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
let mut weight: Weight = Weight::zero();
|
||||
|
||||
if onchain_version < 1 {
|
||||
if on_chain_version < 1 {
|
||||
weight = weight.saturating_add(v0_to_v1::migrate::<T, I>());
|
||||
}
|
||||
|
||||
if onchain_version < 2 {
|
||||
if on_chain_version < 2 {
|
||||
weight = weight.saturating_add(v1_to_v2::migrate::<T, I>());
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ pub mod pallet {
|
||||
};
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -67,9 +67,9 @@ pub mod v1 {
|
||||
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current_version = Pallet::<T>::current_storage_version();
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
if onchain_version == 0 && current_version == 1 {
|
||||
let in_code_version = Pallet::<T>::in_code_storage_version();
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
if on_chain_version == 0 && in_code_version == 1 {
|
||||
let mut translated = 0u64;
|
||||
Asset::<T>::translate::<
|
||||
OldAssetDetails<T::Balance, T::AccountId, DepositBalanceOf<T>>,
|
||||
@@ -78,12 +78,12 @@ pub mod v1 {
|
||||
translated.saturating_inc();
|
||||
Some(old_value.migrate_to_v1())
|
||||
});
|
||||
current_version.put::<Pallet<T>>();
|
||||
in_code_version.put::<Pallet<T>>();
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Upgraded {} pools, storage to version {:?}",
|
||||
translated,
|
||||
current_version
|
||||
in_code_version
|
||||
);
|
||||
T::DbWeight::get().reads_writes(translated + 1, translated + 1)
|
||||
} else {
|
||||
@@ -116,13 +116,13 @@ pub mod v1 {
|
||||
"the asset count before and after the migration should be the same"
|
||||
);
|
||||
|
||||
let current_version = Pallet::<T>::current_storage_version();
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
let in_code_version = Pallet::<T>::in_code_storage_version();
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
frame_support::ensure!(current_version == 1, "must_upgrade");
|
||||
frame_support::ensure!(in_code_version == 1, "must_upgrade");
|
||||
ensure!(
|
||||
current_version == onchain_version,
|
||||
"after migration, the current_version and onchain_version should be the same"
|
||||
in_code_version == on_chain_version,
|
||||
"after migration, the in_code_version and on_chain_version should be the same"
|
||||
);
|
||||
|
||||
Asset::<T>::iter().try_for_each(|(_id, asset)| -> Result<(), TryRuntimeError> {
|
||||
|
||||
@@ -320,7 +320,7 @@ pub mod pallet {
|
||||
type MaxFreezes: Get<u32>;
|
||||
}
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: frame_support::traits::StorageVersion =
|
||||
frame_support::traits::StorageVersion::new(1);
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ use frame_support::{
|
||||
};
|
||||
|
||||
fn migrate_v0_to_v1<T: Config<I>, I: 'static>(accounts: &[T::AccountId]) -> Weight {
|
||||
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
|
||||
if onchain_version == 0 {
|
||||
if on_chain_version == 0 {
|
||||
let total = accounts
|
||||
.iter()
|
||||
.map(|a| Pallet::<T, I>::total_balance(a))
|
||||
@@ -76,9 +76,9 @@ impl<T: Config<I>, A: Get<Vec<T::AccountId>>, I: 'static> OnRuntimeUpgrade
|
||||
pub struct ResetInactive<T, I = ()>(PhantomData<(T, I)>);
|
||||
impl<T: Config<I>, I: 'static> OnRuntimeUpgrade for ResetInactive<T, I> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
|
||||
if onchain_version == 1 {
|
||||
if on_chain_version == 1 {
|
||||
// Remove the old `StorageVersion` type.
|
||||
frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix(
|
||||
Pallet::<T, I>::name().as_bytes(),
|
||||
|
||||
@@ -176,7 +176,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -234,7 +234,7 @@ pub mod pallet {
|
||||
use frame_system::pallet_prelude::*;
|
||||
use sp_runtime::Perbill;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(15);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -263,10 +263,10 @@ impl<T: Config, const TEST_ALL_STEPS: bool> Migration<T, TEST_ALL_STEPS> {
|
||||
impl<T: Config, const TEST_ALL_STEPS: bool> OnRuntimeUpgrade for Migration<T, TEST_ALL_STEPS> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let name = <Pallet<T>>::name();
|
||||
let current_version = <Pallet<T>>::current_storage_version();
|
||||
let in_code_version = <Pallet<T>>::in_code_storage_version();
|
||||
let on_chain_version = <Pallet<T>>::on_chain_storage_version();
|
||||
|
||||
if on_chain_version == current_version {
|
||||
if on_chain_version == in_code_version {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"{name}: No Migration performed storage_version = latest_version = {:?}",
|
||||
@@ -289,7 +289,7 @@ impl<T: Config, const TEST_ALL_STEPS: bool> OnRuntimeUpgrade for Migration<T, TE
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"{name}: Upgrading storage from {on_chain_version:?} to {current_version:?}.",
|
||||
"{name}: Upgrading storage from {on_chain_version:?} to {in_code_version:?}.",
|
||||
);
|
||||
|
||||
let cursor = T::Migrations::new(on_chain_version + 1);
|
||||
@@ -309,21 +309,21 @@ impl<T: Config, const TEST_ALL_STEPS: bool> OnRuntimeUpgrade for Migration<T, TE
|
||||
// Instead, we call the migrations `pre_upgrade` and `post_upgrade` hooks when we iterate
|
||||
// over our migrations.
|
||||
let on_chain_version = <Pallet<T>>::on_chain_storage_version();
|
||||
let current_version = <Pallet<T>>::current_storage_version();
|
||||
let in_code_version = <Pallet<T>>::in_code_storage_version();
|
||||
|
||||
if on_chain_version == current_version {
|
||||
if on_chain_version == in_code_version {
|
||||
return Ok(Default::default())
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
target: LOG_TARGET,
|
||||
"Requested migration of {} from {:?}(on-chain storage version) to {:?}(current storage version)",
|
||||
<Pallet<T>>::name(), on_chain_version, current_version
|
||||
"Requested migration of {} from {:?}(on-chain storage version) to {:?}(in-code storage version)",
|
||||
<Pallet<T>>::name(), on_chain_version, in_code_version
|
||||
);
|
||||
|
||||
ensure!(
|
||||
T::Migrations::is_upgrade_supported(on_chain_version, current_version),
|
||||
"Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)"
|
||||
T::Migrations::is_upgrade_supported(on_chain_version, in_code_version),
|
||||
"Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, in-code storage version)"
|
||||
);
|
||||
|
||||
Ok(Default::default())
|
||||
@@ -421,7 +421,7 @@ impl<T: Config, const TEST_ALL_STEPS: bool> Migration<T, TEST_ALL_STEPS> {
|
||||
},
|
||||
StepResult::Completed { steps_done } => {
|
||||
in_progress_version.put::<Pallet<T>>();
|
||||
if <Pallet<T>>::current_storage_version() != in_progress_version {
|
||||
if <Pallet<T>>::in_code_storage_version() != in_progress_version {
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"{name}: Next migration is {:?},",
|
||||
|
||||
@@ -28,7 +28,7 @@ use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound, Identity};
|
||||
use sp_runtime::TryRuntimeError;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
mod old {
|
||||
mod v8 {
|
||||
use super::*;
|
||||
|
||||
#[derive(Encode, Decode)]
|
||||
@@ -50,14 +50,14 @@ mod old {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub fn store_old_dummy_code<T: Config>(len: usize) {
|
||||
use sp_runtime::traits::Hash;
|
||||
let module = old::PrefabWasmModule {
|
||||
let module = v8::PrefabWasmModule {
|
||||
instruction_weights_version: 0,
|
||||
initial: 0,
|
||||
maximum: 0,
|
||||
code: vec![42u8; len],
|
||||
};
|
||||
let hash = T::Hashing::hash(&module.code);
|
||||
old::CodeStorage::<T>::insert(hash, module);
|
||||
v8::CodeStorage::<T>::insert(hash, module);
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode)]
|
||||
@@ -89,9 +89,9 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let mut iter = if let Some(last_key) = self.last_code_hash.take() {
|
||||
old::CodeStorage::<T>::iter_from(old::CodeStorage::<T>::hashed_key_for(last_key))
|
||||
v8::CodeStorage::<T>::iter_from(v8::CodeStorage::<T>::hashed_key_for(last_key))
|
||||
} else {
|
||||
old::CodeStorage::<T>::iter()
|
||||
v8::CodeStorage::<T>::iter()
|
||||
};
|
||||
|
||||
if let Some((key, old)) = iter.next() {
|
||||
@@ -115,7 +115,7 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let sample: Vec<_> = old::CodeStorage::<T>::iter().take(100).collect();
|
||||
let sample: Vec<_> = v8::CodeStorage::<T>::iter().take(100).collect();
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Taking sample of {} contract codes", sample.len());
|
||||
Ok(sample.encode())
|
||||
@@ -123,7 +123,7 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
|
||||
let sample = <Vec<(CodeHash<T>, old::PrefabWasmModule)> as Decode>::decode(&mut &state[..])
|
||||
let sample = <Vec<(CodeHash<T>, v8::PrefabWasmModule)> as Decode>::decode(&mut &state[..])
|
||||
.expect("pre_upgrade_step provides a valid state; qed");
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Validating sample of {} contract codes", sample.len());
|
||||
|
||||
@@ -47,7 +47,7 @@ use sp_runtime::{
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
mod old {
|
||||
mod v9 {
|
||||
use super::*;
|
||||
|
||||
pub type BalanceOf<T, OldCurrency> = <OldCurrency as frame_support::traits::Currency<
|
||||
@@ -85,7 +85,7 @@ pub fn store_old_contract_info<T: Config, OldCurrency>(
|
||||
) where
|
||||
OldCurrency: ReservableCurrency<<T as frame_system::Config>::AccountId> + 'static,
|
||||
{
|
||||
let info = old::ContractInfo {
|
||||
let info = v9::ContractInfo {
|
||||
trie_id: info.trie_id,
|
||||
code_hash: info.code_hash,
|
||||
storage_bytes: Default::default(),
|
||||
@@ -94,7 +94,7 @@ pub fn store_old_contract_info<T: Config, OldCurrency>(
|
||||
storage_item_deposit: Default::default(),
|
||||
storage_base_deposit: Default::default(),
|
||||
};
|
||||
old::ContractInfoOf::<T, OldCurrency>::insert(account, info);
|
||||
v9::ContractInfoOf::<T, OldCurrency>::insert(account, info);
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen)]
|
||||
@@ -120,9 +120,9 @@ where
|
||||
pub code_hash: CodeHash<T>,
|
||||
storage_bytes: u32,
|
||||
storage_items: u32,
|
||||
pub storage_byte_deposit: old::BalanceOf<T, OldCurrency>,
|
||||
storage_item_deposit: old::BalanceOf<T, OldCurrency>,
|
||||
storage_base_deposit: old::BalanceOf<T, OldCurrency>,
|
||||
pub storage_byte_deposit: v9::BalanceOf<T, OldCurrency>,
|
||||
storage_item_deposit: v9::BalanceOf<T, OldCurrency>,
|
||||
storage_base_deposit: v9::BalanceOf<T, OldCurrency>,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
|
||||
@@ -152,7 +152,7 @@ fn deposit_address<T: Config>(
|
||||
impl<T: Config, OldCurrency: 'static> MigrationStep for Migration<T, OldCurrency>
|
||||
where
|
||||
OldCurrency: ReservableCurrency<<T as frame_system::Config>::AccountId>
|
||||
+ Inspect<<T as frame_system::Config>::AccountId, Balance = old::BalanceOf<T, OldCurrency>>,
|
||||
+ Inspect<<T as frame_system::Config>::AccountId, Balance = v9::BalanceOf<T, OldCurrency>>,
|
||||
{
|
||||
const VERSION: u16 = 10;
|
||||
|
||||
@@ -162,11 +162,11 @@ where
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let mut iter = if let Some(last_account) = self.last_account.take() {
|
||||
old::ContractInfoOf::<T, OldCurrency>::iter_from(
|
||||
old::ContractInfoOf::<T, OldCurrency>::hashed_key_for(last_account),
|
||||
v9::ContractInfoOf::<T, OldCurrency>::iter_from(
|
||||
v9::ContractInfoOf::<T, OldCurrency>::hashed_key_for(last_account),
|
||||
)
|
||||
} else {
|
||||
old::ContractInfoOf::<T, OldCurrency>::iter()
|
||||
v9::ContractInfoOf::<T, OldCurrency>::iter()
|
||||
};
|
||||
|
||||
if let Some((account, contract)) = iter.next() {
|
||||
@@ -276,7 +276,7 @@ where
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let sample: Vec<_> = old::ContractInfoOf::<T, OldCurrency>::iter().take(10).collect();
|
||||
let sample: Vec<_> = v9::ContractInfoOf::<T, OldCurrency>::iter().take(10).collect();
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Taking sample of {} contracts", sample.len());
|
||||
Ok(sample.encode())
|
||||
@@ -284,7 +284,7 @@ where
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
|
||||
let sample = <Vec<(T::AccountId, old::ContractInfo<T, OldCurrency>)> as Decode>::decode(
|
||||
let sample = <Vec<(T::AccountId, v9::ContractInfo<T, OldCurrency>)> as Decode>::decode(
|
||||
&mut &state[..],
|
||||
)
|
||||
.expect("pre_upgrade_step provides a valid state; qed");
|
||||
|
||||
@@ -29,7 +29,7 @@ use sp_runtime::TryRuntimeError;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound};
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
mod old {
|
||||
mod v10 {
|
||||
use super::*;
|
||||
|
||||
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
@@ -51,11 +51,11 @@ pub struct DeletionQueueManager<T: Config> {
|
||||
|
||||
#[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime"))]
|
||||
pub fn fill_old_queue<T: Config>(len: usize) {
|
||||
let queue: Vec<old::DeletedContract> =
|
||||
core::iter::repeat_with(|| old::DeletedContract { trie_id: Default::default() })
|
||||
let queue: Vec<v10::DeletedContract> =
|
||||
core::iter::repeat_with(|| v10::DeletedContract { trie_id: Default::default() })
|
||||
.take(len)
|
||||
.collect();
|
||||
old::DeletionQueue::<T>::set(Some(queue));
|
||||
v10::DeletionQueue::<T>::set(Some(queue));
|
||||
}
|
||||
|
||||
#[storage_alias]
|
||||
@@ -80,7 +80,7 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
}
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let Some(old_queue) = old::DeletionQueue::<T>::take() else {
|
||||
let Some(old_queue) = v10::DeletionQueue::<T>::take() else {
|
||||
return (IsFinished::Yes, Weight::zero())
|
||||
};
|
||||
let len = old_queue.len();
|
||||
@@ -106,7 +106,7 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let old_queue = old::DeletionQueue::<T>::take().unwrap_or_default();
|
||||
let old_queue = v10::DeletionQueue::<T>::take().unwrap_or_default();
|
||||
|
||||
if old_queue.is_empty() {
|
||||
let len = 10u32;
|
||||
|
||||
@@ -34,7 +34,7 @@ use sp_runtime::TryRuntimeError;
|
||||
use sp_runtime::{traits::Zero, FixedPointNumber, FixedU128, Saturating};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
mod old {
|
||||
mod v11 {
|
||||
use super::*;
|
||||
|
||||
pub type BalanceOf<T, OldCurrency> = <OldCurrency as frame_support::traits::Currency<
|
||||
@@ -87,7 +87,7 @@ where
|
||||
{
|
||||
owner: AccountIdOf<T>,
|
||||
#[codec(compact)]
|
||||
deposit: old::BalanceOf<T, OldCurrency>,
|
||||
deposit: v11::BalanceOf<T, OldCurrency>,
|
||||
#[codec(compact)]
|
||||
refcount: u64,
|
||||
determinism: Determinism,
|
||||
@@ -112,17 +112,17 @@ where
|
||||
let hash = T::Hashing::hash(&code);
|
||||
PristineCode::<T>::insert(hash, code.clone());
|
||||
|
||||
let module = old::PrefabWasmModule {
|
||||
let module = v11::PrefabWasmModule {
|
||||
instruction_weights_version: Default::default(),
|
||||
initial: Default::default(),
|
||||
maximum: Default::default(),
|
||||
code,
|
||||
determinism: Determinism::Enforced,
|
||||
};
|
||||
old::CodeStorage::<T>::insert(hash, module);
|
||||
v11::CodeStorage::<T>::insert(hash, module);
|
||||
|
||||
let info = old::OwnerInfo { owner: account, deposit: u32::MAX.into(), refcount: u64::MAX };
|
||||
old::OwnerInfoOf::<T, OldCurrency>::insert(hash, info);
|
||||
let info = v11::OwnerInfo { owner: account, deposit: u32::MAX.into(), refcount: u64::MAX };
|
||||
v11::OwnerInfoOf::<T, OldCurrency>::insert(hash, info);
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
|
||||
@@ -148,16 +148,16 @@ where
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let mut iter = if let Some(last_key) = self.last_code_hash.take() {
|
||||
old::OwnerInfoOf::<T, OldCurrency>::iter_from(
|
||||
old::OwnerInfoOf::<T, OldCurrency>::hashed_key_for(last_key),
|
||||
v11::OwnerInfoOf::<T, OldCurrency>::iter_from(
|
||||
v11::OwnerInfoOf::<T, OldCurrency>::hashed_key_for(last_key),
|
||||
)
|
||||
} else {
|
||||
old::OwnerInfoOf::<T, OldCurrency>::iter()
|
||||
v11::OwnerInfoOf::<T, OldCurrency>::iter()
|
||||
};
|
||||
if let Some((hash, old_info)) = iter.next() {
|
||||
log::debug!(target: LOG_TARGET, "Migrating OwnerInfo for code_hash {:?}", hash);
|
||||
|
||||
let module = old::CodeStorage::<T>::take(hash)
|
||||
let module = v11::CodeStorage::<T>::take(hash)
|
||||
.expect(format!("No PrefabWasmModule found for code_hash: {:?}", hash).as_str());
|
||||
|
||||
let code_len = module.code.len();
|
||||
@@ -184,7 +184,7 @@ where
|
||||
let bytes_before = module
|
||||
.encoded_size()
|
||||
.saturating_add(code_len)
|
||||
.saturating_add(old::OwnerInfo::<T, OldCurrency>::max_encoded_len())
|
||||
.saturating_add(v11::OwnerInfo::<T, OldCurrency>::max_encoded_len())
|
||||
as u32;
|
||||
let items_before = 3u32;
|
||||
let deposit_expected_before = price_per_byte
|
||||
@@ -241,10 +241,10 @@ where
|
||||
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let len = 100;
|
||||
log::debug!(target: LOG_TARGET, "Taking sample of {} OwnerInfo(s)", len);
|
||||
let sample: Vec<_> = old::OwnerInfoOf::<T, OldCurrency>::iter()
|
||||
let sample: Vec<_> = v11::OwnerInfoOf::<T, OldCurrency>::iter()
|
||||
.take(len)
|
||||
.map(|(k, v)| {
|
||||
let module = old::CodeStorage::<T>::get(k)
|
||||
let module = v11::CodeStorage::<T>::get(k)
|
||||
.expect("No PrefabWasmModule found for code_hash: {:?}");
|
||||
let info: CodeInfo<T, OldCurrency> = CodeInfo {
|
||||
determinism: module.determinism,
|
||||
@@ -258,9 +258,9 @@ where
|
||||
.collect();
|
||||
|
||||
let storage: u32 =
|
||||
old::CodeStorage::<T>::iter().map(|(_k, v)| v.encoded_size() as u32).sum();
|
||||
let mut deposit: old::BalanceOf<T, OldCurrency> = Default::default();
|
||||
old::OwnerInfoOf::<T, OldCurrency>::iter().for_each(|(_k, v)| deposit += v.deposit);
|
||||
v11::CodeStorage::<T>::iter().map(|(_k, v)| v.encoded_size() as u32).sum();
|
||||
let mut deposit: v11::BalanceOf<T, OldCurrency> = Default::default();
|
||||
v11::OwnerInfoOf::<T, OldCurrency>::iter().for_each(|(_k, v)| deposit += v.deposit);
|
||||
|
||||
Ok((sample, deposit, storage).encode())
|
||||
}
|
||||
@@ -269,7 +269,7 @@ where
|
||||
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
|
||||
let state = <(
|
||||
Vec<(CodeHash<T>, CodeInfo<T, OldCurrency>)>,
|
||||
old::BalanceOf<T, OldCurrency>,
|
||||
v11::BalanceOf<T, OldCurrency>,
|
||||
u32,
|
||||
) as Decode>::decode(&mut &state[..])
|
||||
.unwrap();
|
||||
@@ -283,7 +283,7 @@ where
|
||||
ensure!(info.refcount == old.refcount, "invalid refcount");
|
||||
}
|
||||
|
||||
if let Some((k, _)) = old::CodeStorage::<T>::iter().next() {
|
||||
if let Some((k, _)) = v11::CodeStorage::<T>::iter().next() {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"CodeStorage is still NOT empty, found code_hash: {:?}",
|
||||
@@ -292,7 +292,7 @@ where
|
||||
} else {
|
||||
log::debug!(target: LOG_TARGET, "CodeStorage is empty.");
|
||||
}
|
||||
if let Some((k, _)) = old::OwnerInfoOf::<T, OldCurrency>::iter().next() {
|
||||
if let Some((k, _)) = v11::OwnerInfoOf::<T, OldCurrency>::iter().next() {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"OwnerInfoOf is still NOT empty, found code_hash: {:?}",
|
||||
@@ -302,7 +302,7 @@ where
|
||||
log::debug!(target: LOG_TARGET, "OwnerInfoOf is empty.");
|
||||
}
|
||||
|
||||
let mut deposit: old::BalanceOf<T, OldCurrency> = Default::default();
|
||||
let mut deposit: v11::BalanceOf<T, OldCurrency> = Default::default();
|
||||
let mut items = 0u32;
|
||||
let mut storage_info = 0u32;
|
||||
CodeInfoOf::<T, OldCurrency>::iter().for_each(|(_k, v)| {
|
||||
|
||||
@@ -28,7 +28,7 @@ use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound};
|
||||
use sp_runtime::BoundedBTreeMap;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
mod old {
|
||||
mod v12 {
|
||||
use super::*;
|
||||
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
@@ -59,7 +59,7 @@ pub fn store_old_contract_info<T: Config>(account: T::AccountId, info: crate::Co
|
||||
let entropy = (b"contract_depo_v1", account.clone()).using_encoded(T::Hashing::hash);
|
||||
let deposit_account = Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
|
||||
.expect("infinite length input; no invalid inputs for type; qed");
|
||||
let info = old::ContractInfo {
|
||||
let info = v12::ContractInfo {
|
||||
trie_id: info.trie_id.clone(),
|
||||
deposit_account,
|
||||
code_hash: info.code_hash,
|
||||
@@ -69,7 +69,7 @@ pub fn store_old_contract_info<T: Config>(account: T::AccountId, info: crate::Co
|
||||
storage_item_deposit: Default::default(),
|
||||
storage_base_deposit: Default::default(),
|
||||
};
|
||||
old::ContractInfoOf::<T>::insert(account, info);
|
||||
v12::ContractInfoOf::<T>::insert(account, info);
|
||||
}
|
||||
|
||||
#[storage_alias]
|
||||
@@ -104,11 +104,11 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let mut iter = if let Some(last_account) = self.last_account.take() {
|
||||
old::ContractInfoOf::<T>::iter_from(old::ContractInfoOf::<T>::hashed_key_for(
|
||||
v12::ContractInfoOf::<T>::iter_from(v12::ContractInfoOf::<T>::hashed_key_for(
|
||||
last_account,
|
||||
))
|
||||
} else {
|
||||
old::ContractInfoOf::<T>::iter()
|
||||
v12::ContractInfoOf::<T>::iter()
|
||||
};
|
||||
|
||||
if let Some((key, old)) = iter.next() {
|
||||
|
||||
@@ -44,7 +44,7 @@ use sp_runtime::{traits::Zero, Saturating};
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use sp_std::collections::btree_map::BTreeMap;
|
||||
|
||||
mod old {
|
||||
mod v13 {
|
||||
use super::*;
|
||||
|
||||
pub type BalanceOf<T, OldCurrency> = <OldCurrency as frame_support::traits::Currency<
|
||||
@@ -61,7 +61,7 @@ mod old {
|
||||
{
|
||||
pub owner: AccountIdOf<T>,
|
||||
#[codec(compact)]
|
||||
pub deposit: old::BalanceOf<T, OldCurrency>,
|
||||
pub deposit: v13::BalanceOf<T, OldCurrency>,
|
||||
#[codec(compact)]
|
||||
pub refcount: u64,
|
||||
pub determinism: Determinism,
|
||||
@@ -86,14 +86,14 @@ where
|
||||
let code = vec![42u8; len as usize];
|
||||
let hash = T::Hashing::hash(&code);
|
||||
|
||||
let info = old::CodeInfo {
|
||||
let info = v13::CodeInfo {
|
||||
owner: account,
|
||||
deposit: 10_000u32.into(),
|
||||
refcount: u64::MAX,
|
||||
determinism: Determinism::Enforced,
|
||||
code_len: len,
|
||||
};
|
||||
old::CodeInfoOf::<T, OldCurrency>::insert(hash, info);
|
||||
v13::CodeInfoOf::<T, OldCurrency>::insert(hash, info);
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
@@ -105,9 +105,9 @@ where
|
||||
OldCurrency: ReservableCurrency<<T as frame_system::Config>::AccountId>,
|
||||
{
|
||||
/// Total reserved balance as code upload deposit for the owner.
|
||||
reserved: old::BalanceOf<T, OldCurrency>,
|
||||
reserved: v13::BalanceOf<T, OldCurrency>,
|
||||
/// Total balance of the owner.
|
||||
total: old::BalanceOf<T, OldCurrency>,
|
||||
total: v13::BalanceOf<T, OldCurrency>,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
|
||||
@@ -134,11 +134,11 @@ where
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let mut iter = if let Some(last_hash) = self.last_code_hash.take() {
|
||||
old::CodeInfoOf::<T, OldCurrency>::iter_from(
|
||||
old::CodeInfoOf::<T, OldCurrency>::hashed_key_for(last_hash),
|
||||
v13::CodeInfoOf::<T, OldCurrency>::iter_from(
|
||||
v13::CodeInfoOf::<T, OldCurrency>::hashed_key_for(last_hash),
|
||||
)
|
||||
} else {
|
||||
old::CodeInfoOf::<T, OldCurrency>::iter()
|
||||
v13::CodeInfoOf::<T, OldCurrency>::iter()
|
||||
};
|
||||
|
||||
if let Some((hash, code_info)) = iter.next() {
|
||||
@@ -194,7 +194,7 @@ where
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let info: Vec<_> = old::CodeInfoOf::<T, OldCurrency>::iter().collect();
|
||||
let info: Vec<_> = v13::CodeInfoOf::<T, OldCurrency>::iter().collect();
|
||||
|
||||
let mut owner_balance_allocation =
|
||||
BTreeMap::<AccountIdOf<T>, BalanceAllocation<T, OldCurrency>>::new();
|
||||
|
||||
@@ -46,7 +46,7 @@ use sp_runtime::{traits::Zero, Saturating};
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
mod old {
|
||||
mod v14 {
|
||||
use super::*;
|
||||
|
||||
#[derive(
|
||||
@@ -81,7 +81,7 @@ pub fn store_old_contract_info<T: Config>(account: T::AccountId, info: crate::Co
|
||||
let entropy = (b"contract_depo_v1", account.clone()).using_encoded(T::Hashing::hash);
|
||||
let deposit_account = Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
|
||||
.expect("infinite length input; no invalid inputs for type; qed");
|
||||
let info = old::ContractInfo {
|
||||
let info = v14::ContractInfo {
|
||||
trie_id: info.trie_id.clone(),
|
||||
deposit_account,
|
||||
code_hash: info.code_hash,
|
||||
@@ -92,7 +92,7 @@ pub fn store_old_contract_info<T: Config>(account: T::AccountId, info: crate::Co
|
||||
storage_base_deposit: info.storage_base_deposit(),
|
||||
delegate_dependencies: info.delegate_dependencies().clone(),
|
||||
};
|
||||
old::ContractInfoOf::<T>::insert(account, info);
|
||||
v14::ContractInfoOf::<T>::insert(account, info);
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, CloneNoBound, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
|
||||
@@ -127,11 +127,11 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
fn step(&mut self) -> (IsFinished, Weight) {
|
||||
let mut iter = if let Some(last_account) = self.last_account.take() {
|
||||
old::ContractInfoOf::<T>::iter_from(old::ContractInfoOf::<T>::hashed_key_for(
|
||||
v14::ContractInfoOf::<T>::iter_from(v14::ContractInfoOf::<T>::hashed_key_for(
|
||||
last_account,
|
||||
))
|
||||
} else {
|
||||
old::ContractInfoOf::<T>::iter()
|
||||
v14::ContractInfoOf::<T>::iter()
|
||||
};
|
||||
|
||||
if let Some((account, old_contract)) = iter.next() {
|
||||
@@ -243,11 +243,11 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let sample: Vec<_> = old::ContractInfoOf::<T>::iter().take(100).collect();
|
||||
let sample: Vec<_> = v14::ContractInfoOf::<T>::iter().take(100).collect();
|
||||
|
||||
log::debug!(target: LOG_TARGET, "Taking sample of {} contracts", sample.len());
|
||||
|
||||
let state: Vec<(T::AccountId, old::ContractInfo<T>, BalanceOf<T>, BalanceOf<T>)> = sample
|
||||
let state: Vec<(T::AccountId, v14::ContractInfo<T>, BalanceOf<T>, BalanceOf<T>)> = sample
|
||||
.iter()
|
||||
.map(|(account, contract)| {
|
||||
(
|
||||
@@ -265,7 +265,7 @@ impl<T: Config> MigrationStep for Migration<T> {
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
|
||||
let sample =
|
||||
<Vec<(T::AccountId, old::ContractInfo<T>, BalanceOf<T>, BalanceOf<T>)> as Decode>::decode(
|
||||
<Vec<(T::AccountId, v14::ContractInfo<T>, BalanceOf<T>, BalanceOf<T>)> as Decode>::decode(
|
||||
&mut &state[..],
|
||||
)
|
||||
.expect("pre_upgrade_step provides a valid state; qed");
|
||||
|
||||
@@ -211,7 +211,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -1343,7 +1343,7 @@ pub mod pallet {
|
||||
#[pallet::getter(fn minimum_untrusted_score)]
|
||||
pub type MinimumUntrustedScore<T: Config> = StorageValue<_, ElectionScore>;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
///
|
||||
/// v1: https://github.com/paritytech/substrate/pull/12237/
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
@@ -27,12 +27,12 @@ pub mod v1 {
|
||||
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
|
||||
@@ -188,7 +188,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -23,6 +23,7 @@ pallet-example-frame-crate = { path = "frame-crate", default-features = false }
|
||||
pallet-example-kitchensink = { path = "kitchensink", default-features = false }
|
||||
pallet-example-offchain-worker = { path = "offchain-worker", default-features = false }
|
||||
pallet-example-split = { path = "split", default-features = false }
|
||||
pallet-example-single-block-migrations = { path = "single-block-migrations", default-features = false }
|
||||
pallet-example-tasks = { path = "tasks", default-features = false }
|
||||
|
||||
[features]
|
||||
@@ -34,6 +35,7 @@ std = [
|
||||
"pallet-example-frame-crate/std",
|
||||
"pallet-example-kitchensink/std",
|
||||
"pallet-example-offchain-worker/std",
|
||||
"pallet-example-single-block-migrations/std",
|
||||
"pallet-example-split/std",
|
||||
"pallet-example-tasks/std",
|
||||
]
|
||||
@@ -43,6 +45,7 @@ try-runtime = [
|
||||
"pallet-example-basic/try-runtime",
|
||||
"pallet-example-kitchensink/try-runtime",
|
||||
"pallet-example-offchain-worker/try-runtime",
|
||||
"pallet-example-single-block-migrations/try-runtime",
|
||||
"pallet-example-split/try-runtime",
|
||||
"pallet-example-tasks/try-runtime",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
[package]
|
||||
name = "pallet-example-single-block-migrations"
|
||||
version = "0.0.1"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "MIT-0"
|
||||
homepage = "https://substrate.io"
|
||||
repository.workspace = true
|
||||
description = "FRAME example pallet demonstrating best-practices for writing storage migrations."
|
||||
publish = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
docify = { version = "0.2.3", default-features = false }
|
||||
log = { version = "0.4.20", default-features = false }
|
||||
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
|
||||
frame-support = { path = "../../support", default-features = false }
|
||||
frame-executive = { path = "../../executive", default-features = false }
|
||||
frame-system = { path = "../../system", default-features = false }
|
||||
frame-try-runtime = { path = "../../try-runtime", default-features = false, optional = true }
|
||||
pallet-balances = { path = "../../balances", default-features = false }
|
||||
sp-std = { path = "../../../primitives/std", default-features = false }
|
||||
sp-runtime = { path = "../../../primitives/runtime", default-features = false }
|
||||
sp-core = { path = "../../../primitives/core", default-features = false }
|
||||
sp-io = { path = "../../../primitives/io", default-features = false }
|
||||
sp-version = { path = "../../../primitives/version", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"frame-executive/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"frame-try-runtime/std",
|
||||
"log/std",
|
||||
"pallet-balances/std",
|
||||
"scale-info/std",
|
||||
"sp-core/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
"sp-version/std",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame-system/runtime-benchmarks",
|
||||
"pallet-balances/runtime-benchmarks",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-executive/try-runtime",
|
||||
"frame-support/try-runtime",
|
||||
"frame-system/try-runtime",
|
||||
"frame-try-runtime/try-runtime",
|
||||
"pallet-balances/try-runtime",
|
||||
"sp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,213 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Single Block Migration Example Pallet
|
||||
//!
|
||||
//! An example pallet demonstrating best-practices for writing single-block migrations in the
|
||||
//! context of upgrading pallet storage.
|
||||
//!
|
||||
//! ## Forwarning
|
||||
//!
|
||||
//! Single block migrations **MUST** execute in a single block, therefore when executed on a
|
||||
//! parachain are only appropriate when guaranteed to not exceed block weight limits. If a
|
||||
//! parachain submits a block that exceeds the block weight limit it will **brick the chain**!
|
||||
//!
|
||||
//! If weight is a concern or you are not sure which type of migration to use, you should probably
|
||||
//! use a multi-block migration.
|
||||
//!
|
||||
//! TODO: Link above to multi-block migration example.
|
||||
//!
|
||||
//! ## Pallet Overview
|
||||
//!
|
||||
//! This example pallet contains a single storage item [`Value`](pallet::Value), which may be set by
|
||||
//! any signed origin by calling the [`set_value`](crate::Call::set_value) extrinsic.
|
||||
//!
|
||||
//! For the purposes of this exercise, we imagine that in [`StorageVersion`] V0 of this pallet
|
||||
//! [`Value`](pallet::Value) is a `u32`, and this what is currently stored on-chain.
|
||||
//!
|
||||
//! ```ignore
|
||||
//! // (Old) Storage Version V0 representation of `Value`
|
||||
//! #[pallet::storage]
|
||||
//! pub type Value<T: Config> = StorageValue<_, u32>;
|
||||
//! ```
|
||||
//!
|
||||
//! In [`StorageVersion`] V1 of the pallet a new struct [`CurrentAndPreviousValue`] is introduced:
|
||||
#![doc = docify::embed!("src/lib.rs", CurrentAndPreviousValue)]
|
||||
//! and [`Value`](pallet::Value) is updated to store this new struct instead of a `u32`:
|
||||
#![doc = docify::embed!("src/lib.rs", Value)]
|
||||
//!
|
||||
//! In StorageVersion V1 of the pallet when [`set_value`](crate::Call::set_value) is called, the
|
||||
//! new value is stored in the `current` field of [`CurrentAndPreviousValue`], and the previous
|
||||
//! value (if it exists) is stored in the `previous` field.
|
||||
#![doc = docify::embed!("src/lib.rs", pallet_calls)]
|
||||
//!
|
||||
//! ## Why a migration is necessary
|
||||
//!
|
||||
//! Without a migration, there will be a discrepancy between the on-chain storage for [`Value`] (in
|
||||
//! V0 it is a `u32`) and the current storage for [`Value`] (in V1 it was changed to a
|
||||
//! [`CurrentAndPreviousValue`] struct).
|
||||
//!
|
||||
//! The on-chain storage for [`Value`] would be a `u32` but the runtime would try to read it as a
|
||||
//! [`CurrentAndPreviousValue`]. This would result in unacceptable undefined behavior.
|
||||
//!
|
||||
//! ## Adding a migration module
|
||||
//!
|
||||
//! Writing a pallets migrations in a seperate module is strongly recommended.
|
||||
//!
|
||||
//! Here's how the migration module is defined for this pallet:
|
||||
//!
|
||||
//! ```text
|
||||
//! substrate/frame/examples/single-block-migrations/src/
|
||||
//! ├── lib.rs <-- pallet definition
|
||||
//! ├── Cargo.toml <-- pallet manifest
|
||||
//! └── migrations/
|
||||
//! ├── mod.rs <-- migrations module definition
|
||||
//! └── v1.rs <-- migration logic for the V0 to V1 transition
|
||||
//! ```
|
||||
//!
|
||||
//! This structure allows keeping migration logic separate from the pallet logic and
|
||||
//! easily adding new migrations in the future.
|
||||
//!
|
||||
//! ## Writing the Migration
|
||||
//!
|
||||
//! All code related to the migration can be found under
|
||||
//! [`v1.rs`](migrations::v1).
|
||||
//!
|
||||
//! See the migration source code for detailed comments.
|
||||
//!
|
||||
//! To keep the migration logic organised, it is split across additional modules:
|
||||
//!
|
||||
//! ### `mod v0`
|
||||
//!
|
||||
//! Here we define a [`storage_alias`](frame_support::storage_alias) for the old v0 [`Value`]
|
||||
//! format.
|
||||
//!
|
||||
//! This allows reading the old v0 value from storage during the migration.
|
||||
//!
|
||||
//! ### `mod version_unchecked`
|
||||
//!
|
||||
//! Here we define our raw migration logic,
|
||||
//! `version_unchecked::MigrateV0ToV1` which implements the [`OnRuntimeUpgrade`] trait.
|
||||
//!
|
||||
//! Importantly, it is kept in a private module so that it cannot be accidentally used in a runtime.
|
||||
//!
|
||||
//! Private modules cannot be referenced in docs, so please read the code directly.
|
||||
//!
|
||||
//! #### Standalone Struct or Pallet Hook?
|
||||
//!
|
||||
//! Note that the storage migration logic is attached to a standalone struct implementing
|
||||
//! [`OnRuntimeUpgrade`], rather than implementing the
|
||||
//! [`Hooks::on_runtime_upgrade`](frame_support::traits::Hooks::on_runtime_upgrade) hook directly on
|
||||
//! the pallet. The pallet hook is better suited for special types of logic that need to execute on
|
||||
//! every runtime upgrade, but not so much for one-off storage migrations.
|
||||
//!
|
||||
//! ### `pub mod versioned`
|
||||
//!
|
||||
//! Here, `version_unchecked::MigrateV0ToV1` is wrapped in a
|
||||
//! [`VersionedMigration`] to define
|
||||
//! [`versioned::MigrateV0ToV1`](crate::migrations::v1::versioned::MigrateV0ToV1), which may be used
|
||||
//! in runtimes.
|
||||
//!
|
||||
//! Using [`VersionedMigration`] ensures that
|
||||
//! - The migration only runs once when the on-chain storage version is `0`
|
||||
//! - The on-chain storage version is updated to `1` after the migration executes
|
||||
//! - Reads and writes from checking and setting the on-chain storage version are accounted for in
|
||||
//! the final [`Weight`](frame_support::weights::Weight)
|
||||
//!
|
||||
//! This is the only public module exported from `v1`.
|
||||
//!
|
||||
//! ### `mod test`
|
||||
//!
|
||||
//! Here basic unit tests are defined for the migration.
|
||||
//!
|
||||
//! When writing migration tests, don't forget to check:
|
||||
//! - `on_runtime_upgrade` returns the expected weight
|
||||
//! - `post_upgrade` succeeds when given the bytes returned by `pre_upgrade`
|
||||
//! - Pallet storage is in the expected state after the migration
|
||||
//!
|
||||
//! [`VersionedMigration`]: frame_support::migrations::VersionedMigration
|
||||
//! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion
|
||||
//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade
|
||||
//! [`MigrateV0ToV1`]: crate::migrations::v1::versioned::MigrationV0ToV1
|
||||
|
||||
// We make sure this pallet uses `no_std` for compiling to Wasm.
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// allow non-camel-case names for storage version V0 value
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
// Re-export pallet items so that they can be accessed from the crate namespace.
|
||||
pub use pallet::*;
|
||||
|
||||
// Export migrations so they may be used in the runtime.
|
||||
pub mod migrations;
|
||||
#[doc(hidden)]
|
||||
mod mock;
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_support::traits::StorageVersion;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
|
||||
/// Example struct holding the most recently set [`u32`] and the
|
||||
/// second most recently set [`u32`] (if one existed).
|
||||
#[docify::export]
|
||||
#[derive(
|
||||
Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
pub struct CurrentAndPreviousValue {
|
||||
/// The most recently set value.
|
||||
pub current: u32,
|
||||
/// The previous value, if one existed.
|
||||
pub previous: Option<u32>,
|
||||
}
|
||||
|
||||
// Pallet for demonstrating storage migrations.
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// Define the current [`StorageVersion`] of the pallet.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
/// [`StorageVersion`] V1 of [`Value`].
|
||||
///
|
||||
/// Currently used.
|
||||
#[docify::export]
|
||||
#[pallet::storage]
|
||||
pub type Value<T: Config> = StorageValue<_, CurrentAndPreviousValue>;
|
||||
|
||||
#[docify::export(pallet_calls)]
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn set_value(origin: OriginFor<T>, value: u32) -> DispatchResult {
|
||||
ensure_signed(origin)?;
|
||||
|
||||
let previous = Value::<T>::get().map(|v| v.current);
|
||||
let new_struct = CurrentAndPreviousValue { current: value, previous };
|
||||
<Value<T>>::put(new_struct);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// Module containing all logic associated with the example migration from
|
||||
/// [`StorageVersion`](frame_support::traits::StorageVersion) V0 to V1.
|
||||
pub mod v1;
|
||||
@@ -0,0 +1,222 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use frame_support::{
|
||||
storage_alias,
|
||||
traits::{Get, OnRuntimeUpgrade},
|
||||
};
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
/// Collection of storage item formats from the previous storage version.
|
||||
///
|
||||
/// Required so we can read values in the v0 storage format during the migration.
|
||||
mod v0 {
|
||||
use super::*;
|
||||
|
||||
/// V0 type for [`crate::Value`].
|
||||
#[storage_alias]
|
||||
pub type Value<T: crate::Config> = StorageValue<crate::Pallet<T>, u32>;
|
||||
}
|
||||
|
||||
/// Private module containing *version unchecked* migration logic.
|
||||
///
|
||||
/// Should only be used by the [`VersionedMigration`](frame_support::migrations::VersionedMigration)
|
||||
/// type in this module to create something to export.
|
||||
///
|
||||
/// The unversioned migration should be kept private so the unversioned migration cannot
|
||||
/// accidentally be used in any runtimes.
|
||||
///
|
||||
/// For more about this pattern of keeping items private, see
|
||||
/// - <https://github.com/rust-lang/rust/issues/30905>
|
||||
/// - <https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40>
|
||||
mod version_unchecked {
|
||||
use super::*;
|
||||
|
||||
/// Implements [`OnRuntimeUpgrade`], migrating the state of this pallet from V0 to V1.
|
||||
///
|
||||
/// In V0 of the template [`crate::Value`] is just a `u32`. In V1, it has been upgraded to
|
||||
/// contain the struct [`crate::CurrentAndPreviousValue`].
|
||||
///
|
||||
/// In this migration, update the on-chain storage for the pallet to reflect the new storage
|
||||
/// layout.
|
||||
pub struct MigrateV0ToV1<T: crate::Config>(sp_std::marker::PhantomData<T>);
|
||||
|
||||
impl<T: crate::Config> OnRuntimeUpgrade for MigrateV0ToV1<T> {
|
||||
/// Return the existing [`crate::Value`] so we can check that it was correctly set in
|
||||
/// `version_unchecked::MigrateV0ToV1::post_upgrade`.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
|
||||
use codec::Encode;
|
||||
|
||||
// Access the old value using the `storage_alias` type
|
||||
let old_value = v0::Value::<T>::get();
|
||||
// Return it as an encoded `Vec<u8>`
|
||||
Ok(old_value.encode())
|
||||
}
|
||||
|
||||
/// Migrate the storage from V0 to V1.
|
||||
///
|
||||
/// - If the value doesn't exist, there is nothing to do.
|
||||
/// - If the value exists, it is read and then written back to storage inside a
|
||||
/// [`crate::CurrentAndPreviousValue`].
|
||||
fn on_runtime_upgrade() -> frame_support::weights::Weight {
|
||||
// Read the old value from storage
|
||||
if let Some(old_value) = v0::Value::<T>::take() {
|
||||
// Write the new value to storage
|
||||
let new = crate::CurrentAndPreviousValue { current: old_value, previous: None };
|
||||
crate::Value::<T>::put(new);
|
||||
// One read for the old value, one write for the new value
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
} else {
|
||||
// One read for trying to access the old value
|
||||
T::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifies the storage was migrated correctly.
|
||||
///
|
||||
/// - If there was no old value, the new value should not be set.
|
||||
/// - If there was an old value, the new value should be a
|
||||
/// [`crate::CurrentAndPreviousValue`].
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
|
||||
use codec::Decode;
|
||||
use frame_support::ensure;
|
||||
|
||||
let maybe_old_value = Option::<u32>::decode(&mut &state[..]).map_err(|_| {
|
||||
sp_runtime::TryRuntimeError::Other("Failed to decode old value from storage")
|
||||
})?;
|
||||
|
||||
match maybe_old_value {
|
||||
Some(old_value) => {
|
||||
let expected_new_value =
|
||||
crate::CurrentAndPreviousValue { current: old_value, previous: None };
|
||||
let actual_new_value = crate::Value::<T>::get();
|
||||
|
||||
ensure!(actual_new_value.is_some(), "New value not set");
|
||||
ensure!(
|
||||
actual_new_value == Some(expected_new_value),
|
||||
"New value not set correctly"
|
||||
);
|
||||
},
|
||||
None => {
|
||||
ensure!(crate::Value::<T>::get().is_none(), "New value unexpectedly set");
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Public module containing *version checked* migration logic.
|
||||
///
|
||||
/// This is the only module that should be exported from this module.
|
||||
///
|
||||
/// See [`VersionedMigration`](frame_support::migrations::VersionedMigration) docs for more about
|
||||
/// how it works.
|
||||
pub mod versioned {
|
||||
use super::*;
|
||||
|
||||
/// `version_unchecked::MigrateV0ToV1` wrapped in a
|
||||
/// [`VersionedMigration`](frame_support::migrations::VersionedMigration), which ensures that:
|
||||
/// - The migration only runs once when the on-chain storage version is 0
|
||||
/// - The on-chain storage version is updated to `1` after the migration executes
|
||||
/// - Reads/Writes from checking/settings the on-chain storage version are accounted for
|
||||
pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
|
||||
0, // The migration will only execute when the on-chain storage version is 0
|
||||
1, // The on-chain storage version will be set to 1 after the migration is complete
|
||||
version_unchecked::MigrateV0ToV1<T>,
|
||||
crate::pallet::Pallet<T>,
|
||||
<T as frame_system::Config>::DbWeight,
|
||||
>;
|
||||
}
|
||||
|
||||
/// Tests for our migration.
|
||||
///
|
||||
/// When writing migration tests, it is important to check:
|
||||
/// 1. `on_runtime_upgrade` returns the expected weight
|
||||
/// 2. `post_upgrade` succeeds when given the bytes returned by `pre_upgrade`
|
||||
/// 3. The storage is in the expected state after the migration
|
||||
#[cfg(any(all(feature = "try-runtime", test), doc))]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::mock::{new_test_ext, MockRuntime};
|
||||
use frame_support::assert_ok;
|
||||
use version_unchecked::MigrateV0ToV1;
|
||||
|
||||
#[test]
|
||||
fn handles_no_existing_value() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// By default, no value should be set. Verify this assumption.
|
||||
assert!(crate::Value::<MockRuntime>::get().is_none());
|
||||
assert!(v0::Value::<MockRuntime>::get().is_none());
|
||||
|
||||
// Get the pre_upgrade bytes
|
||||
let bytes = match MigrateV0ToV1::<MockRuntime>::pre_upgrade() {
|
||||
Ok(bytes) => bytes,
|
||||
Err(e) => panic!("pre_upgrade failed: {:?}", e),
|
||||
};
|
||||
|
||||
// Execute the migration
|
||||
let weight = MigrateV0ToV1::<MockRuntime>::on_runtime_upgrade();
|
||||
|
||||
// Verify post_upgrade succeeds
|
||||
assert_ok!(MigrateV0ToV1::<MockRuntime>::post_upgrade(bytes));
|
||||
|
||||
// The weight should be just 1 read for trying to access the old value.
|
||||
assert_eq!(weight, <MockRuntime as frame_system::Config>::DbWeight::get().reads(1));
|
||||
|
||||
// After the migration, no value should have been set.
|
||||
assert!(crate::Value::<MockRuntime>::get().is_none());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handles_existing_value() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Set up an initial value
|
||||
let initial_value = 42;
|
||||
v0::Value::<MockRuntime>::put(initial_value);
|
||||
|
||||
// Get the pre_upgrade bytes
|
||||
let bytes = match MigrateV0ToV1::<MockRuntime>::pre_upgrade() {
|
||||
Ok(bytes) => bytes,
|
||||
Err(e) => panic!("pre_upgrade failed: {:?}", e),
|
||||
};
|
||||
|
||||
// Execute the migration
|
||||
let weight = MigrateV0ToV1::<MockRuntime>::on_runtime_upgrade();
|
||||
|
||||
// Verify post_upgrade succeeds
|
||||
assert_ok!(MigrateV0ToV1::<MockRuntime>::post_upgrade(bytes));
|
||||
|
||||
// The weight used should be 1 read for the old value, and 1 write for the new
|
||||
// value.
|
||||
assert_eq!(
|
||||
weight,
|
||||
<MockRuntime as frame_system::Config>::DbWeight::get().reads_writes(1, 1)
|
||||
);
|
||||
|
||||
// After the migration, the new value should be set as the `current` value.
|
||||
let expected_new_value =
|
||||
crate::CurrentAndPreviousValue { current: initial_value, previous: None };
|
||||
assert_eq!(crate::Value::<MockRuntime>::get(), Some(expected_new_value));
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![cfg(any(all(feature = "try-runtime", test), doc))]
|
||||
|
||||
use crate::*;
|
||||
use frame_support::{derive_impl, traits::ConstU64, weights::constants::ParityDbWeight};
|
||||
|
||||
// Re-export crate as its pallet name for construct_runtime.
|
||||
use crate as pallet_example_storage_migration;
|
||||
|
||||
type Block = frame_system::mocking::MockBlock<MockRuntime>;
|
||||
|
||||
// For testing the pallet, we construct a mock runtime.
|
||||
frame_support::construct_runtime!(
|
||||
pub struct MockRuntime {
|
||||
System: frame_system::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Example: pallet_example_storage_migration::{Pallet, Call, Storage},
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
|
||||
impl frame_system::Config for MockRuntime {
|
||||
type Block = Block;
|
||||
type AccountData = pallet_balances::AccountData<u64>;
|
||||
type DbWeight = ParityDbWeight;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for MockRuntime {
|
||||
type RuntimeHoldReason = RuntimeHoldReason;
|
||||
type RuntimeFreezeReason = RuntimeFreezeReason;
|
||||
type MaxLocks = ();
|
||||
type MaxReserves = ();
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type Balance = u64;
|
||||
type DustRemoval = ();
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ExistentialDeposit = ConstU64<1>;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type FreezeIdentifier = ();
|
||||
type MaxFreezes = ();
|
||||
}
|
||||
|
||||
impl Config for MockRuntime {}
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
use sp_runtime::BuildStorage;
|
||||
|
||||
let t = RuntimeGenesisConfig { system: Default::default(), balances: Default::default() }
|
||||
.build_storage()
|
||||
.unwrap();
|
||||
t.into()
|
||||
}
|
||||
@@ -43,6 +43,9 @@
|
||||
//! - [`pallet_example_frame_crate`]: Example pallet showcasing how one can be
|
||||
//! built using only the `frame` umbrella crate.
|
||||
//!
|
||||
//! - [`pallet_example_single_block_migrations`]: An example pallet demonstrating best-practices for
|
||||
//! writing storage migrations.
|
||||
//!
|
||||
//! - [`pallet_example_tasks`]: This pallet demonstrates the use of `Tasks` to execute service work.
|
||||
//!
|
||||
//! **Tip**: Use `cargo doc --package <pallet-name> --open` to view each pallet's documentation.
|
||||
|
||||
@@ -33,12 +33,12 @@ pub mod v1 {
|
||||
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
|
||||
@@ -73,7 +73,7 @@ pub mod pallet {
|
||||
use frame_support::{dispatch::DispatchResult, pallet_prelude::*};
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -251,7 +251,7 @@ type OffchainResult<T, A> = Result<A, OffchainErr<BlockNumberFor<T>>>;
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -72,7 +72,7 @@ pub mod v1 {
|
||||
if StorageVersion::get::<Pallet<T>>() != 0 {
|
||||
log::warn!(
|
||||
target: TARGET,
|
||||
"Skipping migration because current storage version is not 0"
|
||||
"Skipping migration because in-code storage version is not 0"
|
||||
);
|
||||
return weight
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -168,7 +168,7 @@ pub mod pallet {
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -51,7 +51,7 @@ pub mod v1 {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
use sp_runtime::Saturating;
|
||||
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
if onchain > 0 {
|
||||
|
||||
@@ -76,7 +76,7 @@ pub mod pallet {
|
||||
use frame_support::{pallet_prelude::*, traits::ExistenceRequirement};
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -54,17 +54,17 @@ pub mod v1 {
|
||||
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current_version = Pallet::<T>::current_storage_version();
|
||||
let onchain_version = Pallet::<T>::on_chain_storage_version();
|
||||
let in_code_version = Pallet::<T>::in_code_storage_version();
|
||||
let on_chain_version = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
current_version,
|
||||
onchain_version
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
in_code_version,
|
||||
on_chain_version
|
||||
);
|
||||
|
||||
if onchain_version == 0 && current_version == 1 {
|
||||
if on_chain_version == 0 && in_code_version == 1 {
|
||||
let mut translated = 0u64;
|
||||
let mut configs_iterated = 0u64;
|
||||
Collection::<T>::translate::<
|
||||
@@ -77,13 +77,13 @@ pub mod v1 {
|
||||
Some(old_value.migrate_to_v1(item_configs))
|
||||
});
|
||||
|
||||
current_version.put::<Pallet<T>>();
|
||||
in_code_version.put::<Pallet<T>>();
|
||||
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Upgraded {} records, storage to version {:?}",
|
||||
translated,
|
||||
current_version
|
||||
in_code_version
|
||||
);
|
||||
T::DbWeight::get().reads_writes(translated + configs_iterated + 1, translated + 1)
|
||||
} else {
|
||||
|
||||
@@ -1576,7 +1576,7 @@ pub mod pallet {
|
||||
use frame_system::{ensure_signed, pallet_prelude::*};
|
||||
use sp_runtime::Perbill;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(8);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -342,25 +342,25 @@ pub mod v5 {
|
||||
pub struct MigrateToV5<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV5<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let in_code = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
in_code,
|
||||
onchain
|
||||
);
|
||||
|
||||
if current == 5 && onchain == 4 {
|
||||
if in_code == 5 && onchain == 4 {
|
||||
let mut translated = 0u64;
|
||||
RewardPools::<T>::translate::<OldRewardPool<T>, _>(|_id, old_value| {
|
||||
translated.saturating_inc();
|
||||
Some(old_value.migrate_to_v5())
|
||||
});
|
||||
|
||||
current.put::<Pallet<T>>();
|
||||
log!(info, "Upgraded {} pools, storage to version {:?}", translated, current);
|
||||
in_code.put::<Pallet<T>>();
|
||||
log!(info, "Upgraded {} pools, storage to version {:?}", translated, in_code);
|
||||
|
||||
// reads: translated + onchain version.
|
||||
// writes: translated + current.put.
|
||||
@@ -498,12 +498,12 @@ pub mod v4 {
|
||||
#[allow(deprecated)]
|
||||
impl<T: Config, U: Get<Perbill>> OnRuntimeUpgrade for MigrateToV4<T, U> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
@@ -579,13 +579,13 @@ pub mod v3 {
|
||||
pub struct MigrateToV3<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV3<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
if onchain == 2 {
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
@@ -859,12 +859,12 @@ pub mod v2 {
|
||||
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV2<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
@@ -976,12 +976,12 @@ pub mod v1 {
|
||||
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let current = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
log!(
|
||||
info,
|
||||
"Running migration with current storage version {:?} / onchain {:?}",
|
||||
"Running migration with in-code storage version {:?} / onchain {:?}",
|
||||
current,
|
||||
onchain
|
||||
);
|
||||
|
||||
@@ -102,7 +102,7 @@ pub const MAX_HASH_UPGRADE_BULK_COUNT: u32 = 1024;
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::config]
|
||||
|
||||
@@ -143,7 +143,7 @@ pub mod pallet {
|
||||
use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg};
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -109,16 +109,16 @@ pub mod v1 {
|
||||
}
|
||||
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current_version = Pallet::<T, I>::current_storage_version();
|
||||
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
let in_code_version = Pallet::<T, I>::in_code_storage_version();
|
||||
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
log::info!(
|
||||
target: TARGET,
|
||||
"running migration with current storage version {:?} / onchain {:?}.",
|
||||
current_version,
|
||||
onchain_version
|
||||
"running migration with in-code storage version {:?} / onchain {:?}.",
|
||||
in_code_version,
|
||||
on_chain_version
|
||||
);
|
||||
if onchain_version != 0 {
|
||||
if on_chain_version != 0 {
|
||||
log::warn!(target: TARGET, "skipping migration from v0 to v1.");
|
||||
return weight
|
||||
}
|
||||
@@ -149,8 +149,8 @@ pub mod v1 {
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {
|
||||
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
ensure!(onchain_version == 1, "must upgrade from version 0 to 1.");
|
||||
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
|
||||
ensure!(on_chain_version == 1, "must upgrade from version 0 to 1.");
|
||||
let pre_referendum_count: u32 = Decode::decode(&mut &state[..])
|
||||
.expect("failed to decode the state from pre-upgrade.");
|
||||
let post_referendum_count = ReferendumInfoFor::<T, I>::iter().count() as u32;
|
||||
|
||||
@@ -229,7 +229,7 @@ pub mod pallet {
|
||||
use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*};
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -58,7 +58,7 @@ pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -368,7 +368,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -40,11 +40,11 @@ impl<
|
||||
{
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
let current = Pallet::<T, I>::current_storage_version();
|
||||
let onchain = Pallet::<T, I>::on_chain_storage_version();
|
||||
ensure!(onchain == 0 && current == 2, "pallet_society: invalid version");
|
||||
let in_code = Pallet::<T, I>::in_code_storage_version();
|
||||
let on_chain = Pallet::<T, I>::on_chain_storage_version();
|
||||
ensure!(on_chain == 0 && in_code == 2, "pallet_society: invalid version");
|
||||
|
||||
Ok((old::Candidates::<T, I>::get(), old::Members::<T, I>::get()).encode())
|
||||
Ok((v0::Candidates::<T, I>::get(), v0::Members::<T, I>::get()).encode())
|
||||
}
|
||||
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
@@ -103,7 +103,7 @@ pub type MigrateToV2<T, I, PastPayouts> = frame_support::migrations::VersionedMi
|
||||
<T as frame_system::Config>::DbWeight,
|
||||
>;
|
||||
|
||||
pub(crate) mod old {
|
||||
pub(crate) mod v0 {
|
||||
use super::*;
|
||||
use frame_support::storage_alias;
|
||||
|
||||
@@ -230,37 +230,37 @@ pub fn assert_internal_consistency<T: Config<I>, I: Instance + 'static>() {
|
||||
}
|
||||
|
||||
// We don't use these - make sure they don't exist.
|
||||
assert_eq!(old::SuspendedCandidates::<T, I>::iter().count(), 0);
|
||||
assert_eq!(old::Strikes::<T, I>::iter().count(), 0);
|
||||
assert_eq!(old::Vouching::<T, I>::iter().count(), 0);
|
||||
assert!(!old::Defender::<T, I>::exists());
|
||||
assert!(!old::Members::<T, I>::exists());
|
||||
assert_eq!(v0::SuspendedCandidates::<T, I>::iter().count(), 0);
|
||||
assert_eq!(v0::Strikes::<T, I>::iter().count(), 0);
|
||||
assert_eq!(v0::Vouching::<T, I>::iter().count(), 0);
|
||||
assert!(!v0::Defender::<T, I>::exists());
|
||||
assert!(!v0::Members::<T, I>::exists());
|
||||
}
|
||||
|
||||
pub fn from_original<T: Config<I>, I: Instance + 'static>(
|
||||
past_payouts: &mut [(<T as frame_system::Config>::AccountId, BalanceOf<T, I>)],
|
||||
) -> Result<Weight, &'static str> {
|
||||
// Migrate Bids from old::Bids (just a trunctation).
|
||||
Bids::<T, I>::put(BoundedVec::<_, T::MaxBids>::truncate_from(old::Bids::<T, I>::take()));
|
||||
Bids::<T, I>::put(BoundedVec::<_, T::MaxBids>::truncate_from(v0::Bids::<T, I>::take()));
|
||||
|
||||
// Initialise round counter.
|
||||
RoundCount::<T, I>::put(0);
|
||||
|
||||
// Migrate Candidates from old::Candidates
|
||||
for Bid { who: candidate, kind, value } in old::Candidates::<T, I>::take().into_iter() {
|
||||
for Bid { who: candidate, kind, value } in v0::Candidates::<T, I>::take().into_iter() {
|
||||
let mut tally = Tally::default();
|
||||
// Migrate Votes from old::Votes
|
||||
// No need to drain, since we're overwriting values.
|
||||
for (voter, vote) in old::Votes::<T, I>::iter_prefix(&candidate) {
|
||||
for (voter, vote) in v0::Votes::<T, I>::iter_prefix(&candidate) {
|
||||
Votes::<T, I>::insert(
|
||||
&candidate,
|
||||
&voter,
|
||||
Vote { approve: vote == old::Vote::Approve, weight: 1 },
|
||||
Vote { approve: vote == v0::Vote::Approve, weight: 1 },
|
||||
);
|
||||
match vote {
|
||||
old::Vote::Approve => tally.approvals.saturating_inc(),
|
||||
old::Vote::Reject => tally.rejections.saturating_inc(),
|
||||
old::Vote::Skeptic => Skeptic::<T, I>::put(&voter),
|
||||
v0::Vote::Approve => tally.approvals.saturating_inc(),
|
||||
v0::Vote::Reject => tally.rejections.saturating_inc(),
|
||||
v0::Vote::Skeptic => Skeptic::<T, I>::put(&voter),
|
||||
}
|
||||
}
|
||||
Candidates::<T, I>::insert(
|
||||
@@ -271,9 +271,9 @@ pub fn from_original<T: Config<I>, I: Instance + 'static>(
|
||||
|
||||
// Migrate Members from old::Members old::Strikes old::Vouching
|
||||
let mut member_count = 0;
|
||||
for member in old::Members::<T, I>::take() {
|
||||
let strikes = old::Strikes::<T, I>::take(&member);
|
||||
let vouching = old::Vouching::<T, I>::take(&member);
|
||||
for member in v0::Members::<T, I>::take() {
|
||||
let strikes = v0::Strikes::<T, I>::take(&member);
|
||||
let vouching = v0::Vouching::<T, I>::take(&member);
|
||||
let record = MemberRecord { index: member_count, rank: 0, strikes, vouching };
|
||||
Members::<T, I>::insert(&member, record);
|
||||
MemberByIndex::<T, I>::insert(member_count, &member);
|
||||
@@ -314,7 +314,7 @@ pub fn from_original<T: Config<I>, I: Instance + 'static>(
|
||||
// Migrate Payouts from: old::Payouts and raw info (needed since we can't query old chain
|
||||
// state).
|
||||
past_payouts.sort();
|
||||
for (who, mut payouts) in old::Payouts::<T, I>::iter() {
|
||||
for (who, mut payouts) in v0::Payouts::<T, I>::iter() {
|
||||
payouts.truncate(T::MaxPayouts::get() as usize);
|
||||
// ^^ Safe since we already truncated.
|
||||
let paid = past_payouts
|
||||
@@ -329,19 +329,19 @@ pub fn from_original<T: Config<I>, I: Instance + 'static>(
|
||||
}
|
||||
|
||||
// Migrate SuspendedMembers from old::SuspendedMembers old::Strikes old::Vouching.
|
||||
for who in old::SuspendedMembers::<T, I>::iter_keys() {
|
||||
let strikes = old::Strikes::<T, I>::take(&who);
|
||||
let vouching = old::Vouching::<T, I>::take(&who);
|
||||
for who in v0::SuspendedMembers::<T, I>::iter_keys() {
|
||||
let strikes = v0::Strikes::<T, I>::take(&who);
|
||||
let vouching = v0::Vouching::<T, I>::take(&who);
|
||||
let record = MemberRecord { index: 0, rank: 0, strikes, vouching };
|
||||
SuspendedMembers::<T, I>::insert(&who, record);
|
||||
}
|
||||
|
||||
// Any suspended candidates remaining are rejected.
|
||||
let _ = old::SuspendedCandidates::<T, I>::clear(u32::MAX, None);
|
||||
let _ = v0::SuspendedCandidates::<T, I>::clear(u32::MAX, None);
|
||||
|
||||
// We give the current defender the benefit of the doubt.
|
||||
old::Defender::<T, I>::kill();
|
||||
let _ = old::DefenderVotes::<T, I>::clear(u32::MAX, None);
|
||||
v0::Defender::<T, I>::kill();
|
||||
let _ = v0::DefenderVotes::<T, I>::clear(u32::MAX, None);
|
||||
|
||||
Ok(T::BlockWeights::get().max_block)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//! Tests for the module.
|
||||
|
||||
use super::*;
|
||||
use migrations::old;
|
||||
use migrations::v0;
|
||||
use mock::*;
|
||||
|
||||
use frame_support::{assert_noop, assert_ok};
|
||||
@@ -32,41 +32,41 @@ use RuntimeOrigin as Origin;
|
||||
#[test]
|
||||
fn migration_works() {
|
||||
EnvBuilder::new().founded(false).execute(|| {
|
||||
use old::Vote::*;
|
||||
use v0::Vote::*;
|
||||
|
||||
// Initialise the old storage items.
|
||||
Founder::<Test>::put(10);
|
||||
Head::<Test>::put(30);
|
||||
old::Members::<Test, ()>::put(vec![10, 20, 30]);
|
||||
old::Vouching::<Test, ()>::insert(30, Vouching);
|
||||
old::Vouching::<Test, ()>::insert(40, Banned);
|
||||
old::Strikes::<Test, ()>::insert(20, 1);
|
||||
old::Strikes::<Test, ()>::insert(30, 2);
|
||||
old::Strikes::<Test, ()>::insert(40, 5);
|
||||
old::Payouts::<Test, ()>::insert(20, vec![(1, 1)]);
|
||||
old::Payouts::<Test, ()>::insert(
|
||||
v0::Members::<Test, ()>::put(vec![10, 20, 30]);
|
||||
v0::Vouching::<Test, ()>::insert(30, Vouching);
|
||||
v0::Vouching::<Test, ()>::insert(40, Banned);
|
||||
v0::Strikes::<Test, ()>::insert(20, 1);
|
||||
v0::Strikes::<Test, ()>::insert(30, 2);
|
||||
v0::Strikes::<Test, ()>::insert(40, 5);
|
||||
v0::Payouts::<Test, ()>::insert(20, vec![(1, 1)]);
|
||||
v0::Payouts::<Test, ()>::insert(
|
||||
30,
|
||||
(0..=<Test as Config>::MaxPayouts::get())
|
||||
.map(|i| (i as u64, i as u64))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
old::SuspendedMembers::<Test, ()>::insert(40, true);
|
||||
v0::SuspendedMembers::<Test, ()>::insert(40, true);
|
||||
|
||||
old::Defender::<Test, ()>::put(20);
|
||||
old::DefenderVotes::<Test, ()>::insert(10, Approve);
|
||||
old::DefenderVotes::<Test, ()>::insert(20, Approve);
|
||||
old::DefenderVotes::<Test, ()>::insert(30, Reject);
|
||||
v0::Defender::<Test, ()>::put(20);
|
||||
v0::DefenderVotes::<Test, ()>::insert(10, Approve);
|
||||
v0::DefenderVotes::<Test, ()>::insert(20, Approve);
|
||||
v0::DefenderVotes::<Test, ()>::insert(30, Reject);
|
||||
|
||||
old::SuspendedCandidates::<Test, ()>::insert(50, (10, Deposit(100)));
|
||||
v0::SuspendedCandidates::<Test, ()>::insert(50, (10, Deposit(100)));
|
||||
|
||||
old::Candidates::<Test, ()>::put(vec![
|
||||
v0::Candidates::<Test, ()>::put(vec![
|
||||
Bid { who: 60, kind: Deposit(100), value: 200 },
|
||||
Bid { who: 70, kind: Vouch(30, 30), value: 100 },
|
||||
]);
|
||||
old::Votes::<Test, ()>::insert(60, 10, Approve);
|
||||
old::Votes::<Test, ()>::insert(70, 10, Reject);
|
||||
old::Votes::<Test, ()>::insert(70, 20, Approve);
|
||||
old::Votes::<Test, ()>::insert(70, 30, Approve);
|
||||
v0::Votes::<Test, ()>::insert(60, 10, Approve);
|
||||
v0::Votes::<Test, ()>::insert(70, 10, Reject);
|
||||
v0::Votes::<Test, ()>::insert(70, 20, Approve);
|
||||
v0::Votes::<Test, ()>::insert(70, 30, Approve);
|
||||
|
||||
let bids = (0..=<Test as Config>::MaxBids::get())
|
||||
.map(|i| Bid {
|
||||
@@ -75,7 +75,7 @@ fn migration_works() {
|
||||
value: 10u64 + i as u64,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
old::Bids::<Test, ()>::put(bids);
|
||||
v0::Bids::<Test, ()>::put(bids);
|
||||
|
||||
migrations::from_original::<Test, ()>(&mut [][..]).expect("migration failed");
|
||||
migrations::assert_internal_consistency::<Test, ()>();
|
||||
|
||||
@@ -67,11 +67,11 @@ pub mod v14 {
|
||||
pub struct MigrateToV14<T>(core::marker::PhantomData<T>);
|
||||
impl<T: Config> OnRuntimeUpgrade for MigrateToV14<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let in_code = Pallet::<T>::in_code_storage_version();
|
||||
let on_chain = Pallet::<T>::on_chain_storage_version();
|
||||
|
||||
if current == 14 && on_chain == 13 {
|
||||
current.put::<Pallet<T>>();
|
||||
if in_code == 14 && on_chain == 13 {
|
||||
in_code.put::<Pallet<T>>();
|
||||
|
||||
log!(info, "v14 applied successfully.");
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
@@ -108,12 +108,12 @@ pub mod v13 {
|
||||
}
|
||||
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let current = Pallet::<T>::current_storage_version();
|
||||
let in_code = Pallet::<T>::in_code_storage_version();
|
||||
let onchain = StorageVersion::<T>::get();
|
||||
|
||||
if current == 13 && onchain == ObsoleteReleases::V12_0_0 {
|
||||
if in_code == 13 && onchain == ObsoleteReleases::V12_0_0 {
|
||||
StorageVersion::<T>::kill();
|
||||
current.put::<Pallet<T>>();
|
||||
in_code.put::<Pallet<T>>();
|
||||
|
||||
log!(info, "v13 applied successfully");
|
||||
T::DbWeight::get().reads_writes(1, 2)
|
||||
|
||||
@@ -66,7 +66,7 @@ pub mod pallet {
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(14);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
@@ -555,6 +555,42 @@ pub fn __create_tt_macro(input: TokenStream) -> TokenStream {
|
||||
tt_macro::create_tt_return_macro(input)
|
||||
}
|
||||
|
||||
/// Allows accessing on-chain pallet storage that is no longer accessible via the pallet.
|
||||
///
|
||||
/// This is especially useful when writing storage migrations, when types of storage items are
|
||||
/// modified or outright removed, but the previous definition is required to perform the migration.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// Imagine a pallet with the following storage definition:
|
||||
/// ```ignore
|
||||
/// #[pallet::storage]
|
||||
/// pub type Value<T: Config> = StorageValue<_, u32>;
|
||||
/// ```
|
||||
/// `Value` can be accessed by calling `Value::<T>::get()`.
|
||||
///
|
||||
/// Now imagine the definition of `Value` is updated to a `(u32, u32)`:
|
||||
/// ```ignore
|
||||
/// #[pallet::storage]
|
||||
/// pub type Value<T: Config> = StorageValue<_, (u32, u32)>;
|
||||
/// ```
|
||||
/// The on-chain value of `Value` is `u32`, but `Value::<T>::get()` expects it to be `(u32, u32)`.
|
||||
///
|
||||
/// In this instance the developer must write a storage migration to reading the old value of
|
||||
/// `Value` and writing it back to storage in the new format, so that the on-chain storage layout is
|
||||
/// consistent with what is defined in the pallet.
|
||||
///
|
||||
/// We can read the old v0 value of `Value` in the migration by creating a `storage_alias`:
|
||||
/// ```ignore
|
||||
/// pub(crate) mod v0 {
|
||||
/// use super::*;
|
||||
///
|
||||
/// #[storage_alias]
|
||||
/// pub type Value<T: crate::Config> = StorageValue<crate::Pallet<T>, u32>;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The developer can now access the old value of `Value` by calling `v0::Value::<T>::get()`.
|
||||
#[proc_macro_attribute]
|
||||
pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream {
|
||||
storage_alias::storage_alias(attributes.into(), input.into())
|
||||
@@ -1058,7 +1094,7 @@ pub fn generate_store(_: TokenStream, _: TokenStream) -> TokenStream {
|
||||
/// pub struct Pallet<T>(_);
|
||||
/// ```
|
||||
///
|
||||
/// If not present, the current storage version is set to the default value.
|
||||
/// If not present, the in-code storage version is set to the default value.
|
||||
#[proc_macro_attribute]
|
||||
pub fn storage_version(_: TokenStream, _: TokenStream) -> TokenStream {
|
||||
pallet_macro_stub()
|
||||
|
||||
@@ -42,7 +42,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
>::name::<Self>().unwrap_or("<unknown pallet name>")
|
||||
};
|
||||
|
||||
let initialize_on_chain_storage_version = if let Some(current_version) =
|
||||
let initialize_on_chain_storage_version = if let Some(in_code_version) =
|
||||
&def.pallet_struct.storage_version
|
||||
{
|
||||
quote::quote! {
|
||||
@@ -50,9 +50,9 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
target: #frame_support::LOG_TARGET,
|
||||
"🐥 New pallet {:?} detected in the runtime. Initializing the on-chain storage version to match the storage version defined in the pallet: {:?}",
|
||||
#pallet_name,
|
||||
#current_version
|
||||
#in_code_version
|
||||
);
|
||||
#current_version.put::<Self>();
|
||||
#in_code_version.put::<Self>();
|
||||
}
|
||||
} else {
|
||||
quote::quote! {
|
||||
@@ -73,10 +73,10 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
#frame_support::__private::log::info!(
|
||||
target: #frame_support::LOG_TARGET,
|
||||
"⚠️ {} declares internal migrations (which *might* execute). \
|
||||
On-chain `{:?}` vs current storage version `{:?}`",
|
||||
On-chain `{:?}` vs in-code storage version `{:?}`",
|
||||
#pallet_name,
|
||||
<Self as #frame_support::traits::GetStorageVersion>::on_chain_storage_version(),
|
||||
<Self as #frame_support::traits::GetStorageVersion>::current_storage_version(),
|
||||
<Self as #frame_support::traits::GetStorageVersion>::in_code_storage_version(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -102,23 +102,23 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
};
|
||||
|
||||
// If a storage version is set, we should ensure that the storage version on chain matches the
|
||||
// current storage version. This assumes that `Executive` is running custom migrations before
|
||||
// in-code storage version. This assumes that `Executive` is running custom migrations before
|
||||
// the pallets are called.
|
||||
let post_storage_version_check = if def.pallet_struct.storage_version.is_some() {
|
||||
quote::quote! {
|
||||
let on_chain_version = <Self as #frame_support::traits::GetStorageVersion>::on_chain_storage_version();
|
||||
let current_version = <Self as #frame_support::traits::GetStorageVersion>::current_storage_version();
|
||||
let in_code_version = <Self as #frame_support::traits::GetStorageVersion>::in_code_storage_version();
|
||||
|
||||
if on_chain_version != current_version {
|
||||
if on_chain_version != in_code_version {
|
||||
#frame_support::__private::log::error!(
|
||||
target: #frame_support::LOG_TARGET,
|
||||
"{}: On chain storage version {:?} doesn't match current storage version {:?}.",
|
||||
"{}: On chain storage version {:?} doesn't match in-code storage version {:?}.",
|
||||
#pallet_name,
|
||||
on_chain_version,
|
||||
current_version,
|
||||
in_code_version,
|
||||
);
|
||||
|
||||
return Err("On chain and current storage version do not match. Missing runtime upgrade?".into());
|
||||
return Err("On chain and in-code storage version do not match. Missing runtime upgrade?".into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -160,7 +160,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
}
|
||||
);
|
||||
|
||||
let (storage_version, current_storage_version_ty) =
|
||||
let (storage_version, in_code_storage_version_ty) =
|
||||
if let Some(v) = def.pallet_struct.storage_version.as_ref() {
|
||||
(quote::quote! { #v }, quote::quote! { #frame_support::traits::StorageVersion })
|
||||
} else {
|
||||
@@ -203,9 +203,9 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
for #pallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
type CurrentStorageVersion = #current_storage_version_ty;
|
||||
type InCodeStorageVersion = #in_code_storage_version_ty;
|
||||
|
||||
fn current_storage_version() -> Self::CurrentStorageVersion {
|
||||
fn in_code_storage_version() -> Self::InCodeStorageVersion {
|
||||
#storage_version
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ pub struct PalletStructDef {
|
||||
/// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`.
|
||||
/// Contains the span of the attribute.
|
||||
pub without_storage_info: Option<proc_macro2::Span>,
|
||||
/// The current storage version of the pallet.
|
||||
/// The in-code storage version of the pallet.
|
||||
pub storage_version: Option<syn::Path>,
|
||||
}
|
||||
|
||||
|
||||
@@ -1178,7 +1178,7 @@ pub mod pallet_prelude {
|
||||
/// # `pallet::storage_version`
|
||||
///
|
||||
/// Because the [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) macro
|
||||
/// implements [`traits::GetStorageVersion`], the current storage version needs to be
|
||||
/// implements [`traits::GetStorageVersion`], the in-code storage version needs to be
|
||||
/// communicated to the macro. This can be done by using the `pallet::storage_version`
|
||||
/// attribute:
|
||||
///
|
||||
@@ -1190,7 +1190,7 @@ pub mod pallet_prelude {
|
||||
/// pub struct Pallet<T>(_);
|
||||
/// ```
|
||||
///
|
||||
/// If not present, the current storage version is set to the default value.
|
||||
/// If not present, the in-code storage version is set to the default value.
|
||||
///
|
||||
/// Also see [`pallet::storage_version`](`frame_support::pallet_macros::storage_version`)
|
||||
///
|
||||
|
||||
@@ -43,12 +43,30 @@ use sp_std::marker::PhantomData;
|
||||
/// Otherwise, a warning is logged notifying the developer that the upgrade was a noop and should
|
||||
/// probably be removed.
|
||||
///
|
||||
/// It is STRONGLY RECOMMENDED to write the unversioned migration logic in a private module and
|
||||
/// only export the versioned migration logic to prevent accidentally using the unversioned
|
||||
/// migration in any runtimes.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```ignore
|
||||
/// // In file defining migrations
|
||||
/// pub struct VersionUncheckedMigrateV5ToV6<T>(sp_std::marker::PhantomData<T>);
|
||||
/// impl<T: Config> OnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6<T> {
|
||||
/// // OnRuntimeUpgrade implementation...
|
||||
///
|
||||
/// /// Private module containing *version unchecked* migration logic.
|
||||
/// ///
|
||||
/// /// Should only be used by the [`VersionedMigration`] type in this module to create something to
|
||||
/// /// export.
|
||||
/// ///
|
||||
/// /// We keep this private so the unversioned migration cannot accidentally be used in any runtimes.
|
||||
/// ///
|
||||
/// /// For more about this pattern of keeping items private, see
|
||||
/// /// - https://github.com/rust-lang/rust/issues/30905
|
||||
/// /// - https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40
|
||||
/// mod version_unchecked {
|
||||
/// use super::*;
|
||||
/// pub struct MigrateV5ToV6<T>(sp_std::marker::PhantomData<T>);
|
||||
/// impl<T: Config> OnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6<T> {
|
||||
/// // OnRuntimeUpgrade implementation...
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// pub type MigrateV5ToV6<T, I> =
|
||||
@@ -91,7 +109,7 @@ impl<
|
||||
const FROM: u16,
|
||||
const TO: u16,
|
||||
Inner: crate::traits::OnRuntimeUpgrade,
|
||||
Pallet: GetStorageVersion<CurrentStorageVersion = StorageVersion> + PalletInfoAccess,
|
||||
Pallet: GetStorageVersion<InCodeStorageVersion = StorageVersion> + PalletInfoAccess,
|
||||
DbWeight: Get<RuntimeDbWeight>,
|
||||
> crate::traits::OnRuntimeUpgrade for VersionedMigration<FROM, TO, Inner, Pallet, DbWeight>
|
||||
{
|
||||
@@ -163,25 +181,25 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// Can store the current pallet version in storage.
|
||||
pub trait StoreCurrentStorageVersion<T: GetStorageVersion + PalletInfoAccess> {
|
||||
/// Write the current storage version to the storage.
|
||||
fn store_current_storage_version();
|
||||
/// Can store the in-code pallet version on-chain.
|
||||
pub trait StoreInCodeStorageVersion<T: GetStorageVersion + PalletInfoAccess> {
|
||||
/// Write the in-code storage version on-chain.
|
||||
fn store_in_code_storage_version();
|
||||
}
|
||||
|
||||
impl<T: GetStorageVersion<CurrentStorageVersion = StorageVersion> + PalletInfoAccess>
|
||||
StoreCurrentStorageVersion<T> for StorageVersion
|
||||
impl<T: GetStorageVersion<InCodeStorageVersion = StorageVersion> + PalletInfoAccess>
|
||||
StoreInCodeStorageVersion<T> for StorageVersion
|
||||
{
|
||||
fn store_current_storage_version() {
|
||||
let version = <T as GetStorageVersion>::current_storage_version();
|
||||
fn store_in_code_storage_version() {
|
||||
let version = <T as GetStorageVersion>::in_code_storage_version();
|
||||
version.put::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: GetStorageVersion<CurrentStorageVersion = NoStorageVersionSet> + PalletInfoAccess>
|
||||
StoreCurrentStorageVersion<T> for NoStorageVersionSet
|
||||
impl<T: GetStorageVersion<InCodeStorageVersion = NoStorageVersionSet> + PalletInfoAccess>
|
||||
StoreInCodeStorageVersion<T> for NoStorageVersionSet
|
||||
{
|
||||
fn store_current_storage_version() {
|
||||
fn store_in_code_storage_version() {
|
||||
StorageVersion::default().put::<T>();
|
||||
}
|
||||
}
|
||||
@@ -193,7 +211,7 @@ pub trait PalletVersionToStorageVersionHelper {
|
||||
|
||||
impl<T: GetStorageVersion + PalletInfoAccess> PalletVersionToStorageVersionHelper for T
|
||||
where
|
||||
T::CurrentStorageVersion: StoreCurrentStorageVersion<T>,
|
||||
T::InCodeStorageVersion: StoreInCodeStorageVersion<T>,
|
||||
{
|
||||
fn migrate(db_weight: &RuntimeDbWeight) -> Weight {
|
||||
const PALLET_VERSION_STORAGE_KEY_POSTFIX: &[u8] = b":__PALLET_VERSION__:";
|
||||
@@ -204,8 +222,7 @@ where
|
||||
|
||||
sp_io::storage::clear(&pallet_version_key(<T as PalletInfoAccess>::name()));
|
||||
|
||||
<T::CurrentStorageVersion as StoreCurrentStorageVersion<T>>::store_current_storage_version(
|
||||
);
|
||||
<T::InCodeStorageVersion as StoreInCodeStorageVersion<T>>::store_in_code_storage_version();
|
||||
|
||||
db_weight.writes(2)
|
||||
}
|
||||
@@ -226,7 +243,7 @@ impl PalletVersionToStorageVersionHelper for T {
|
||||
|
||||
/// Migrate from the `PalletVersion` struct to the new [`StorageVersion`] struct.
|
||||
///
|
||||
/// This will remove all `PalletVersion's` from the state and insert the current storage version.
|
||||
/// This will remove all `PalletVersion's` from the state and insert the in-code storage version.
|
||||
pub fn migrate_from_pallet_version_to_storage_version<
|
||||
Pallets: PalletVersionToStorageVersionHelper,
|
||||
>(
|
||||
|
||||
@@ -90,7 +90,7 @@ impl<BlockNumber: Copy + AtLeast32BitUnsigned> OnIdle<BlockNumber> for Tuple {
|
||||
///
|
||||
/// Implementing this trait for a pallet let's you express operations that should
|
||||
/// happen at genesis. It will be called in an externalities provided environment and
|
||||
/// will see the genesis state after all pallets have written their genesis state.
|
||||
/// will set the genesis state after all pallets have written their genesis state.
|
||||
#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))]
|
||||
#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
|
||||
#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
|
||||
@@ -306,19 +306,23 @@ pub trait IntegrityTest {
|
||||
/// end
|
||||
/// ```
|
||||
///
|
||||
/// * `OnRuntimeUpgrade` is only executed before everything else if a code
|
||||
/// * `OnRuntimeUpgrade` is mandatorily at the beginning of the block body (extrinsics) being
|
||||
/// processed. change is detected.
|
||||
/// * Extrinsics start with inherents, and continue with other signed or unsigned extrinsics.
|
||||
/// * `OnIdle` optionally comes after extrinsics.
|
||||
/// `OnFinalize` mandatorily comes after `OnIdle`.
|
||||
/// * [`OnRuntimeUpgrade`](Hooks::OnRuntimeUpgrade) hooks are only executed when a code change is
|
||||
/// detected.
|
||||
/// * [`OnRuntimeUpgrade`](Hooks::OnRuntimeUpgrade) hooks are mandatorily executed at the very
|
||||
/// beginning of the block body, before any extrinsics are processed.
|
||||
/// * [`Inherents`](sp_inherents) are always executed before any other other signed or unsigned
|
||||
/// extrinsics.
|
||||
/// * [`OnIdle`](Hooks::OnIdle) hooks are executed after extrinsics if there is weight remaining in
|
||||
/// the block.
|
||||
/// * [`OnFinalize`](Hooks::OnFinalize) hooks are mandatorily executed after
|
||||
/// [`OnIdle`](Hooks::OnIdle).
|
||||
///
|
||||
/// > `OffchainWorker` is not part of this flow, as it is not really part of the consensus/main
|
||||
/// > block import path, and is called optionally, and in other circumstances. See
|
||||
/// > [`crate::traits::misc::OffchainWorker`] for more information.
|
||||
/// > [`OffchainWorker`](crate::traits::misc::OffchainWorker) hooks are not part of this flow,
|
||||
/// > because they are not part of the consensus/main block building logic. See
|
||||
/// > [`OffchainWorker`](crate::traits::misc::OffchainWorker) for more information.
|
||||
///
|
||||
/// To learn more about the execution of hooks see `frame-executive` as this component is is charge
|
||||
/// of dispatching extrinsics and placing the hooks in the correct order.
|
||||
/// To learn more about the execution of hooks see the FRAME `Executive` pallet which is in charge
|
||||
/// of dispatching extrinsics and calling hooks in the correct order.
|
||||
pub trait Hooks<BlockNumber> {
|
||||
/// Block initialization hook. This is called at the very beginning of block execution.
|
||||
///
|
||||
@@ -370,30 +374,38 @@ pub trait Hooks<BlockNumber> {
|
||||
Weight::zero()
|
||||
}
|
||||
|
||||
/// Hook executed when a code change (aka. a "runtime upgrade") is detected by FRAME.
|
||||
/// Hook executed when a code change (aka. a "runtime upgrade") is detected by the FRAME
|
||||
/// `Executive` pallet.
|
||||
///
|
||||
/// Be aware that this is called before [`Hooks::on_initialize`] of any pallet; therefore, a lot
|
||||
/// of the critical storage items such as `block_number` in system pallet might have not been
|
||||
/// set.
|
||||
/// set yet.
|
||||
///
|
||||
/// Vert similar to [`Hooks::on_initialize`], any code in this block is mandatory and MUST
|
||||
/// execute. Use with care.
|
||||
/// Similar to [`Hooks::on_initialize`], any code in this block is mandatory and MUST execute.
|
||||
/// It is strongly recommended to dry-run the execution of these hooks using
|
||||
/// [try-runtime-cli](https://github.com/paritytech/try-runtime-cli) to ensure they will not
|
||||
/// produce and overweight block which can brick your chain. Use with care!
|
||||
///
|
||||
/// ## Implementation Note: Versioning
|
||||
/// ## Implementation Note: Standalone Migrations
|
||||
///
|
||||
/// 1. An implementation of this should typically follow a pattern where the version of the
|
||||
/// pallet is checked against the onchain version, and a decision is made about what needs to be
|
||||
/// done. This is helpful to prevent accidental repetitive execution of this hook, which can be
|
||||
/// catastrophic.
|
||||
/// Additional migrations can be created by directly implementing [`OnRuntimeUpgrade`] on
|
||||
/// structs and passing them to `Executive`.
|
||||
///
|
||||
/// Alternatively, [`frame_support::migrations::VersionedMigration`] can be used to assist with
|
||||
/// this.
|
||||
/// ## Implementation Note: Pallet Versioning
|
||||
///
|
||||
/// ## Implementation Note: Runtime Level Migration
|
||||
/// Implementations of this hook are typically wrapped in
|
||||
/// [`crate::migrations::VersionedMigration`] to ensure the migration is executed exactly
|
||||
/// once and only when it is supposed to.
|
||||
///
|
||||
/// Additional "upgrade hooks" can be created by pallets by a manual implementation of
|
||||
/// [`Hooks::on_runtime_upgrade`] which can be passed on to `Executive` at the top level
|
||||
/// runtime.
|
||||
/// Alternatively, developers can manually implement version checks.
|
||||
///
|
||||
/// Failure to adequately check storage versions can result in accidental repetitive execution
|
||||
/// of the hook, which can be catastrophic.
|
||||
///
|
||||
/// ## Implementation Note: Weight
|
||||
///
|
||||
/// Typically, implementations of this method are simple enough that weights can be calculated
|
||||
/// manually. However, if required, a benchmark can also be used.
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
@@ -403,7 +415,7 @@ pub trait Hooks<BlockNumber> {
|
||||
/// It should focus on certain checks to ensure that the state is sensible. This is never
|
||||
/// executed in a consensus code-path, therefore it can consume as much weight as it needs.
|
||||
///
|
||||
/// This hook should not alter any storage.
|
||||
/// This hook must not alter any storage.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn try_state(_n: BlockNumber) -> Result<(), TryRuntimeError> {
|
||||
Ok(())
|
||||
@@ -415,7 +427,7 @@ pub trait Hooks<BlockNumber> {
|
||||
/// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector
|
||||
/// should be returned if there is no such need.
|
||||
///
|
||||
/// This hook is never meant to be executed on-chain but is meant to be used by testing tools.
|
||||
/// This hook is never executed on-chain but instead used by testing tools.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
|
||||
Ok(Vec::new())
|
||||
|
||||
@@ -261,41 +261,64 @@ impl Add<u16> for StorageVersion {
|
||||
}
|
||||
}
|
||||
|
||||
/// Special marker struct if no storage version is set for a pallet.
|
||||
/// Special marker struct used when [`storage_version`](crate::pallet_macros::storage_version) is
|
||||
/// not defined for a pallet.
|
||||
///
|
||||
/// If you (the reader) end up here, it probably means that you tried to compare
|
||||
/// [`GetStorageVersion::on_chain_storage_version`] against
|
||||
/// [`GetStorageVersion::current_storage_version`]. This basically means that the
|
||||
/// [`storage_version`](crate::pallet_macros::storage_version) is missing in the pallet where the
|
||||
/// mentioned functions are being called.
|
||||
/// [`GetStorageVersion::in_code_storage_version`]. This basically means that the
|
||||
/// [`storage_version`](crate::pallet_macros::storage_version) is missing from the pallet where the
|
||||
/// mentioned functions are being called, and needs to be defined.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct NoStorageVersionSet;
|
||||
|
||||
/// Provides information about the storage version of a pallet.
|
||||
/// Provides information about a pallet's storage versions.
|
||||
///
|
||||
/// It differentiates between current and on-chain storage version. Both should be only out of sync
|
||||
/// when a new runtime upgrade was applied and the runtime migrations did not yet executed.
|
||||
/// Otherwise it means that the pallet works with an unsupported storage version and unforeseen
|
||||
/// stuff can happen.
|
||||
/// Every pallet has two storage versions:
|
||||
/// 1. An in-code storage version
|
||||
/// 2. An on-chain storage version
|
||||
///
|
||||
/// The current storage version is the version of the pallet as supported at runtime. The active
|
||||
/// storage version is the version of the pallet in the storage.
|
||||
/// The in-code storage version is the version of the pallet as defined in the runtime blob, and the
|
||||
/// on-chain storage version is the version of the pallet stored on-chain.
|
||||
///
|
||||
/// It is required to update the on-chain storage version manually when a migration was applied.
|
||||
/// Storage versions should be only ever be out of sync when a pallet has been updated to a new
|
||||
/// version and the in-code version is incremented, but the migration has not yet been executed
|
||||
/// on-chain as part of a runtime upgrade.
|
||||
///
|
||||
/// It is the responsibility of the developer to ensure that the on-chain storage version is set
|
||||
/// correctly during a migration so that it matches the in-code storage version.
|
||||
pub trait GetStorageVersion {
|
||||
/// This will be filled out by the [`pallet`](crate::pallet) macro.
|
||||
/// This type is generated by the [`pallet`](crate::pallet) macro.
|
||||
///
|
||||
/// If the [`storage_version`](crate::pallet_macros::storage_version) attribute isn't given
|
||||
/// this is set to [`NoStorageVersionSet`] to inform the user that the attribute is missing.
|
||||
/// This should prevent that the user forgets to set a storage version when required. However,
|
||||
/// this will only work when the user actually tries to call [`Self::current_storage_version`]
|
||||
/// to compare it against the [`Self::on_chain_storage_version`]. If the attribute is given,
|
||||
/// this will be set to [`StorageVersion`].
|
||||
type CurrentStorageVersion;
|
||||
/// If the [`storage_version`](crate::pallet_macros::storage_version) attribute isn't specified,
|
||||
/// this is set to [`NoStorageVersionSet`] to signify that it is missing.
|
||||
///
|
||||
/// If the [`storage_version`](crate::pallet_macros::storage_version) attribute is specified,
|
||||
/// this is be set to a [`StorageVersion`] corresponding to the attribute.
|
||||
///
|
||||
/// The intention of using [`NoStorageVersionSet`] instead of defaulting to a [`StorageVersion`]
|
||||
/// of zero is to prevent developers from forgetting to set
|
||||
/// [`storage_version`](crate::pallet_macros::storage_version) when it is required, like in the
|
||||
/// case that they wish to compare the in-code storage version to the on-chain storage version.
|
||||
type InCodeStorageVersion;
|
||||
|
||||
/// Returns the current storage version as supported by the pallet.
|
||||
fn current_storage_version() -> Self::CurrentStorageVersion;
|
||||
/// Returns the on-chain storage version of the pallet as stored in the storage.
|
||||
#[deprecated(
|
||||
note = "This method has been renamed to `in_code_storage_version` and will be removed after March 2024."
|
||||
)]
|
||||
/// DEPRECATED: Use [`Self::current_storage_version`] instead.
|
||||
///
|
||||
/// Returns the in-code storage version as specified in the
|
||||
/// [`storage_version`](crate::pallet_macros::storage_version) attribute, or
|
||||
/// [`NoStorageVersionSet`] if the attribute is missing.
|
||||
fn current_storage_version() -> Self::InCodeStorageVersion {
|
||||
Self::in_code_storage_version()
|
||||
}
|
||||
|
||||
/// Returns the in-code storage version as specified in the
|
||||
/// [`storage_version`](crate::pallet_macros::storage_version) attribute, or
|
||||
/// [`NoStorageVersionSet`] if the attribute is missing.
|
||||
fn in_code_storage_version() -> Self::InCodeStorageVersion;
|
||||
/// Returns the storage version of the pallet as last set in the actual on-chain storage.
|
||||
fn on_chain_storage_version() -> StorageVersion;
|
||||
}
|
||||
|
||||
|
||||
@@ -683,7 +683,7 @@ fn test_metadata() {
|
||||
name: "Version",
|
||||
ty: meta_type::<RuntimeVersion>(),
|
||||
value: RuntimeVersion::default().encode(),
|
||||
docs: maybe_docs(vec![ " Get the chain's current version."]),
|
||||
docs: maybe_docs(vec![ " Get the chain's in-code version."]),
|
||||
},
|
||||
PalletConstantMetadata {
|
||||
name: "SS58Prefix",
|
||||
|
||||
@@ -590,7 +590,7 @@ pub mod pallet2 {
|
||||
Self::deposit_event(Event::Something(31));
|
||||
|
||||
if UpdateStorageVersion::get() {
|
||||
Self::current_storage_version().put::<Self>();
|
||||
Self::in_code_storage_version().put::<Self>();
|
||||
}
|
||||
|
||||
Weight::zero()
|
||||
@@ -1310,7 +1310,7 @@ fn pallet_on_genesis() {
|
||||
assert_eq!(pallet::Pallet::<Runtime>::on_chain_storage_version(), StorageVersion::new(0));
|
||||
pallet::Pallet::<Runtime>::on_genesis();
|
||||
assert_eq!(
|
||||
pallet::Pallet::<Runtime>::current_storage_version(),
|
||||
pallet::Pallet::<Runtime>::in_code_storage_version(),
|
||||
pallet::Pallet::<Runtime>::on_chain_storage_version(),
|
||||
);
|
||||
})
|
||||
@@ -2257,10 +2257,10 @@ fn pallet_on_chain_storage_version_initializes_correctly() {
|
||||
AllPalletsWithSystem,
|
||||
>;
|
||||
|
||||
// Simple example of a pallet with current version 10 being added to the runtime for the first
|
||||
// Simple example of a pallet with in-code version 10 being added to the runtime for the first
|
||||
// time.
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let current_version = Example::current_storage_version();
|
||||
let in_code_version = Example::in_code_storage_version();
|
||||
|
||||
// Check the pallet has no storage items set.
|
||||
let pallet_hashed_prefix = twox_128(Example::name().as_bytes());
|
||||
@@ -2271,14 +2271,14 @@ fn pallet_on_chain_storage_version_initializes_correctly() {
|
||||
// version.
|
||||
Executive::execute_on_runtime_upgrade();
|
||||
|
||||
// Check that the storage version was initialized to the current version
|
||||
// Check that the storage version was initialized to the in-code version
|
||||
let on_chain_version_after = StorageVersion::get::<Example>();
|
||||
assert_eq!(on_chain_version_after, current_version);
|
||||
assert_eq!(on_chain_version_after, in_code_version);
|
||||
});
|
||||
|
||||
// Pallet with no current storage version should have the on-chain version initialized to 0.
|
||||
// Pallet with no in-code storage version should have the on-chain version initialized to 0.
|
||||
TestExternalities::default().execute_with(|| {
|
||||
// Example4 current_storage_version is NoStorageVersionSet.
|
||||
// Example4 in_code_storage_version is NoStorageVersionSet.
|
||||
|
||||
// Check the pallet has no storage items set.
|
||||
let pallet_hashed_prefix = twox_128(Example4::name().as_bytes());
|
||||
@@ -2308,7 +2308,7 @@ fn post_runtime_upgrade_detects_storage_version_issues() {
|
||||
|
||||
impl OnRuntimeUpgrade for CustomUpgrade {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
Example2::current_storage_version().put::<Example2>();
|
||||
Example2::in_code_storage_version().put::<Example2>();
|
||||
|
||||
Default::default()
|
||||
}
|
||||
@@ -2351,14 +2351,14 @@ fn post_runtime_upgrade_detects_storage_version_issues() {
|
||||
>;
|
||||
|
||||
TestExternalities::default().execute_with(|| {
|
||||
// Set the on-chain version to one less than the current version for `Example`, simulating a
|
||||
// Set the on-chain version to one less than the in-code version for `Example`, simulating a
|
||||
// forgotten migration
|
||||
StorageVersion::new(9).put::<Example2>();
|
||||
|
||||
// The version isn't changed, we should detect it.
|
||||
assert!(
|
||||
Executive::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost).unwrap_err() ==
|
||||
"On chain and current storage version do not match. Missing runtime upgrade?"
|
||||
"On chain and in-code storage version do not match. Missing runtime upgrade?"
|
||||
.into()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ mod pallet {
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
if Self::current_storage_version() != Self::on_chain_storage_version() {
|
||||
if Self::in_code_storage_version() != Self::on_chain_storage_version() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
error[E0369]: binary operation `!=` cannot be applied to type `NoStorageVersionSet`
|
||||
--> tests/pallet_ui/compare_unset_storage_version.rs:32:39
|
||||
|
|
||||
32 | if Self::current_storage_version() != Self::on_chain_storage_version() {
|
||||
32 | if Self::in_code_storage_version() != Self::on_chain_storage_version() {
|
||||
| ------------------------------- ^^ -------------------------------- StorageVersion
|
||||
| |
|
||||
| NoStorageVersionSet
|
||||
|
||||
@@ -525,7 +525,7 @@ pub mod pallet {
|
||||
#[pallet::constant]
|
||||
type DbWeight: Get<RuntimeDbWeight>;
|
||||
|
||||
/// Get the chain's current version.
|
||||
/// Get the chain's in-code version.
|
||||
#[pallet::constant]
|
||||
type Version: Get<RuntimeVersion>;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
/// The current storage version.
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);
|
||||
|
||||
#[pallet::pallet]
|
||||
|
||||
Reference in New Issue
Block a user