From d57afb6c4284bf462317742f82479dee48f2f319 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Mar 2024 14:38:53 +0200 Subject: [PATCH 01/21] Copy over files before force-push Signed-off-by: Oliver Tale-Yazdi --- Cargo.toml | 2 + .../multi-block-migrations/pallet/Cargo.toml | 30 +++++++ .../multi-block-migrations/pallet/src/lib.rs | 84 +++++++++++++++++ .../pallet/src/migrations/mod.rs | 41 +++++++++ .../pallet/src/migrations/v1.rs | 90 +++++++++++++++++++ .../multi-block-migrations/runtime/Cargo.toml | 35 ++++++++ .../multi-block-migrations/runtime/src/lib.rs | 75 ++++++++++++++++ 7 files changed, 357 insertions(+) create mode 100644 substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml create mode 100644 substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs create mode 100644 substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs create mode 100644 substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs create mode 100644 substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml create mode 100644 substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 5eeac5978270..34d5d41a9130 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -330,6 +330,8 @@ members = [ "substrate/frame/examples/dev-mode", "substrate/frame/examples/frame-crate", "substrate/frame/examples/kitchensink", + "substrate/frame/examples/multi-block-migrations/pallet", + "substrate/frame/examples/multi-block-migrations/runtime", "substrate/frame/examples/offchain-worker", "substrate/frame/examples/single-block-migrations", "substrate/frame/examples/split", diff --git a/substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml b/substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml new file mode 100644 index 000000000000..90d2b9ce734c --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "pallet-examples-pallet-mbm" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "Example FRAME pallet for multi-block migrations" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false } +frame-support = { version = "4.0.0-dev", path = "../../../support", default-features = false } +frame-system = { version = "4.0.0-dev", path = "../../../system", default-features = false } +log = { version = "0.4.20", default-features = false } +scale-info = { version = "2.10.0", default-features = false } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", +] diff --git a/substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs b/substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs new file mode 100644 index 000000000000..d2d889355a8e --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs @@ -0,0 +1,84 @@ +// 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. + +//! # Multi-Block Migrations Example Pallet +//! +//! This pallet serves as a minimal example of a pallet that uses the [Multi-Block Migrations +//! Framework](frame_support::migrations). +//! +//! ## Introduction and Purpose +//! +//! The primary purpose of this pallet is to demonstrate the concept of Multi-Block Migrations in +//! Substrate. It showcases the migration of values from in the +//! [`StoredValue`](`pallet::StoredValue`) storage map a `u32` to a `u64` data type using the +//! [`SteppedMigration`](`frame_support::migrations::SteppedMigration`) implementation from the +//! [`migrations::v1`] module. +//! +//! The [`StoredValue`](`pallet::StoredValue`) storage item is defined in this `pallet`, and is +//! aliased to [`old::StoredValue`](`migrations::v1::old::StoredValue`) in the [`migrations::v1`] +//! module. +//! +//! ## How to Read the Documentation +//! +//! To access and navigate this documentation in your browser, use the following command: +//! +//! - `cargo doc --package pallet-examples-pallet-mbm --open` +//! +//! This documentation is organized to help you understand the pallet's components, features, and +//! migration process. +//! +//! ## Example Usage +//! +//! To use this pallet and understand multi-block migrations, you can refer to the +//! [`migrations::v1`] module, which contains a step-by-step migration example. +//! +//! ## Pallet Structure +//! +//! The pallet is structured as follows: +//! +//! - [`migrations`]: Contains migration-related modules and migration logic. +//! - [`v1`](`migrations::v1`): Demonstrates the migration process for changing the data type in +//! the storage map. +//! - [`pallet`]: Defines the pallet configuration and storage items. +//! +//! ## Migration Safety +//! +//! When working with migrations, it's crucial to ensure the safety of your migrations. The +//! preferred tool to test migrations is +//! [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli). Support will be added to +//! dry-run MBMs once they are stable +//! (tracked: ). +//! +//! You can also consider using [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) for testing +//! your migrations in addition to `try-runtime-cli`. + +pub mod migrations; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{pallet_prelude::StorageMap, Blake2_128Concat}; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + /// Define a storage item to illustrate multi-block migrations. + #[pallet::storage] + pub type StoredValue = StorageMap<_, Blake2_128Concat, u32, u64>; +} diff --git a/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs b/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs new file mode 100644 index 000000000000..3da1c1a8a394 --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs @@ -0,0 +1,41 @@ +// 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 codec::{Decode, Encode, MaxEncodedLen}; + +/// # Multi-Block Migrations Module +/// +/// This module showcases a simple use of the multi-block migrations framework. +pub mod v1; + +/// Migration identifier. +/// +/// Used to identify a migration across all pallets. This identifier is essential because +/// the [`SteppedMigration::Identifier`](`frame_support::migrations::SteppedMigration::Identifier`) +/// needs to be globally unique. +#[derive(MaxEncodedLen, Encode, Decode)] +pub struct MigrationIdentifier { + pallet_identifier: [u8; 16], + version_from: u8, + version_to: u8, +} + +/// A unique identifier across all pallets. +/// +/// This constant represents a unique identifier for the migrations of this pallet. +/// It helps differentiate migrations for this pallet from those of others. +const PALLET_MIGRATIONS_ID: &[u8; 26] = b"pallet-examples-pallet-mbm"; diff --git a/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs b/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs new file mode 100644 index 000000000000..d299cac85580 --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs @@ -0,0 +1,90 @@ +// 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. + +//! # Multi-Block Migration v1 +//! +//! This module showcases a simple migration that iterates over the values in the +//! [`old::StoredValue`](`crate::migrations::v1::old::StoredValue`) storage map, transforms them, +//! and inserts them into the [`StoredValue`](`crate::pallet::StoredValue`) storage map. + +use super::{MigrationIdentifier, PALLET_MIGRATIONS_ID}; +use crate::pallet::{Config, StoredValue}; +use frame_support::{ + migrations::{SteppedMigration, SteppedMigrationError}, + pallet_prelude::PhantomData, + weights::WeightMeter, + Hashable, +}; + +/// Module containing the OLD storage items. +/// +/// Before running this migration, the storage alias defined here represents the +/// `on_chain` storage. +// This module is public only for the purposes of linking it in the documentation. It is not +// intended to be used by any other code. +pub mod old { + use super::Config; + use crate::pallet::Pallet; + use frame_support::{storage_alias, Blake2_128Concat}; + + #[storage_alias] + /// The storage item that is being migrated from. + pub type StoredValue = StorageMap, Blake2_128Concat, u32, u32>; +} + +pub struct LazyMigrationV1(PhantomData); +impl SteppedMigration for LazyMigrationV1 { + type Cursor = u32; + type Identifier = MigrationIdentifier; + + /// The identifier of this migration. Which should be globally unique. + fn id() -> Self::Identifier { + MigrationIdentifier { + pallet_identifier: (*PALLET_MIGRATIONS_ID).twox_128(), + version_from: 0, + version_to: 1, + } + } + + /// The actual logic of the migration. + /// + /// This function is called repeatedly until it returns `Ok(None)`, indicating that the + /// migration is complete. Ideally, the migration should be designed in such a way that each + /// step consumes as much weight as possible. However, this is simplified to perform one + /// stored value mutation per block. + fn step( + cursor: Option, + _meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + let mut iter = if let Some(last_key) = cursor { + // If a cursor is provided, start iterating from the stored value + // corresponding to the last key processed in the previous step. + old::StoredValue::::iter_from(old::StoredValue::::hashed_key_for(last_key)) + } else { + // If no cursor is provided, start iterating from the beginning. + old::StoredValue::::iter() + }; + + if let Some((hash, value)) = iter.next() { + // If there's a next item in the iterator, perform the migration. + StoredValue::::insert(hash, value as u64); + Ok(Some(hash)) // Return the processed key as the new cursor. + } else { + Ok(None) // Signal that the migration is complete (no more items to process). + } + } +} diff --git a/substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml b/substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml new file mode 100644 index 000000000000..6a57ce3f4f76 --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "pallet-examples-runtime-mbm" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "Example runtime for multi-block migrations" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +substrate-wasm-builder = { path = "../../../../utils/wasm-builder", optional = true } + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false } +frame-support = { version = "4.0.0-dev", path = "../../../support", default-features = false } +frame-system = { version = "4.0.0-dev", path = "../../../system", default-features = false } +pallet-migrations = { version = "1.0.0", path = "../../../migrations", default-features = false } +pallet-examples-pallet-mbm = { version = "0.1.0", path = "../pallet", default-features = false } +scale-info = { version = "2.10.0", default-features = false } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "pallet-examples-pallet-mbm/std", + "pallet-migrations/std", + "scale-info/std", +] diff --git a/substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs b/substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs new file mode 100644 index 000000000000..95b2fe50eb09 --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs @@ -0,0 +1,75 @@ +// 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. + +//! # Minimal Example Runtime Using Multi-Block Migrations Framework +//! +//! This runtime provides a minimal example of how to use the +//! [Multi-Block Migrations Framework](frame_support::migrations) and the [`pallet_migrations`]. +//! The core part of this runtime is the [`pallet_migrations::Config`] implementation, where you +//! define the migrations you want to run using the [`Migrations`] type. +//! +//! ## How to Read the Documentation +//! +//! To access and navigate this documentation in your browser, use the following command: +//! +//! - `cargo doc --package pallet-examples-runtime-mbm --open` +//! +//! This documentation is organized to help you understand how this runtime is configured and how +//! it uses the Multi-Block Migrations Framework. + +use frame_support::{construct_runtime, derive_impl, traits::ConstU32}; +use pallet_examples_pallet_mbm::{migrations::*, pallet}; + +type Block = frame_system::mocking::MockBlock; + +impl pallet::Config for Runtime {} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + /// The type that implements + /// [`SteppedMigrations`](`frame_support::migrations::SteppedMigrations`). + /// + /// In this tuple, you list the migrations to run. In this example, we have a single migration, + /// [`v1::LazyMigrationV1`], which is the second version of the storage migration from the + /// [`pallet-examples-pallet-mbm`](`pallet_examples_pallet_mbm`) crate. + /// + /// # Example + /// ```ignore + /// type Migrations = (v1::Migration, v2::Migration, v3::Migration); + /// ``` + type Migrations = (v1::LazyMigrationV1,); + type CursorMaxLen = ConstU32<256>; + type IdentifierMaxLen = ConstU32<256>; + type OnMigrationUpdate = (); + type ServiceWeight = (); + type WeightInfo = (); +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +// Construct the runtime using the `construct_runtime` macro, specifying the pallet_migrations. +construct_runtime! { + pub struct Runtime + { + System: frame_system, + Pallet: pallet, + Migrations: pallet_migrations, + } +} From f99895635c663b1c9ec60c5c9bd02f83a8c5ba36 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Mar 2024 18:36:49 +0200 Subject: [PATCH 02/21] Refactor Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 16 +++++ Cargo.toml | 3 +- substrate/bin/node/runtime/Cargo.toml | 3 + substrate/bin/node/runtime/src/lib.rs | 6 ++ .../{pallet => }/Cargo.toml | 18 ++++- .../multi-block-migrations/runtime/Cargo.toml | 35 ---------- .../{pallet => }/src/lib.rs | 7 +- .../{pallet => }/src/migrations/mod.rs | 20 ++---- .../src/migrations/v1/benchmarks.rs | 36 ++++++++++ .../v1.rs => src/migrations/v1/mod.rs} | 43 +++++++----- .../src/migrations/v1/weights.rs | 68 +++++++++++++++++++ .../{runtime/src/lib.rs => src/mock.rs} | 33 ++++++--- substrate/frame/support/src/migrations.rs | 10 +++ substrate/primitives/runtime/Cargo.toml | 1 + 14 files changed, 214 insertions(+), 85 deletions(-) rename substrate/frame/examples/multi-block-migrations/{pallet => }/Cargo.toml (50%) delete mode 100644 substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml rename substrate/frame/examples/multi-block-migrations/{pallet => }/src/lib.rs (95%) rename substrate/frame/examples/multi-block-migrations/{pallet => }/src/migrations/mod.rs (65%) create mode 100644 substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs rename substrate/frame/examples/multi-block-migrations/{pallet/src/migrations/v1.rs => src/migrations/v1/mod.rs} (71%) create mode 100644 substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs rename substrate/frame/examples/multi-block-migrations/{runtime/src/lib.rs => src/mock.rs} (75%) diff --git a/Cargo.lock b/Cargo.lock index 074b657e767b..1749df5cc2fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7077,6 +7077,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", + "pallet-example-pallet-mbm", "pallet-example-tasks", "pallet-fast-unstake", "pallet-glutton", @@ -9877,6 +9878,20 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-example-pallet-mbm" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-migrations", + "parity-scale-codec", + "scale-info", + "sp-io", +] + [[package]] name = "pallet-example-single-block-migrations" version = "0.0.1" @@ -18972,6 +18987,7 @@ dependencies = [ "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-weights", + "static_assertions", "substrate-test-runtime-client", "zstd 0.12.4", ] diff --git a/Cargo.toml b/Cargo.toml index 34d5d41a9130..8d2cb6ca665d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -330,8 +330,7 @@ members = [ "substrate/frame/examples/dev-mode", "substrate/frame/examples/frame-crate", "substrate/frame/examples/kitchensink", - "substrate/frame/examples/multi-block-migrations/pallet", - "substrate/frame/examples/multi-block-migrations/runtime", + "substrate/frame/examples/multi-block-migrations", "substrate/frame/examples/offchain-worker", "substrate/frame/examples/single-block-migrations", "substrate/frame/examples/split", diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 4d342ceb460a..5a1f3b264517 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -89,6 +89,7 @@ pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", defaul pallet-example-tasks = { path = "../../../frame/examples/tasks", default-features = false } pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false } pallet-migrations = { path = "../../../frame/migrations", default-features = false } +pallet-example-pallet-mbm = { path = "../../../frame/examples/multi-block-migrations", default-features = false } pallet-nis = { path = "../../../frame/nis", default-features = false } pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } pallet-im-online = { path = "../../../frame/im-online", default-features = false } @@ -267,6 +268,7 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", + "pallet-example-pallet-mbm/std" ] runtime-benchmarks = [ "frame-benchmarking-pallet-pov/runtime-benchmarks", @@ -342,6 +344,7 @@ runtime-benchmarks = [ "pallet-whitelist/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "pallet-example-pallet-mbm/runtime-benchmarks" ] try-runtime = [ "frame-benchmarking-pallet-pov/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index ca7e14f6eb16..17172a268519 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -320,6 +320,8 @@ impl pallet_example_tasks::Config for Runtime { type WeightInfo = pallet_example_tasks::weights::SubstrateWeight; } +impl pallet_example_pallet_mbm::Config for Runtime {} + impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -2438,6 +2440,9 @@ mod runtime { #[runtime::pallet_index(77)] pub type SkipFeelessPayment = pallet_skip_feeless_payment; + + #[runtime::pallet_index(78)] + pub type PalletExampleMbms = pallet_example_pallet_mbm; } /// The address format for describing accounts. @@ -2596,6 +2601,7 @@ mod benches { [pallet_whitelist, Whitelist] [pallet_tx_pause, TxPause] [pallet_safe_mode, SafeMode] + [pallet_example_pallet_mbm, PalletExampleMbms] ); } diff --git a/substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml similarity index 50% rename from substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml rename to substrate/frame/examples/multi-block-migrations/Cargo.toml index 90d2b9ce734c..801d1c4f2d37 100644 --- a/substrate/frame/examples/multi-block-migrations/pallet/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-examples-pallet-mbm" +name = "pallet-example-pallet-mbm" version = "0.1.0" authors.workspace = true edition.workspace = true @@ -14,10 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false } -frame-support = { version = "4.0.0-dev", path = "../../../support", default-features = false } -frame-system = { version = "4.0.0-dev", path = "../../../system", default-features = false } +pallet-migrations = { path = "../../migrations", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } log = { version = "0.4.20", default-features = false } scale-info = { version = "2.10.0", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } [features] default = [ "std" ] @@ -27,4 +30,13 @@ std = [ "frame-system/std", "log/std", "scale-info/std", + "frame-benchmarking?/std", + "pallet-migrations/std", + "sp-io/std" +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks" ] diff --git a/substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml b/substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml deleted file mode 100644 index 6a57ce3f4f76..000000000000 --- a/substrate/frame/examples/multi-block-migrations/runtime/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "pallet-examples-runtime-mbm" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -description = "Example runtime for multi-block migrations" -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[build-dependencies] -substrate-wasm-builder = { path = "../../../../utils/wasm-builder", optional = true } - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false } -frame-support = { version = "4.0.0-dev", path = "../../../support", default-features = false } -frame-system = { version = "4.0.0-dev", path = "../../../system", default-features = false } -pallet-migrations = { version = "1.0.0", path = "../../../migrations", default-features = false } -pallet-examples-pallet-mbm = { version = "0.1.0", path = "../pallet", default-features = false } -scale-info = { version = "2.10.0", default-features = false } - -[features] -default = [ "std" ] -std = [ - "codec/std", - "frame-support/std", - "frame-system/std", - "pallet-examples-pallet-mbm/std", - "pallet-migrations/std", - "scale-info/std", -] diff --git a/substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs b/substrate/frame/examples/multi-block-migrations/src/lib.rs similarity index 95% rename from substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs rename to substrate/frame/examples/multi-block-migrations/src/lib.rs index d2d889355a8e..5b78905e85c1 100644 --- a/substrate/frame/examples/multi-block-migrations/pallet/src/lib.rs +++ b/substrate/frame/examples/multi-block-migrations/src/lib.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![cfg_attr(not(feature = "std"), no_std)] + //! # Multi-Block Migrations Example Pallet //! //! This pallet serves as a minimal example of a pallet that uses the [Multi-Block Migrations @@ -67,6 +69,9 @@ //! your migrations in addition to `try-runtime-cli`. pub mod migrations; +mod mock; + +pub use pallet::*; #[frame_support::pallet] pub mod pallet { @@ -80,5 +85,5 @@ pub mod pallet { /// Define a storage item to illustrate multi-block migrations. #[pallet::storage] - pub type StoredValue = StorageMap<_, Blake2_128Concat, u32, u64>; + pub type MyMap = StorageMap<_, Blake2_128Concat, u32, u64>; } diff --git a/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs similarity index 65% rename from substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs rename to substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs index 3da1c1a8a394..99f903ab4d01 100644 --- a/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs @@ -15,27 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use codec::{Decode, Encode, MaxEncodedLen}; - /// # Multi-Block Migrations Module /// /// This module showcases a simple use of the multi-block migrations framework. pub mod v1; -/// Migration identifier. -/// -/// Used to identify a migration across all pallets. This identifier is essential because -/// the [`SteppedMigration::Identifier`](`frame_support::migrations::SteppedMigration::Identifier`) -/// needs to be globally unique. -#[derive(MaxEncodedLen, Encode, Decode)] -pub struct MigrationIdentifier { - pallet_identifier: [u8; 16], - version_from: u8, - version_to: u8, -} - /// A unique identifier across all pallets. /// /// This constant represents a unique identifier for the migrations of this pallet. -/// It helps differentiate migrations for this pallet from those of others. -const PALLET_MIGRATIONS_ID: &[u8; 26] = b"pallet-examples-pallet-mbm"; +/// It helps differentiate migrations for this pallet from those of others. Note that we don't +/// directly pull the crate name from the environment, since that would change if the crate were +/// ever to be renamed and could cause historic migrations to run again. +pub const PALLET_MIGRATIONS_ID: &[u8; 26] = b"pallet-examples-pallet-mbm"; diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs new file mode 100644 index 000000000000..3be78d43649e --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs @@ -0,0 +1,36 @@ +#![cfg(feature = "runtime-benchmarks")] + +use crate::{ + migrations::{ + v1, + v1::{weights, weights::WeightInfo}, + }, + Config, Pallet, +}; +use frame_benchmarking::v2::*; +use frame_support::{migrations::SteppedMigration, weights::WeightMeter}; + +#[benchmarks] +mod benches { + use super::*; + + /// Benchmark a single step of the `v1::LazyMigrationV1` migration. + #[benchmark] + fn step() { + v1::old::MyMap::::insert(0, 0); + // Check that the old storage is undecodable: + assert!(crate::MyMap::::get(0).is_none()); + let mut meter = WeightMeter::new(); + + #[block] + { + v1::LazyMigrationV1::::step(None, &mut meter).unwrap(); + } + + // Check that the new storage is decodable: + assert_eq!(crate::MyMap::::get(0), Some(0)); + assert_eq!(meter.consumed(), weights::SubstrateWeight::::step()); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); +} diff --git a/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs similarity index 71% rename from substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs rename to substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index d299cac85580..0941f6e4e6bd 100644 --- a/substrate/frame/examples/multi-block-migrations/pallet/src/migrations/v1.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -21,14 +21,17 @@ //! [`old::StoredValue`](`crate::migrations::v1::old::StoredValue`) storage map, transforms them, //! and inserts them into the [`StoredValue`](`crate::pallet::StoredValue`) storage map. -use super::{MigrationIdentifier, PALLET_MIGRATIONS_ID}; -use crate::pallet::{Config, StoredValue}; +use super::PALLET_MIGRATIONS_ID; +use crate::pallet::{Config, MyMap}; use frame_support::{ - migrations::{SteppedMigration, SteppedMigrationError}, + migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, pallet_prelude::PhantomData, weights::WeightMeter, - Hashable, }; +use weights::WeightInfo; + +mod benchmarks; +pub mod weights; /// Module containing the OLD storage items. /// @@ -43,21 +46,18 @@ pub mod old { #[storage_alias] /// The storage item that is being migrated from. - pub type StoredValue = StorageMap, Blake2_128Concat, u32, u32>; + pub type MyMap = StorageMap, Blake2_128Concat, u32, u32>; } +/// Migrates the items of the [`crate::MyMap`] map from `u32` to `u64`. pub struct LazyMigrationV1(PhantomData); impl SteppedMigration for LazyMigrationV1 { type Cursor = u32; - type Identifier = MigrationIdentifier; + type Identifier = MigrationId<26>; /// The identifier of this migration. Which should be globally unique. fn id() -> Self::Identifier { - MigrationIdentifier { - pallet_identifier: (*PALLET_MIGRATIONS_ID).twox_128(), - version_from: 0, - version_to: 1, - } + MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 0, version_to: 1 } } /// The actual logic of the migration. @@ -68,21 +68,28 @@ impl SteppedMigration for LazyMigrationV1 { /// stored value mutation per block. fn step( cursor: Option, - _meter: &mut WeightMeter, + meter: &mut WeightMeter, ) -> Result, SteppedMigrationError> { + let required = weights::SubstrateWeight::::step(); + if meter.try_consume(required).is_err() { + return Err(SteppedMigrationError::InsufficientWeight { required }) + } + let mut iter = if let Some(last_key) = cursor { // If a cursor is provided, start iterating from the stored value // corresponding to the last key processed in the previous step. - old::StoredValue::::iter_from(old::StoredValue::::hashed_key_for(last_key)) + old::MyMap::::iter_from(old::MyMap::::hashed_key_for(last_key)) } else { // If no cursor is provided, start iterating from the beginning. - old::StoredValue::::iter() + old::MyMap::::iter() }; - if let Some((hash, value)) = iter.next() { - // If there's a next item in the iterator, perform the migration. - StoredValue::::insert(hash, value as u64); - Ok(Some(hash)) // Return the processed key as the new cursor. + // If there's a next item in the iterator, perform the migration. + if let Some((last_key, value)) = iter.next() { + // Migrate the inner value: u32 -> u64. + let value = value as u64; + MyMap::::insert(last_key, value); + Ok(Some(last_key)) // Return the processed key as the new cursor. } else { Ok(None) // Signal that the migration is complete (no more items to process). } diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs new file mode 100644 index 000000000000..1f5efcb6b3ec --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs @@ -0,0 +1,68 @@ + +//! Autogenerated weights for `pallet_example_pallet_mbm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Olivers-MBP`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` + +// Executed Command: +// polkadot-omni-bencher +// v1 +// benchmark +// pallet +// --runtime +// target/release/wbuild/kitchensink-runtime/kitchensink_runtime.compact.compressed.wasm +// --pallet +// pallet_example_pallet_mbm +// --extrinsic +// +// --template +// substrate/.maintain/frame-weight-template.hbs +// --output +// substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_example_pallet_mbm`. +pub trait WeightInfo { + fn step() -> Weight; +} + +/// Weights for `pallet_example_pallet_mbm` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) + /// Proof: `PalletExampleMbms::MyMap` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + fn step() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `5996` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(8_000_000, 5996) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) + /// Proof: `PalletExampleMbms::MyMap` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + fn step() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `5996` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(8_000_000, 5996) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs similarity index 75% rename from substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs rename to substrate/frame/examples/multi-block-migrations/src/mock.rs index 95b2fe50eb09..8dce9adccd9f 100644 --- a/substrate/frame/examples/multi-block-migrations/runtime/src/lib.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -15,7 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Minimal Example Runtime Using Multi-Block Migrations Framework +#![cfg(test)] + +//! # Minimal Example Runtime Using Multi-Block Migrations Framework. //! //! This runtime provides a minimal example of how to use the //! [Multi-Block Migrations Framework](frame_support::migrations) and the [`pallet_migrations`]. @@ -31,12 +33,13 @@ //! This documentation is organized to help you understand how this runtime is configured and how //! it uses the Multi-Block Migrations Framework. -use frame_support::{construct_runtime, derive_impl, traits::ConstU32}; -use pallet_examples_pallet_mbm::{migrations::*, pallet}; +use frame_support::{ + construct_runtime, derive_impl, migrations::FreezeChainOnFailedMigration, traits::ConstU32, +}; type Block = frame_system::mocking::MockBlock; -impl pallet::Config for Runtime {} +impl crate::Config for Runtime {} impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -45,23 +48,28 @@ impl pallet_migrations::Config for Runtime { /// /// In this tuple, you list the migrations to run. In this example, we have a single migration, /// [`v1::LazyMigrationV1`], which is the second version of the storage migration from the - /// [`pallet-examples-pallet-mbm`](`pallet_examples_pallet_mbm`) crate. + /// [`pallet-example-pallet-mbm`](`pallet_example_pallet_mbm`) crate. /// /// # Example /// ```ignore /// type Migrations = (v1::Migration, v2::Migration, v3::Migration); /// ``` + #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = (v1::LazyMigrationV1,); - type CursorMaxLen = ConstU32<256>; + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; - type OnMigrationUpdate = (); - type ServiceWeight = (); + type MigrationStatusHandler = (); + type FailedMigrationHandler = FreezeChainOnFailedMigration; + type MaxServiceWeight = (); type WeightInfo = (); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; + type MultiBlockMigrator = Migrator; } // Construct the runtime using the `construct_runtime` macro, specifying the pallet_migrations. @@ -69,7 +77,12 @@ construct_runtime! { pub struct Runtime { System: frame_system, - Pallet: pallet, - Migrations: pallet_migrations, + Pallet: crate, + Migrator: pallet_migrations, } } + +#[cfg(all(test, feature = "runtime-benchmarks"))] +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 2ceab44cb16b..e5f4d16e011b 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -441,6 +441,16 @@ pub enum SteppedMigrationError { Failed, } +/// A generic migration identifier that can be used by MBMs. +/// +/// It is not required that migrations use this identifier type, but it can help. +#[derive(MaxEncodedLen, Encode, Decode)] +pub struct MigrationId { + pub pallet_id: [u8; N], + pub version_from: u8, + pub version_to: u8, +} + /// Notification handler for status updates regarding Multi-Block-Migrations. #[impl_trait_for_tuples::impl_for_tuples(8)] pub trait MigrationStatusHandler { diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index cacfc0597229..6d1d73423e13 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -33,6 +33,7 @@ sp-io = { path = "../io", default-features = false } sp-std = { path = "../std", default-features = false } sp-weights = { path = "../weights", default-features = false } docify = { version = "0.2.7" } +static_assertions = "1.1.0" simple-mermaid = { version = "0.1.1", optional = true } From 36056f97f6d325d92641980160eb056c25f3b697 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Mar 2024 21:13:41 +0200 Subject: [PATCH 03/21] Refactor Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 24 +++--- substrate/bin/node/runtime/Cargo.toml | 6 +- substrate/bin/node/runtime/src/lib.rs | 6 +- .../multi-block-migrations/Cargo.toml | 2 +- .../multi-block-migrations/src/lib.rs | 11 +-- .../src/migrations/mod.rs | 2 +- .../src/migrations/v1/benchmarks.rs | 2 - .../src/migrations/v1/mod.rs | 61 ++++++++------ .../src/migrations/v1/tests.rs | 82 +++++++++++++++++++ .../src/migrations/v1/weights.rs | 8 +- .../src/migrations/weights.rs | 63 ++++++++++++++ .../multi-block-migrations/src/mock.rs | 15 ++-- substrate/frame/migrations/src/lib.rs | 6 +- .../frame/migrations/src/mock_helpers.rs | 2 +- substrate/frame/support/src/migrations.rs | 3 + 15 files changed, 228 insertions(+), 65 deletions(-) create mode 100644 substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs create mode 100644 substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 1749df5cc2fa..2c6e9a2dd1b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7077,7 +7077,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", - "pallet-example-pallet-mbm", + "pallet-example-mbm", "pallet-example-tasks", "pallet-fast-unstake", "pallet-glutton", @@ -9862,34 +9862,34 @@ dependencies = [ ] [[package]] -name = "pallet-example-offchain-worker" -version = "28.0.0" +name = "pallet-example-mbm" +version = "0.1.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", - "lite-json", "log", + "pallet-migrations", "parity-scale-codec", "scale-info", - "sp-core", "sp-io", - "sp-keystore", - "sp-runtime", - "sp-std 14.0.0", ] [[package]] -name = "pallet-example-pallet-mbm" -version = "0.1.0" +name = "pallet-example-offchain-worker" +version = "28.0.0" dependencies = [ - "frame-benchmarking", "frame-support", "frame-system", + "lite-json", "log", - "pallet-migrations", "parity-scale-codec", "scale-info", + "sp-core", "sp-io", + "sp-keystore", + "sp-runtime", + "sp-std 14.0.0", ] [[package]] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 5a1f3b264517..00f6e230852b 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -89,7 +89,7 @@ pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", defaul pallet-example-tasks = { path = "../../../frame/examples/tasks", default-features = false } pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false } pallet-migrations = { path = "../../../frame/migrations", default-features = false } -pallet-example-pallet-mbm = { path = "../../../frame/examples/multi-block-migrations", default-features = false } +pallet-example-mbm = { path = "../../../frame/examples/multi-block-migrations", default-features = false } pallet-nis = { path = "../../../frame/nis", default-features = false } pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } pallet-im-online = { path = "../../../frame/im-online", default-features = false } @@ -268,7 +268,7 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", - "pallet-example-pallet-mbm/std" + "pallet-example-mbm/std" ] runtime-benchmarks = [ "frame-benchmarking-pallet-pov/runtime-benchmarks", @@ -344,7 +344,7 @@ runtime-benchmarks = [ "pallet-whitelist/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", - "pallet-example-pallet-mbm/runtime-benchmarks" + "pallet-example-mbm/runtime-benchmarks" ] try-runtime = [ "frame-benchmarking-pallet-pov/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 17172a268519..deee5c087297 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -320,7 +320,7 @@ impl pallet_example_tasks::Config for Runtime { type WeightInfo = pallet_example_tasks::weights::SubstrateWeight; } -impl pallet_example_pallet_mbm::Config for Runtime {} +impl pallet_example_mbm::Config for Runtime {} impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -2442,7 +2442,7 @@ mod runtime { pub type SkipFeelessPayment = pallet_skip_feeless_payment; #[runtime::pallet_index(78)] - pub type PalletExampleMbms = pallet_example_pallet_mbm; + pub type PalletExampleMbms = pallet_example_mbm; } /// The address format for describing accounts. @@ -2601,7 +2601,7 @@ mod benches { [pallet_whitelist, Whitelist] [pallet_tx_pause, TxPause] [pallet_safe_mode, SafeMode] - [pallet_example_pallet_mbm, PalletExampleMbms] + [pallet_example_mbm, PalletExampleMbms] ); } diff --git a/substrate/frame/examples/multi-block-migrations/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml index 801d1c4f2d37..c1241efcc484 100644 --- a/substrate/frame/examples/multi-block-migrations/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-example-pallet-mbm" +name = "pallet-example-mbm" version = "0.1.0" authors.workspace = true edition.workspace = true diff --git a/substrate/frame/examples/multi-block-migrations/src/lib.rs b/substrate/frame/examples/multi-block-migrations/src/lib.rs index 5b78905e85c1..57799cab7732 100644 --- a/substrate/frame/examples/multi-block-migrations/src/lib.rs +++ b/substrate/frame/examples/multi-block-migrations/src/lib.rs @@ -20,25 +20,26 @@ //! # Multi-Block Migrations Example Pallet //! //! This pallet serves as a minimal example of a pallet that uses the [Multi-Block Migrations -//! Framework](frame_support::migrations). +//! Framework](frame_support::migrations). You can observe how to configure it in a runtime in the +//! `kitchensink-runtime` crate. //! //! ## Introduction and Purpose //! //! The primary purpose of this pallet is to demonstrate the concept of Multi-Block Migrations in //! Substrate. It showcases the migration of values from in the -//! [`StoredValue`](`pallet::StoredValue`) storage map a `u32` to a `u64` data type using the +//! [`MyMap`](`pallet::MyMap`) storage map a `u32` to a `u64` data type using the //! [`SteppedMigration`](`frame_support::migrations::SteppedMigration`) implementation from the //! [`migrations::v1`] module. //! -//! The [`StoredValue`](`pallet::StoredValue`) storage item is defined in this `pallet`, and is -//! aliased to [`old::StoredValue`](`migrations::v1::old::StoredValue`) in the [`migrations::v1`] +//! The [`MyMap`](`pallet::MyMap`) storage item is defined in this `pallet`, and is +//! aliased to [`old::MyMap`](`migrations::v1::old::MyMap`) in the [`migrations::v1`] //! module. //! //! ## How to Read the Documentation //! //! To access and navigate this documentation in your browser, use the following command: //! -//! - `cargo doc --package pallet-examples-pallet-mbm --open` +//! - `cargo doc --package pallet-example-mbm --open` //! //! This documentation is organized to help you understand the pallet's components, features, and //! migration process. diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs index 99f903ab4d01..fa6e1f202cb2 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/mod.rs @@ -26,4 +26,4 @@ pub mod v1; /// It helps differentiate migrations for this pallet from those of others. Note that we don't /// directly pull the crate name from the environment, since that would change if the crate were /// ever to be renamed and could cause historic migrations to run again. -pub const PALLET_MIGRATIONS_ID: &[u8; 26] = b"pallet-examples-pallet-mbm"; +pub const PALLET_MIGRATIONS_ID: &[u8; 18] = b"pallet-example-mbm"; diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs index 3be78d43649e..92373a082ae4 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs @@ -18,8 +18,6 @@ mod benches { #[benchmark] fn step() { v1::old::MyMap::::insert(0, 0); - // Check that the old storage is undecodable: - assert!(crate::MyMap::::get(0).is_none()); let mut meter = WeightMeter::new(); #[block] diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index 0941f6e4e6bd..be6c7e8761d9 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -18,8 +18,8 @@ //! # Multi-Block Migration v1 //! //! This module showcases a simple migration that iterates over the values in the -//! [`old::StoredValue`](`crate::migrations::v1::old::StoredValue`) storage map, transforms them, -//! and inserts them into the [`StoredValue`](`crate::pallet::StoredValue`) storage map. +//! [`old::MyMap`](`crate::migrations::v1::old::MyMap`) storage map, transforms them, +//! and inserts them into the [`MyMap`](`crate::pallet::MyMap`) storage map. use super::PALLET_MIGRATIONS_ID; use crate::pallet::{Config, MyMap}; @@ -28,9 +28,9 @@ use frame_support::{ pallet_prelude::PhantomData, weights::WeightMeter, }; -use weights::WeightInfo; mod benchmarks; +mod tests; pub mod weights; /// Module containing the OLD storage items. @@ -50,10 +50,11 @@ pub mod old { } /// Migrates the items of the [`crate::MyMap`] map from `u32` to `u64`. -pub struct LazyMigrationV1(PhantomData); -impl SteppedMigration for LazyMigrationV1 { +pub struct LazyMigrationV1(PhantomData<(T, W)>); +impl SteppedMigration for LazyMigrationV1 { type Cursor = u32; - type Identifier = MigrationId<26>; + // Without the explicit length here the construction of the ID would not be infallible. + type Identifier = MigrationId<18>; /// The identifier of this migration. Which should be globally unique. fn id() -> Self::Identifier { @@ -67,31 +68,39 @@ impl SteppedMigration for LazyMigrationV1 { /// step consumes as much weight as possible. However, this is simplified to perform one /// stored value mutation per block. fn step( - cursor: Option, + mut cursor: Option, meter: &mut WeightMeter, ) -> Result, SteppedMigrationError> { - let required = weights::SubstrateWeight::::step(); - if meter.try_consume(required).is_err() { - return Err(SteppedMigrationError::InsufficientWeight { required }) + let required = W::step(); + if meter.remaining().any_lt(required) { + return Err(SteppedMigrationError::InsufficientWeight { required }); } - let mut iter = if let Some(last_key) = cursor { - // If a cursor is provided, start iterating from the stored value - // corresponding to the last key processed in the previous step. - old::MyMap::::iter_from(old::MyMap::::hashed_key_for(last_key)) - } else { - // If no cursor is provided, start iterating from the beginning. - old::MyMap::::iter() - }; + loop { + if meter.try_consume(required).is_err() { + break; + } - // If there's a next item in the iterator, perform the migration. - if let Some((last_key, value)) = iter.next() { - // Migrate the inner value: u32 -> u64. - let value = value as u64; - MyMap::::insert(last_key, value); - Ok(Some(last_key)) // Return the processed key as the new cursor. - } else { - Ok(None) // Signal that the migration is complete (no more items to process). + let mut iter = if let Some(last_key) = cursor { + // If a cursor is provided, start iterating from the stored value + // corresponding to the last key processed in the previous step. + old::MyMap::::iter_from(old::MyMap::::hashed_key_for(last_key)) + } else { + // If no cursor is provided, start iterating from the beginning. + old::MyMap::::iter() + }; + + // If there's a next item in the iterator, perform the migration. + if let Some((last_key, value)) = iter.next() { + // Migrate the inner value: u32 -> u64. + let value = value as u64; + MyMap::::insert(last_key, value); + cursor = Some(last_key) // Return the processed key as the new cursor. + } else { + cursor = None; // Signal that the migration is complete (no more items to process). + break + } } + Ok(cursor) } } diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs new file mode 100644 index 000000000000..361f8fbea631 --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs @@ -0,0 +1,82 @@ +// 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(all(test, not(feature = "runtime-benchmarks")))] + +use crate::{ + migrations::{ + v1, + v1::{weights, weights::WeightInfo as _}, + }, + mock::{new_test_ext, AllPalletsWithSystem, MigratorServiceWeight, Runtime as T, System}, +}; +use frame_support::{ + migrations::MultiStepMigrator, + traits::{OnFinalize, OnInitialize, OnRuntimeUpgrade}, +}; +use pallet_migrations::WeightInfo as _; + +#[test] +fn lazy_migration_works() { + new_test_ext().execute_with(|| { + frame_support::__private::sp_tracing::try_init_simple(); + // Insert some values into the old storage map. + for i in 0..1024 { + v1::old::MyMap::::insert(i, i); + } + + // Give it enough weight do do exactly 16 iterations: + let limit = ::WeightInfo::progress_mbms_none() + + pallet_migrations::Pallet::::exec_migration_max_weight() + + weights::SubstrateWeight::::step() * 16; + MigratorServiceWeight::set(&limit); + + System::set_block_number(1); + AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs + + let mut last_decodable = 0; + for block in 2..=65 { + run_to_block(block); + let mut decodable = 0; + for i in 0..1024 { + if crate::MyMap::::get(i).is_some() { + decodable += 1; + } + } + + assert_eq!(decodable, last_decodable + 16); + last_decodable = decodable; + } + + // Check that everything is decodable now: + for i in 0..1024 { + assert_eq!(crate::MyMap::::get(i), Some(i as u64)); + } + }); +} + +fn run_to_block(n: u64) { + assert!(System::block_number() < n); + while System::block_number() < n { + let b = System::block_number(); + AllPalletsWithSystem::on_finalize(b); + // Done by Executive: + ::MultiBlockMigrator::step(); + System::set_block_number(b + 1); + AllPalletsWithSystem::on_initialize(b + 1); + } +} diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs index 1f5efcb6b3ec..b823bf329674 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs @@ -1,5 +1,5 @@ -//! Autogenerated weights for `pallet_example_pallet_mbm` +//! Autogenerated weights for `pallet_example_mbm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 //! DATE: 2024-03-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -15,7 +15,7 @@ // --runtime // target/release/wbuild/kitchensink-runtime/kitchensink_runtime.compact.compressed.wasm // --pallet -// pallet_example_pallet_mbm +// pallet_example_mbm // --extrinsic // // --template @@ -31,12 +31,12 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_example_pallet_mbm`. +/// Weight functions needed for `pallet_example_mbm`. pub trait WeightInfo { fn step() -> Weight; } -/// Weights for `pallet_example_pallet_mbm` using the Substrate node and recommended hardware. +/// Weights for `pallet_example_mbm` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs new file mode 100644 index 000000000000..57a819b02f6e --- /dev/null +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs @@ -0,0 +1,63 @@ + +//! Autogenerated weights for `pallet_example_mbm` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Olivers-MBP`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` + +// Executed Command: +// polkadot-omni-bencher +// v1 +// benchmark +// pallet +// --runtime=target/release/wbuild/kitchensink-runtime/kitchensink_runtime.compact.compressed.wasm +// --pallet=pallet_example_mbm +// --extrinsic= +// --template=substrate/.maintain/frame-weight-template.hbs +// --output=substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_example_mbm`. +pub trait WeightInfo { + fn step() -> Weight; +} + +/// Weights for `pallet_example_mbm` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) + /// Proof: `PalletExampleMbms::MyMap` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + fn step() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `5996` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 5996) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) + /// Proof: `PalletExampleMbms::MyMap` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + fn step() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `5996` + // Minimum execution time: 13_000_000 picoseconds. + Weight::from_parts(14_000_000, 5996) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 8dce9adccd9f..96efed42e92e 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -33,8 +33,10 @@ //! This documentation is organized to help you understand how this runtime is configured and how //! it uses the Multi-Block Migrations Framework. +use crate::{migrations::v1, mock::v1::weights::SubstrateWeight}; use frame_support::{ - construct_runtime, derive_impl, migrations::FreezeChainOnFailedMigration, traits::ConstU32, + construct_runtime, derive_impl, migrations::FreezeChainOnFailedMigration, + pallet_prelude::Weight, traits::ConstU32, }; type Block = frame_system::mocking::MockBlock; @@ -48,24 +50,28 @@ impl pallet_migrations::Config for Runtime { /// /// In this tuple, you list the migrations to run. In this example, we have a single migration, /// [`v1::LazyMigrationV1`], which is the second version of the storage migration from the - /// [`pallet-example-pallet-mbm`](`pallet_example_pallet_mbm`) crate. + /// [`pallet-example-mbm`](`pallet_example_mbm`) crate. /// /// # Example /// ```ignore /// type Migrations = (v1::Migration, v2::Migration, v3::Migration); /// ``` #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = (v1::LazyMigrationV1,); + type Migrations = (v1::LazyMigrationV1>,); #[cfg(feature = "runtime-benchmarks")] type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); type FailedMigrationHandler = FreezeChainOnFailedMigration; - type MaxServiceWeight = (); + type MaxServiceWeight = MigratorServiceWeight; type WeightInfo = (); } +frame_support::parameter_types! { + pub storage MigratorServiceWeight: Weight = Weight::from_parts(100, 100); // do not use in prod +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; @@ -82,7 +88,6 @@ construct_runtime! { } } -#[cfg(all(test, feature = "runtime-benchmarks"))] pub fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new(Default::default()) } diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index cd57d89f440f..bb36a5c1cf2c 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -426,7 +426,8 @@ pub mod pallet { let want = T::MaxServiceWeight::get(); let max = ::BlockWeights::get().max_block; - assert!(want.all_lte(max), "Service weight is larger than a block: {want} > {max}",); + assert!(want.all_lte(max), "Service weight is larger than a block: {want} > {max}"); + assert!(!want.is_zero(), "Service weight cannot be zero"); } // Cursor MEL @@ -726,7 +727,8 @@ impl Pallet { } } - fn exec_migration_max_weight() -> Weight { + /// The maximal weight of calling [`exec_migration`]. + pub fn exec_migration_max_weight() -> Weight { T::WeightInfo::exec_migration_complete() .max(T::WeightInfo::exec_migration_completed()) .max(T::WeightInfo::exec_migration_skipped_historic()) diff --git a/substrate/frame/migrations/src/mock_helpers.rs b/substrate/frame/migrations/src/mock_helpers.rs index c5e23efb4e31..23e20fcd77f8 100644 --- a/substrate/frame/migrations/src/mock_helpers.rs +++ b/substrate/frame/migrations/src/mock_helpers.rs @@ -79,7 +79,7 @@ impl SteppedMigrations for MockedMigrations { let mut count: u32 = cursor.as_ref().and_then(|c| Decode::decode(&mut &c[..]).ok()).unwrap_or(0); - log::debug!("MockedMigration: Step {}", count); + log::debug!("MockedMigration: Step {count} vs max {steps}"); if count != steps || matches!(kind, TimeoutAfter) { count += 1; return Some(Ok(Some(count.encode()))) diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index e5f4d16e011b..853a09705c6e 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -996,4 +996,7 @@ mod tests { .is_err()); }); } + + #[test] + fn run_till_out_of_weight_works() {} } From 74f85b5bf8f08c51802e2120b4aa7d5ac1c2b1eb Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Mar 2024 21:18:57 +0200 Subject: [PATCH 04/21] Format Signed-off-by: Oliver Tale-Yazdi --- substrate/bin/node/runtime/Cargo.toml | 4 ++-- .../frame/examples/multi-block-migrations/Cargo.toml | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 00f6e230852b..e2981ad7888a 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -189,6 +189,7 @@ std = [ "pallet-election-provider-multi-phase/std", "pallet-election-provider-support-benchmarking?/std", "pallet-elections-phragmen/std", + "pallet-example-mbm/std", "pallet-example-tasks/std", "pallet-fast-unstake/std", "pallet-glutton/std", @@ -268,7 +269,6 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", - "pallet-example-mbm/std" ] runtime-benchmarks = [ "frame-benchmarking-pallet-pov/runtime-benchmarks", @@ -296,6 +296,7 @@ runtime-benchmarks = [ "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", + "pallet-example-mbm/runtime-benchmarks", "pallet-example-tasks/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", "pallet-glutton/runtime-benchmarks", @@ -344,7 +345,6 @@ runtime-benchmarks = [ "pallet-whitelist/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", - "pallet-example-mbm/runtime-benchmarks" ] try-runtime = [ "frame-benchmarking-pallet-pov/try-runtime", diff --git a/substrate/frame/examples/multi-block-migrations/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml index c1241efcc484..2217a0b4be74 100644 --- a/substrate/frame/examples/multi-block-migrations/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -23,20 +23,20 @@ scale-info = { version = "2.10.0", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ "codec/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", - "scale-info/std", - "frame-benchmarking?/std", "pallet-migrations/std", - "sp-io/std" + "scale-info/std", + "sp-io/std", ] runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "pallet-migrations/runtime-benchmarks" + "pallet-migrations/runtime-benchmarks", ] From f97b7cb6d7a8f99f8e28ff2616af5a1efb923f5e Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Mar 2024 22:32:43 +0200 Subject: [PATCH 05/21] Clippy Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/migrations/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index bb36a5c1cf2c..eca391daf923 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -421,13 +421,11 @@ pub mod pallet { } // The per-block service weight is sane. - #[cfg(not(test))] { let want = T::MaxServiceWeight::get(); let max = ::BlockWeights::get().max_block; assert!(want.all_lte(max), "Service weight is larger than a block: {want} > {max}"); - assert!(!want.is_zero(), "Service weight cannot be zero"); } // Cursor MEL From 49f230c4a5ba298ef845d7fc4e4dcd3207081fe3 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 26 Mar 2024 23:28:12 +0200 Subject: [PATCH 06/21] Clippy Signed-off-by: Oliver Tale-Yazdi --- .../multi-block-migrations/src/migrations/v1/benchmarks.rs | 5 +++-- substrate/frame/examples/multi-block-migrations/src/mock.rs | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs index 92373a082ae4..fe3a8d185b42 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs @@ -22,12 +22,13 @@ mod benches { #[block] { - v1::LazyMigrationV1::::step(None, &mut meter).unwrap(); + v1::LazyMigrationV1::>::step(None, &mut meter).unwrap(); } // Check that the new storage is decodable: assert_eq!(crate::MyMap::::get(0), Some(0)); - assert_eq!(meter.consumed(), weights::SubstrateWeight::::step()); + // uses twice the weight once for migration and then for checking if there is another key. + assert_eq!(meter.consumed(), weights::SubstrateWeight::::step() * 2); } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 96efed42e92e..451108e5556a 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -33,7 +33,6 @@ //! This documentation is organized to help you understand how this runtime is configured and how //! it uses the Multi-Block Migrations Framework. -use crate::{migrations::v1, mock::v1::weights::SubstrateWeight}; use frame_support::{ construct_runtime, derive_impl, migrations::FreezeChainOnFailedMigration, pallet_prelude::Weight, traits::ConstU32, From b21ae76ecca3d0d2e1a8bfa548780490f9d06e86 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 14:21:33 +0200 Subject: [PATCH 07/21] Fixup MBM example pallet Signed-off-by: Oliver Tale-Yazdi --- .../src/migrations/v1/benchmarks.rs | 19 ++++++++ .../src/migrations/v1/mod.rs | 12 ++++- .../multi-block-migrations/src/mock.rs | 30 +++++-------- substrate/frame/migrations/src/lib.rs | 45 ++++++++++++++++++- substrate/frame/migrations/src/mock.rs | 5 ++- 5 files changed, 89 insertions(+), 22 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs index fe3a8d185b42..edda3d9cd636 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs @@ -1,3 +1,22 @@ +// 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. + +//! Benchmark the multi-block-migration. + #![cfg(feature = "runtime-benchmarks")] use crate::{ diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index be6c7e8761d9..e971ffd8ce98 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -50,6 +50,10 @@ pub mod old { } /// Migrates the items of the [`crate::MyMap`] map from `u32` to `u64`. +/// +/// The `step` function will be called once per block. It is very important that this function +/// *never* panics and never uses more weight than it got in its meter. The migrations should also +/// try to make maximal progress per step, so that the total time it takes to migrate stays low. pub struct LazyMigrationV1(PhantomData<(T, W)>); impl SteppedMigration for LazyMigrationV1 { type Cursor = u32; @@ -65,17 +69,21 @@ impl SteppedMigration for LazyMigrationV1, meter: &mut WeightMeter, ) -> Result, SteppedMigrationError> { let required = W::step(); + // If there is not enough weight to do even a single step, then we are in a really bad spot + // and the chain is bricked. But we can do nothing about it, so just return the proper + // error. if meter.remaining().any_lt(required) { return Err(SteppedMigrationError::InsufficientWeight { required }); } + // We loop here to do as much progress as possible per step. loop { if meter.try_consume(required).is_err() { break; diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 451108e5556a..41c0100253be 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -17,12 +17,12 @@ #![cfg(test)] -//! # Minimal Example Runtime Using Multi-Block Migrations Framework. +//! # Mock runtime for testing Multi-Block-Migrations //! -//! This runtime provides a minimal example of how to use the -//! [Multi-Block Migrations Framework](frame_support::migrations) and the [`pallet_migrations`]. -//! The core part of this runtime is the [`pallet_migrations::Config`] implementation, where you -//! define the migrations you want to run using the [`Migrations`] type. +//! This runtime is for testing only and should *never* be used in production. Please see the +//! comments on the specific config items. The core part of this runtime is the +//! [`pallet_migrations::Config`] implementation, where you define the migrations you want to run +//! using the [`Migrations`] type. //! //! ## How to Read the Documentation //! @@ -33,6 +33,7 @@ //! This documentation is organized to help you understand how this runtime is configured and how //! it uses the Multi-Block Migrations Framework. +use crate::migrations::{v1, v1::weights::SubstrateWeight}; use frame_support::{ construct_runtime, derive_impl, migrations::FreezeChainOnFailedMigration, pallet_prelude::Weight, traits::ConstU32, @@ -44,21 +45,14 @@ impl crate::Config for Runtime {} impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; - /// The type that implements - /// [`SteppedMigrations`](`frame_support::migrations::SteppedMigrations`). - /// - /// In this tuple, you list the migrations to run. In this example, we have a single migration, - /// [`v1::LazyMigrationV1`], which is the second version of the storage migration from the - /// [`pallet-example-mbm`](`pallet_example_mbm`) crate. - /// - /// # Example - /// ```ignore - /// type Migrations = (v1::Migration, v2::Migration, v3::Migration); - /// ``` + // Here we inject the actual MBMs. Currently there is just one, but it accepts a tuple. + // + // # Example + // ```ignore + // type Migrations = (v1::Migration, v2::Migration, v3::Migration); + // ``` #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = (v1::LazyMigrationV1>,); - #[cfg(feature = "runtime-benchmarks")] - type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = (); diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index eca391daf923..cc0bec6c11ba 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -276,9 +276,10 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); - #[pallet::config] + #[pallet::config(with_default)] pub trait Config: frame_system::Config { /// The overarching event type of the runtime. + #[pallet::no_default_bounds] type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// All the multi-block migrations to run. @@ -286,6 +287,7 @@ pub mod pallet { /// Should only be updated in a runtime-upgrade once all the old migrations have completed. /// (Check that [`Cursor`] is `None`). #[cfg(not(feature = "runtime-benchmarks"))] + #[pallet::no_default] type Migrations: SteppedMigrations; /// Mocked migrations for benchmarking only. @@ -323,6 +325,47 @@ pub mod pallet { type WeightInfo: WeightInfo; } + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. + pub mod config_preludes { + use super::{inject_runtime_type, DefaultConfig}; + use frame_support::{ + derive_impl, + migrations::FreezeChainOnFailedMigration, + pallet_prelude::{ConstU32, *}, + }; + use frame_system::limits::BlockWeights; + + /// Provides a viable default config that can be used with + /// [`derive_impl`](`frame_support::derive_impl`) to derive a testing pallet config + /// based on this one. + /// + /// See `Test` in the `default-config` example pallet's `test.rs` for an example of + /// a downstream user of this particular `TestDefaultConfig` + pub struct TestDefaultConfig; + + frame_support::parameter_types! { + /// Maximal weight per block that can be spent on migrations in tests. + pub storage TestMaxServiceWeight: Weight = { <::BlockWeights as Get>::get().max_block.div(2) }; + } + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] + impl frame_system::DefaultConfig for TestDefaultConfig {} + + #[frame_support::register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + #[inject_runtime_type] + type RuntimeEvent = (); + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<{ 1 << 16 }>; + type IdentifierMaxLen = ConstU32<{ 256 }>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = FreezeChainOnFailedMigration; + type MaxServiceWeight = TestMaxServiceWeight; + type WeightInfo = (); + } + } + /// The currently active migration to run and its cursor. /// /// `None` indicates that no migration is running. diff --git a/substrate/frame/migrations/src/mock.rs b/substrate/frame/migrations/src/mock.rs index bcd6a189c5bf..79c12b11a6d2 100644 --- a/substrate/frame/migrations/src/mock.rs +++ b/substrate/frame/migrations/src/mock.rs @@ -51,14 +51,17 @@ frame_support::parameter_types! { pub const MaxServiceWeight: Weight = Weight::MAX.div(10); } +#[derive_impl(crate::config_preludes::TestDefaultConfig)] impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type Migrations = crate::mock_helpers::MockedMigrations; + #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = MockedMigrations; type CursorMaxLen = ConstU32<65_536>; type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = MockedMigrationStatusHandler; type FailedMigrationHandler = MockedFailedMigrationHandler; - type MaxServiceWeight = MaxServiceWeight; type WeightInfo = (); } From 91c0734e9a64a8d75d3a80b1f28c9f4c0410a54a Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 14:40:07 +0200 Subject: [PATCH 08/21] Cleanup mock Signed-off-by: Oliver Tale-Yazdi --- .../src/migrations/v1/tests.rs | 22 ++----- .../src/migrations/weights.rs | 63 ------------------- .../multi-block-migrations/src/mock.rs | 18 +++++- 3 files changed, 21 insertions(+), 82 deletions(-) delete mode 100644 substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs index 361f8fbea631..d6018209ac21 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs @@ -22,12 +22,12 @@ use crate::{ v1, v1::{weights, weights::WeightInfo as _}, }, - mock::{new_test_ext, AllPalletsWithSystem, MigratorServiceWeight, Runtime as T, System}, -}; -use frame_support::{ - migrations::MultiStepMigrator, - traits::{OnFinalize, OnInitialize, OnRuntimeUpgrade}, + mock::{ + new_test_ext, run_to_block, AllPalletsWithSystem, MigratorServiceWeight, Runtime as T, + System, + }, }; +use frame_support::traits::OnRuntimeUpgrade; use pallet_migrations::WeightInfo as _; #[test] @@ -68,15 +68,3 @@ fn lazy_migration_works() { } }); } - -fn run_to_block(n: u64) { - assert!(System::block_number() < n); - while System::block_number() < n { - let b = System::block_number(); - AllPalletsWithSystem::on_finalize(b); - // Done by Executive: - ::MultiBlockMigrator::step(); - System::set_block_number(b + 1); - AllPalletsWithSystem::on_initialize(b + 1); - } -} diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs deleted file mode 100644 index 57a819b02f6e..000000000000 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs +++ /dev/null @@ -1,63 +0,0 @@ - -//! Autogenerated weights for `pallet_example_mbm` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Olivers-MBP`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` - -// Executed Command: -// polkadot-omni-bencher -// v1 -// benchmark -// pallet -// --runtime=target/release/wbuild/kitchensink-runtime/kitchensink_runtime.compact.compressed.wasm -// --pallet=pallet_example_mbm -// --extrinsic= -// --template=substrate/.maintain/frame-weight-template.hbs -// --output=substrate/frame/examples/multi-block-migrations/src/migrations/weights.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for `pallet_example_mbm`. -pub trait WeightInfo { - fn step() -> Weight; -} - -/// Weights for `pallet_example_mbm` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) - /// Proof: `PalletExampleMbms::MyMap` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - fn step() -> Weight { - // Proof Size summary in bytes: - // Measured: `28` - // Estimated: `5996` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 5996) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `PalletExampleMbms::MyMap` (r:2 w:1) - /// Proof: `PalletExampleMbms::MyMap` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - fn step() -> Weight { - // Proof Size summary in bytes: - // Measured: `28` - // Estimated: `5996` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_000_000, 5996) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } -} diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 41c0100253be..7b3886b2d83d 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -35,8 +35,10 @@ use crate::migrations::{v1, v1::weights::SubstrateWeight}; use frame_support::{ - construct_runtime, derive_impl, migrations::FreezeChainOnFailedMigration, - pallet_prelude::Weight, traits::ConstU32, + construct_runtime, derive_impl, + migrations::{FreezeChainOnFailedMigration, MultiStepMigrator}, + pallet_prelude::Weight, + traits::{ConstU32, OnFinalize, OnInitialize}, }; type Block = frame_system::mocking::MockBlock; @@ -84,3 +86,15 @@ construct_runtime! { pub fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new(Default::default()) } + +pub fn run_to_block(n: u64) { + assert!(System::block_number() < n); + while System::block_number() < n { + let b = System::block_number(); + AllPalletsWithSystem::on_finalize(b); + // Done by Executive: + ::MultiBlockMigrator::step(); + System::set_block_number(b + 1); + AllPalletsWithSystem::on_initialize(b + 1); + } +} From 09acee97b4505639ee0ac5b06272a1bf1d276fbb Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 14:45:31 +0200 Subject: [PATCH 09/21] Use derive_impl Signed-off-by: Oliver Tale-Yazdi --- .../multi-block-migrations/src/mock.rs | 27 +++++-------------- substrate/frame/migrations/src/lib.rs | 2 +- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 7b3886b2d83d..216bda5904c3 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -23,28 +23,24 @@ //! comments on the specific config items. The core part of this runtime is the //! [`pallet_migrations::Config`] implementation, where you define the migrations you want to run //! using the [`Migrations`] type. -//! -//! ## How to Read the Documentation -//! -//! To access and navigate this documentation in your browser, use the following command: -//! -//! - `cargo doc --package pallet-examples-runtime-mbm --open` -//! -//! This documentation is organized to help you understand how this runtime is configured and how -//! it uses the Multi-Block Migrations Framework. use crate::migrations::{v1, v1::weights::SubstrateWeight}; use frame_support::{ construct_runtime, derive_impl, - migrations::{FreezeChainOnFailedMigration, MultiStepMigrator}, + migrations::MultiStepMigrator, pallet_prelude::Weight, - traits::{ConstU32, OnFinalize, OnInitialize}, + traits::{OnFinalize, OnInitialize}, }; type Block = frame_system::mocking::MockBlock; impl crate::Config for Runtime {} +frame_support::parameter_types! { + pub storage MigratorServiceWeight: Weight = Weight::from_parts(100, 100); // do not use in prod +} + +#[derive_impl(pallet_migrations::config_preludes::TestDefaultConfig)] impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; // Here we inject the actual MBMs. Currently there is just one, but it accepts a tuple. @@ -55,16 +51,7 @@ impl pallet_migrations::Config for Runtime { // ``` #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = (v1::LazyMigrationV1>,); - type CursorMaxLen = ConstU32<65_536>; - type IdentifierMaxLen = ConstU32<256>; - type MigrationStatusHandler = (); - type FailedMigrationHandler = FreezeChainOnFailedMigration; type MaxServiceWeight = MigratorServiceWeight; - type WeightInfo = (); -} - -frame_support::parameter_types! { - pub storage MigratorServiceWeight: Weight = Weight::from_parts(100, 100); // do not use in prod } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index cc0bec6c11ba..92a8b051303b 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -345,7 +345,7 @@ pub mod pallet { frame_support::parameter_types! { /// Maximal weight per block that can be spent on migrations in tests. - pub storage TestMaxServiceWeight: Weight = { <::BlockWeights as Get>::get().max_block.div(2) }; + pub TestMaxServiceWeight: Weight = <::BlockWeights as Get>::get().max_block.div(2); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] From d302614586798c5985c5e9d31064e59eb82dd43d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 14:46:51 +0200 Subject: [PATCH 10/21] More derive_impl Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/examples/multi-block-migrations/src/mock.rs | 1 - substrate/frame/migrations/src/mock.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 216bda5904c3..6d979d2323f2 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -42,7 +42,6 @@ frame_support::parameter_types! { #[derive_impl(pallet_migrations::config_preludes::TestDefaultConfig)] impl pallet_migrations::Config for Runtime { - type RuntimeEvent = RuntimeEvent; // Here we inject the actual MBMs. Currently there is just one, but it accepts a tuple. // // # Example diff --git a/substrate/frame/migrations/src/mock.rs b/substrate/frame/migrations/src/mock.rs index 79c12b11a6d2..0b25bccbb440 100644 --- a/substrate/frame/migrations/src/mock.rs +++ b/substrate/frame/migrations/src/mock.rs @@ -53,16 +53,12 @@ frame_support::parameter_types! { #[derive_impl(crate::config_preludes::TestDefaultConfig)] impl crate::Config for Test { - type RuntimeEvent = RuntimeEvent; #[cfg(feature = "runtime-benchmarks")] type Migrations = crate::mock_helpers::MockedMigrations; #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = MockedMigrations; - type CursorMaxLen = ConstU32<65_536>; - type IdentifierMaxLen = ConstU32<256>; type MigrationStatusHandler = MockedMigrationStatusHandler; type FailedMigrationHandler = MockedFailedMigrationHandler; - type WeightInfo = (); } frame_support::parameter_types! { From 6f73265e2bee19ab0e0ade9059594c5c0adda0d8 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 14:56:36 +0200 Subject: [PATCH 11/21] Remove stupid changes Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/migrations/src/mock.rs | 2 +- substrate/frame/support/src/migrations.rs | 3 --- substrate/primitives/runtime/Cargo.toml | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/substrate/frame/migrations/src/mock.rs b/substrate/frame/migrations/src/mock.rs index 0b25bccbb440..48ff175f8137 100644 --- a/substrate/frame/migrations/src/mock.rs +++ b/substrate/frame/migrations/src/mock.rs @@ -28,7 +28,7 @@ use frame_support::{ weights::Weight, }; use frame_system::EventRecord; -use sp_core::{ConstU32, H256}; +use sp_core::H256; type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 853a09705c6e..e5f4d16e011b 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -996,7 +996,4 @@ mod tests { .is_err()); }); } - - #[test] - fn run_till_out_of_weight_works() {} } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 6d1d73423e13..cacfc0597229 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -33,7 +33,6 @@ sp-io = { path = "../io", default-features = false } sp-std = { path = "../std", default-features = false } sp-weights = { path = "../weights", default-features = false } docify = { version = "0.2.7" } -static_assertions = "1.1.0" simple-mermaid = { version = "0.1.1", optional = true } From d23268ec4639c28b592a488441ace6e6308e9449 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 14:59:12 +0200 Subject: [PATCH 12/21] comment Signed-off-by: Oliver Tale-Yazdi --- .../multi-block-migrations/src/migrations/v1/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index e971ffd8ce98..2250ebf6b766 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -76,9 +76,9 @@ impl SteppedMigration for LazyMigrationV1 Result, SteppedMigrationError> { let required = W::step(); - // If there is not enough weight to do even a single step, then we are in a really bad spot - // and the chain is bricked. But we can do nothing about it, so just return the proper - // error. + // If there is not enough weight for a single step, return an error. This case can be + // problematic if it is the first migration that ran in this block. But there is nothing + // that we can do about it here. if meter.remaining().any_lt(required) { return Err(SteppedMigrationError::InsufficientWeight { required }); } From 61a6d8b3404b3a0985a785b4564e52a4202538a7 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 21:56:18 +0200 Subject: [PATCH 13/21] Review fixes Signed-off-by: Oliver Tale-Yazdi --- Cargo.lock | 1 - .../examples/multi-block-migrations/src/lib.rs | 3 --- .../src/migrations/v1/benchmarks.rs | 2 +- .../src/migrations/v1/mod.rs | 14 +++++++++----- .../src/migrations/v1/tests.rs | 2 +- substrate/frame/migrations/src/lib.rs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ae960c308a9..ae99adeac597 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18980,7 +18980,6 @@ dependencies = [ "sp-std 14.0.0", "sp-tracing 16.0.0", "sp-weights", - "static_assertions", "substrate-test-runtime-client", "zstd 0.12.4", ] diff --git a/substrate/frame/examples/multi-block-migrations/src/lib.rs b/substrate/frame/examples/multi-block-migrations/src/lib.rs index 57799cab7732..64bba7198a2b 100644 --- a/substrate/frame/examples/multi-block-migrations/src/lib.rs +++ b/substrate/frame/examples/multi-block-migrations/src/lib.rs @@ -65,9 +65,6 @@ //! [`try-runtime-cli`](https://github.com/paritytech/try-runtime-cli). Support will be added to //! dry-run MBMs once they are stable //! (tracked: ). -//! -//! You can also consider using [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) for testing -//! your migrations in addition to `try-runtime-cli`. pub mod migrations; mod mock; diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs index edda3d9cd636..d14da2b705b6 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/benchmarks.rs @@ -36,7 +36,7 @@ mod benches { /// Benchmark a single step of the `v1::LazyMigrationV1` migration. #[benchmark] fn step() { - v1::old::MyMap::::insert(0, 0); + v1::v0::MyMap::::insert(0, 0); let mut meter = WeightMeter::new(); #[block] diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index 2250ebf6b766..8209a7814b23 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -18,7 +18,7 @@ //! # Multi-Block Migration v1 //! //! This module showcases a simple migration that iterates over the values in the -//! [`old::MyMap`](`crate::migrations::v1::old::MyMap`) storage map, transforms them, +//! [`v1::MyMap`](`crate::migrations::v1::v1::MyMap`) storage map, transforms them, //! and inserts them into the [`MyMap`](`crate::pallet::MyMap`) storage map. use super::PALLET_MIGRATIONS_ID; @@ -33,13 +33,13 @@ mod benchmarks; mod tests; pub mod weights; -/// Module containing the OLD storage items. +/// Module containing the OLD (v0) storage items. /// /// Before running this migration, the storage alias defined here represents the /// `on_chain` storage. // This module is public only for the purposes of linking it in the documentation. It is not // intended to be used by any other code. -pub mod old { +pub mod v0 { use super::Config; use crate::pallet::Pallet; use frame_support::{storage_alias, Blake2_128Concat}; @@ -92,16 +92,20 @@ impl SteppedMigration for LazyMigrationV1::iter_from(old::MyMap::::hashed_key_for(last_key)) + // Note that this only works if the old and the new map use the same way to hash + // storage keys. + v0::MyMap::::iter_from(v0::MyMap::::hashed_key_for(last_key)) } else { // If no cursor is provided, start iterating from the beginning. - old::MyMap::::iter() + v0::MyMap::::iter() }; // If there's a next item in the iterator, perform the migration. if let Some((last_key, value)) = iter.next() { // Migrate the inner value: u32 -> u64. let value = value as u64; + // We can just insert here since the old and the new map share the same key-space. + // Otherwise it would have to invert the concat hash function and re-hash it. MyMap::::insert(last_key, value); cursor = Some(last_key) // Return the processed key as the new cursor. } else { diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs index d6018209ac21..838ba29a6212 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/tests.rs @@ -36,7 +36,7 @@ fn lazy_migration_works() { frame_support::__private::sp_tracing::try_init_simple(); // Insert some values into the old storage map. for i in 0..1024 { - v1::old::MyMap::::insert(i, i); + v1::v0::MyMap::::insert(i, i); } // Give it enough weight do do exactly 16 iterations: diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index b71f07f72b3d..50fac175409c 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -356,7 +356,7 @@ pub mod pallet { #[inject_runtime_type] type RuntimeEvent = (); #[cfg(feature = "runtime-benchmarks")] - type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type Migrations = crate::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<{ 1 << 16 }>; type IdentifierMaxLen = ConstU32<{ 256 }>; type MigrationStatusHandler = (); From 59f0d434e472864781be1aabcba997ae4139f722 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 21:59:15 +0200 Subject: [PATCH 14/21] Add license header Signed-off-by: Oliver Tale-Yazdi --- .../src/migrations/v1/weights.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs index b823bf329674..6a5cf2ac5936 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/weights.rs @@ -1,3 +1,19 @@ +// 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. //! Autogenerated weights for `pallet_example_mbm` //! From e3fad7884629e6e0669ab4da1f504ed7af20fca5 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 2 Apr 2024 22:18:02 +0200 Subject: [PATCH 15/21] Fix Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/migrations/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index 50fac175409c..b71f07f72b3d 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -356,7 +356,7 @@ pub mod pallet { #[inject_runtime_type] type RuntimeEvent = (); #[cfg(feature = "runtime-benchmarks")] - type Migrations = crate::mock_helpers::MockedMigrations; + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type CursorMaxLen = ConstU32<{ 1 << 16 }>; type IdentifierMaxLen = ConstU32<{ 256 }>; type MigrationStatusHandler = (); From 5bd074583d95292d5ce6fca02c615ea6e523f258 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 3 Apr 2024 12:22:43 +0200 Subject: [PATCH 16/21] Hotfix for derive_impl syntax quirk Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/migrations/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index b71f07f72b3d..1266cbc0bbec 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -328,6 +328,8 @@ pub mod pallet { /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::{inject_runtime_type, DefaultConfig}; + #[cfg(feature = "runtime-benchmarks")] + use crate::mock_helpers::MockedMigrations; use frame_support::{ derive_impl, migrations::FreezeChainOnFailedMigration, @@ -356,7 +358,7 @@ pub mod pallet { #[inject_runtime_type] type RuntimeEvent = (); #[cfg(feature = "runtime-benchmarks")] - type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type Migrations = MockedMigrations; type CursorMaxLen = ConstU32<{ 1 << 16 }>; type IdentifierMaxLen = ConstU32<{ 256 }>; type MigrationStatusHandler = (); From 46ed756da3e60855c06c5864381616e0ec58d566 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 3 Apr 2024 12:53:56 +0200 Subject: [PATCH 17/21] Try fix compile Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/examples/multi-block-migrations/src/mock.rs | 6 ++++-- substrate/frame/migrations/src/lib.rs | 5 +---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 6d979d2323f2..0aa1f123fba1 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -24,7 +24,6 @@ //! [`pallet_migrations::Config`] implementation, where you define the migrations you want to run //! using the [`Migrations`] type. -use crate::migrations::{v1, v1::weights::SubstrateWeight}; use frame_support::{ construct_runtime, derive_impl, migrations::MultiStepMigrator, @@ -49,7 +48,9 @@ impl pallet_migrations::Config for Runtime { // type Migrations = (v1::Migration, v2::Migration, v3::Migration); // ``` #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = (v1::LazyMigrationV1>,); + type Migrations = (crate::migrations::v1::LazyMigrationV1>,); + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type MaxServiceWeight = MigratorServiceWeight; } @@ -73,6 +74,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { sp_io::TestExternalities::new(Default::default()) } +#[allow(dead_code)] pub fn run_to_block(n: u64) { assert!(System::block_number() < n); while System::block_number() < n { diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index 1266cbc0bbec..c0e23f345520 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -294,6 +294,7 @@ pub mod pallet { /// /// Should be configured to [`crate::mock_helpers::MockedMigrations`] in benchmarks. #[cfg(feature = "runtime-benchmarks")] + #[pallet::no_default] type Migrations: MockedMigrations; /// The maximal length of an encoded cursor. @@ -328,8 +329,6 @@ pub mod pallet { /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::{inject_runtime_type, DefaultConfig}; - #[cfg(feature = "runtime-benchmarks")] - use crate::mock_helpers::MockedMigrations; use frame_support::{ derive_impl, migrations::FreezeChainOnFailedMigration, @@ -357,8 +356,6 @@ pub mod pallet { impl DefaultConfig for TestDefaultConfig { #[inject_runtime_type] type RuntimeEvent = (); - #[cfg(feature = "runtime-benchmarks")] - type Migrations = MockedMigrations; type CursorMaxLen = ConstU32<{ 1 << 16 }>; type IdentifierMaxLen = ConstU32<{ 256 }>; type MigrationStatusHandler = (); From c8510c980e34623b6d8dff7d8e40404e96413a87 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 3 Apr 2024 13:01:42 +0200 Subject: [PATCH 18/21] Fix features Signed-off-by: Oliver Tale-Yazdi --- substrate/bin/node/runtime/Cargo.toml | 1 + substrate/frame/examples/multi-block-migrations/Cargo.toml | 5 +++++ .../frame/examples/multi-block-migrations/src/mock.rs | 7 ++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index e2981ad7888a..605125c0da7b 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -425,6 +425,7 @@ try-runtime = [ "pallet-vesting/try-runtime", "pallet-whitelist/try-runtime", "sp-runtime/try-runtime", + "pallet-example-mbm/try-runtime" ] experimental = [ "frame-support/experimental", diff --git a/substrate/frame/examples/multi-block-migrations/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml index 2217a0b4be74..1dd30b9fbc7b 100644 --- a/substrate/frame/examples/multi-block-migrations/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -40,3 +40,8 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-migrations/runtime-benchmarks", ] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-migrations/try-runtime" +] diff --git a/substrate/frame/examples/multi-block-migrations/src/mock.rs b/substrate/frame/examples/multi-block-migrations/src/mock.rs index 0aa1f123fba1..9da1d2051fa1 100644 --- a/substrate/frame/examples/multi-block-migrations/src/mock.rs +++ b/substrate/frame/examples/multi-block-migrations/src/mock.rs @@ -48,7 +48,12 @@ impl pallet_migrations::Config for Runtime { // type Migrations = (v1::Migration, v2::Migration, v3::Migration); // ``` #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = (crate::migrations::v1::LazyMigrationV1>,); + type Migrations = ( + crate::migrations::v1::LazyMigrationV1< + Runtime, + crate::migrations::v1::weights::SubstrateWeight, + >, + ); #[cfg(feature = "runtime-benchmarks")] type Migrations = pallet_migrations::mock_helpers::MockedMigrations; type MaxServiceWeight = MigratorServiceWeight; From 54d8c22ab44318d849d8c5c885a3e7ac9bc2189d Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 3 Apr 2024 13:10:54 +0200 Subject: [PATCH 19/21] Taplo + doc fixes Signed-off-by: Oliver Tale-Yazdi --- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/frame/examples/multi-block-migrations/Cargo.toml | 2 +- substrate/frame/migrations/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 605125c0da7b..99df4305cd47 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -376,6 +376,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", + "pallet-example-mbm/try-runtime", "pallet-example-tasks/try-runtime", "pallet-fast-unstake/try-runtime", "pallet-glutton/try-runtime", @@ -425,7 +426,6 @@ try-runtime = [ "pallet-vesting/try-runtime", "pallet-whitelist/try-runtime", "sp-runtime/try-runtime", - "pallet-example-mbm/try-runtime" ] experimental = [ "frame-support/experimental", diff --git a/substrate/frame/examples/multi-block-migrations/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml index 1dd30b9fbc7b..28eca8577154 100644 --- a/substrate/frame/examples/multi-block-migrations/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -43,5 +43,5 @@ runtime-benchmarks = [ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", - "pallet-migrations/try-runtime" + "pallet-migrations/try-runtime", ] diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index c0e23f345520..649bc314a12b 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -767,7 +767,7 @@ impl Pallet { } } - /// The maximal weight of calling [`exec_migration`]. + /// The maximal weight of calling the private `Self::exec_migration` function. pub fn exec_migration_max_weight() -> Weight { T::WeightInfo::exec_migration_complete() .max(T::WeightInfo::exec_migration_completed()) From 3d08bd2352e9c21ad54edbf3e9e2c9e1d93c3c21 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 3 Apr 2024 13:20:05 +0200 Subject: [PATCH 20/21] More doc fixes Signed-off-by: Oliver Tale-Yazdi --- substrate/frame/examples/multi-block-migrations/src/lib.rs | 2 +- .../examples/multi-block-migrations/src/migrations/v1/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/examples/multi-block-migrations/src/lib.rs b/substrate/frame/examples/multi-block-migrations/src/lib.rs index 64bba7198a2b..657c42b1662c 100644 --- a/substrate/frame/examples/multi-block-migrations/src/lib.rs +++ b/substrate/frame/examples/multi-block-migrations/src/lib.rs @@ -32,7 +32,7 @@ //! [`migrations::v1`] module. //! //! The [`MyMap`](`pallet::MyMap`) storage item is defined in this `pallet`, and is -//! aliased to [`old::MyMap`](`migrations::v1::old::MyMap`) in the [`migrations::v1`] +//! aliased to [`v0::MyMap`](`migrations::v1::v0::MyMap`) in the [`migrations::v1`] //! module. //! //! ## How to Read the Documentation diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index 8209a7814b23..2016b03de45e 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -18,7 +18,7 @@ //! # Multi-Block Migration v1 //! //! This module showcases a simple migration that iterates over the values in the -//! [`v1::MyMap`](`crate::migrations::v1::v1::MyMap`) storage map, transforms them, +//! [`v0::MyMap`](`crate::migrations::v1::v0::MyMap`) storage map, transforms them, //! and inserts them into the [`MyMap`](`crate::pallet::MyMap`) storage map. use super::PALLET_MIGRATIONS_ID; From bb4ab7752917219e2f711e6378729860d0fd1795 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Wed, 3 Apr 2024 15:07:14 +0200 Subject: [PATCH 21/21] prdoc Signed-off-by: Oliver Tale-Yazdi --- prdoc/pr_2119.prdoc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 prdoc/pr_2119.prdoc diff --git a/prdoc/pr_2119.prdoc b/prdoc/pr_2119.prdoc new file mode 100644 index 000000000000..d548b5af18a4 --- /dev/null +++ b/prdoc/pr_2119.prdoc @@ -0,0 +1,16 @@ +title: "Add example pallet for Multi-Block-Migrations" + +doc: + - audience: Runtime Dev + description: | + - Add an example pallet to demonstrate Multi-Block-Migrations. + - Add a `MigrationId` to frame-support for more convenient identification or migrations. + - Add default config prelude for testing in pallet-migrations. + +crates: + - name: frame-support + bump: minor + - name: pallet-migrations + bump: minor + - name: kitchensink-runtime + bump: patch