feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
[package]
|
||||
name = "pezpallet-migrations"
|
||||
version = "1.0.0"
|
||||
description = "FRAME pallet to execute multi-block migrations."
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { features = ["derive"], workspace = true }
|
||||
docify = { workspace = true }
|
||||
impl-trait-for-tuples = { workspace = true }
|
||||
log = { workspace = true, default-features = true }
|
||||
scale-info = { features = ["derive"], workspace = true }
|
||||
|
||||
frame = { workspace = true, features = ["runtime"] }
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pezframe-executive = { workspace = true, default-features = true }
|
||||
pezsp-tracing = { features = ["std"], workspace = true, default-features = true }
|
||||
|
||||
pretty_assertions = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"pezframe-benchmarking?/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"frame/std",
|
||||
"log/std",
|
||||
"scale-info/std",
|
||||
"pezsp-core/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
]
|
||||
|
||||
runtime-benchmarks = [
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-executive/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"frame/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
|
||||
try-runtime = [
|
||||
"pezframe-executive/try-runtime",
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"frame/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
@@ -0,0 +1,263 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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(feature = "runtime-benchmarks")]
|
||||
|
||||
use super::*;
|
||||
|
||||
use core::array;
|
||||
use pezframe_benchmarking::{v2::*, BenchmarkError};
|
||||
use pezframe_system::{Pallet as System, RawOrigin};
|
||||
use pezsp_core::{twox_128, Get};
|
||||
use pezsp_io::{storage, KillStorageResult};
|
||||
use pezsp_runtime::traits::One;
|
||||
|
||||
fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
|
||||
pezframe_system::Pallet::<T>::assert_has_event(generic_event.into());
|
||||
}
|
||||
|
||||
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
|
||||
pezframe_system::Pallet::<T>::assert_last_event(generic_event.into());
|
||||
}
|
||||
|
||||
#[benchmarks]
|
||||
mod benches {
|
||||
use super::*;
|
||||
use pezframe_support::traits::Hooks;
|
||||
|
||||
#[benchmark]
|
||||
fn onboard_new_mbms() {
|
||||
T::Migrations::set_fail_after(0); // Should not be called anyway.
|
||||
assert!(!Cursor::<T>::exists());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::onboard_new_mbms();
|
||||
}
|
||||
|
||||
assert_last_event::<T>(Event::UpgradeStarted { migrations: 1 }.into());
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn progress_mbms_none() {
|
||||
T::Migrations::set_fail_after(0); // Should not be called anyway.
|
||||
assert!(!Cursor::<T>::exists());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::progress_mbms(One::one());
|
||||
}
|
||||
}
|
||||
|
||||
/// All migrations completed.
|
||||
#[benchmark]
|
||||
fn exec_migration_completed() -> Result<(), BenchmarkError> {
|
||||
T::Migrations::set_fail_after(0); // Should not be called anyway.
|
||||
assert_eq!(T::Migrations::len(), 1, "Setup failed");
|
||||
let c = ActiveCursor { index: 1, inner_cursor: None, started_at: 0u32.into() };
|
||||
let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
|
||||
System::<T>::set_block_number(1u32.into());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::exec_migration(c, false, &mut meter);
|
||||
}
|
||||
|
||||
assert_last_event::<T>(Event::UpgradeCompleted {}.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// No migration runs since it is skipped as historic.
|
||||
#[benchmark]
|
||||
fn exec_migration_skipped_historic() -> Result<(), BenchmarkError> {
|
||||
T::Migrations::set_fail_after(0); // Should not be called anyway.
|
||||
assert_eq!(T::Migrations::len(), 1, "Setup failed");
|
||||
let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
|
||||
|
||||
let id: IdentifierOf<T> = T::Migrations::nth_id(0).unwrap().try_into().unwrap();
|
||||
Historic::<T>::insert(id, ());
|
||||
|
||||
let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
|
||||
System::<T>::set_block_number(1u32.into());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::exec_migration(c, false, &mut meter);
|
||||
}
|
||||
|
||||
assert_last_event::<T>(Event::MigrationSkipped { index: 0 }.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Advance a migration by one step.
|
||||
#[benchmark]
|
||||
fn exec_migration_advance() -> Result<(), BenchmarkError> {
|
||||
T::Migrations::set_success_after(1);
|
||||
assert_eq!(T::Migrations::len(), 1, "Setup failed");
|
||||
let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
|
||||
let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
|
||||
System::<T>::set_block_number(1u32.into());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::exec_migration(c, false, &mut meter);
|
||||
}
|
||||
|
||||
assert_last_event::<T>(Event::MigrationAdvanced { index: 0, took: One::one() }.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Successfully complete a migration.
|
||||
#[benchmark]
|
||||
fn exec_migration_complete() -> Result<(), BenchmarkError> {
|
||||
T::Migrations::set_success_after(0);
|
||||
assert_eq!(T::Migrations::len(), 1, "Setup failed");
|
||||
let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
|
||||
let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
|
||||
System::<T>::set_block_number(1u32.into());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::exec_migration(c, false, &mut meter);
|
||||
}
|
||||
|
||||
assert_last_event::<T>(Event::MigrationCompleted { index: 0, took: One::one() }.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn exec_migration_fail() -> Result<(), BenchmarkError> {
|
||||
T::Migrations::set_fail_after(0);
|
||||
assert_eq!(T::Migrations::len(), 1, "Setup failed");
|
||||
let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
|
||||
let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
|
||||
System::<T>::set_block_number(1u32.into());
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::exec_migration(c, false, &mut meter);
|
||||
}
|
||||
|
||||
assert_has_event::<T>(Event::UpgradeFailed {}.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn on_init_loop() {
|
||||
T::Migrations::set_fail_after(0); // Should not be called anyway.
|
||||
System::<T>::set_block_number(1u32.into());
|
||||
<Pallet<T> as Hooks<BlockNumberFor<T>>>::on_runtime_upgrade();
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::on_initialize(1u32.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_set_cursor() {
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, Some(cursor::<T>()));
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_set_active_cursor() {
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root, 0, None, None);
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn force_onboard_mbms() {
|
||||
#[extrinsic_call]
|
||||
_(RawOrigin::Root);
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn clear_historic(n: Linear<0, { DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 }>) {
|
||||
let id_max_len = <T as Config>::IdentifierMaxLen::get();
|
||||
assert!(id_max_len >= 4, "Precondition violated");
|
||||
|
||||
for i in 0..DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 {
|
||||
let id = IdentifierOf::<T>::truncate_from(
|
||||
i.encode().into_iter().cycle().take(id_max_len as usize).collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
Historic::<T>::insert(&id, ());
|
||||
}
|
||||
|
||||
#[extrinsic_call]
|
||||
_(
|
||||
RawOrigin::Root,
|
||||
HistoricCleanupSelector::Wildcard { limit: n.into(), previous_cursor: None },
|
||||
);
|
||||
}
|
||||
|
||||
#[benchmark(skip_meta, pov_mode = Measured)]
|
||||
fn reset_pallet_migration(n: Linear<0, 2048>) -> Result<(), BenchmarkError> {
|
||||
let prefix: [u8; 16] = twox_128(b"__ResetPalletBenchmarkPrefix__");
|
||||
|
||||
for i in 0..n {
|
||||
// we need to avoid allocations here
|
||||
let mut iter = prefix.into_iter().chain(i.to_le_bytes());
|
||||
let key: [u8; 20] = array::from_fn(|_| iter.next().unwrap());
|
||||
// 32 byte will trigger the worst case where the value is
|
||||
// no longer stored inline
|
||||
storage::set(&key, &[0u8; 32]);
|
||||
}
|
||||
|
||||
let result;
|
||||
#[block]
|
||||
{
|
||||
result = storage::clear_prefix(&prefix, None);
|
||||
}
|
||||
|
||||
// It will always reports no keys removed because they are still in the overlay.
|
||||
// However, the benchmarking PoV results are correctly dependent on the amount of
|
||||
// keys removed.
|
||||
match result {
|
||||
KillStorageResult::AllRemoved(_i) => {
|
||||
// during the test the storage is not comitted and `i` will always be 0
|
||||
#[cfg(not(test))]
|
||||
ensure!(_i == n, "Not all keys are removed");
|
||||
},
|
||||
_ => Err("Not all keys were removed")?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cursor<T: Config>() -> CursorOf<T> {
|
||||
// Note: The weight of a function can depend on the weight of reading the `inner_cursor`.
|
||||
// `Cursor` is a user provided type. Now instead of requiring something like `Cursor:
|
||||
// From<u32>`, we instead rely on the fact that it is MEL and the PoV benchmarking will
|
||||
// therefore already take the MEL bound, even when the cursor in storage is `None`.
|
||||
MigrationCursor::Active(ActiveCursor {
|
||||
index: u32::MAX,
|
||||
inner_cursor: None,
|
||||
started_at: 0u32.into(),
|
||||
})
|
||||
}
|
||||
|
||||
// Implements a test for each benchmark. Execute with:
|
||||
// `cargo test -p pezpallet-migrations --features runtime-benchmarks`.
|
||||
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
}
|
||||
@@ -0,0 +1,869 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
|
||||
//! # `pezpallet-migrations`
|
||||
//!
|
||||
//! Provides multi block migrations for FRAME runtimes.
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! The pallet takes care of executing a batch of multi-step migrations over multiple blocks. The
|
||||
//! process starts on each runtime upgrade. Normal and operational transactions are paused while
|
||||
//! migrations are on-going.
|
||||
//!
|
||||
//! ### Example
|
||||
//!
|
||||
//! This example demonstrates a simple mocked walk through of a basic success scenario. The pallet
|
||||
//! is configured with two migrations: one succeeding after just one step, and the second one
|
||||
//! succeeding after two steps. A runtime upgrade is then enacted and the block number is advanced
|
||||
//! until all migrations finish executing. Afterwards, the recorded historic migrations are
|
||||
//! checked and events are asserted.
|
||||
#![doc = docify::embed!("src/tests.rs", simple_works)]
|
||||
//!
|
||||
//! ## Pallet API
|
||||
//!
|
||||
//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
|
||||
//! including its configuration trait, dispatchables, storage items, events and errors.
|
||||
//!
|
||||
//! Otherwise noteworthy API of this pallet include its implementation of the
|
||||
//! [`MultiStepMigrator`] trait. This must be plugged into
|
||||
//! [`pezframe_system::Config::MultiBlockMigrator`] for proper function.
|
||||
//!
|
||||
//! The API contains some calls for emergency management. They are all prefixed with `force_` and
|
||||
//! should normally not be needed. Pay special attention prior to using them.
|
||||
//!
|
||||
//! ### Design Goals
|
||||
//!
|
||||
//! 1. Must automatically execute migrations over multiple blocks.
|
||||
//! 2. Must expose information about whether migrations are ongoing.
|
||||
//! 3. Must respect pessimistic weight bounds of migrations.
|
||||
//! 4. Must execute migrations in order. Skipping is not allowed; migrations are run on a
|
||||
//! all-or-nothing basis.
|
||||
//! 5. Must prevent re-execution of past migrations.
|
||||
//! 6. Must provide transactional storage semantics for migrations.
|
||||
//! 7. Must guarantee progress.
|
||||
//!
|
||||
//! ### Design
|
||||
//!
|
||||
//! Migrations are provided to the pallet through the associated type [`Config::Migrations`] of type
|
||||
//! [`SteppedMigrations`]. This allows multiple migrations to be aggregated through a tuple. It
|
||||
//! simplifies the trait bounds since all associated types of the trait must be provided by the
|
||||
//! pallet. The actual progress of the pallet is stored in the [`Cursor`] storage item. This can
|
||||
//! either be [`MigrationCursor::Active`] or [`MigrationCursor::Stuck`]. In the active case it
|
||||
//! points to the currently active migration and stores its inner cursor. The inner cursor can then
|
||||
//! be used by the migration to store its inner state and advance. Each time when the migration
|
||||
//! returns `Some(cursor)`, it signals the pallet that it is not done yet.
|
||||
//!
|
||||
//! The cursor is reset on each runtime upgrade. This ensures that it starts to execute at the
|
||||
//! first migration in the vector. The pallets cursor is only ever incremented or set to `Stuck`
|
||||
//! once it encounters an error (Goal 4). Once in the stuck state, the pallet will stay stuck until
|
||||
//! it is fixed through manual governance intervention.
|
||||
//!
|
||||
//! As soon as the cursor of the pallet becomes `Some(_)`; [`MultiStepMigrator::ongoing`] returns
|
||||
//! `true` (Goal 2). This can be used by upstream code to possibly pause transactions.
|
||||
//! In `on_initialize` the pallet will load the current migration and check whether it was already
|
||||
//! executed in the past by checking for membership of its ID in the [`Historic`] set. Historic
|
||||
//! migrations are skipped without causing an error. Each successfully executed migration is added
|
||||
//! to this set (Goal 5).
|
||||
//!
|
||||
//! This proceeds until no more migrations remain. At that point, the event `UpgradeCompleted` is
|
||||
//! emitted (Goal 1).
|
||||
//!
|
||||
//! The execution of each migration happens by calling [`SteppedMigration::transactional_step`].
|
||||
//! This function wraps the inner `step` function into a transactional layer to allow rollback in
|
||||
//! the error case (Goal 6).
|
||||
//!
|
||||
//! Weight limits must be checked by the migration itself. The pallet provides a [`WeightMeter`] for
|
||||
//! that purpose. The pallet may return [`SteppedMigrationError::InsufficientWeight`] at any point.
|
||||
//! In that scenario, one of two things will happen: if that migration was exclusively executed
|
||||
//! in this block, and therefore required more than the maximum amount of weight possible, the
|
||||
//! process becomes `Stuck`. Otherwise, one re-attempt is executed with the same logic in the next
|
||||
//! block (Goal 3). Progress through the migrations is guaranteed by providing a timeout for each
|
||||
//! migration via [`SteppedMigration::max_steps`]. The pallet **ONLY** guarantees progress if this
|
||||
//! is set to sensible limits (Goal 7).
|
||||
//!
|
||||
//! ### Scenario: Governance cleanup
|
||||
//!
|
||||
//! Every now and then, governance can make use of the [`clear_historic`][Pallet::clear_historic]
|
||||
//! call. This ensures that no old migrations pile up in the [`Historic`] set. This can be done very
|
||||
//! rarely, since the storage should not grow quickly and the lookup weight does not suffer much.
|
||||
//! Another possibility would be to have a synchronous single-block migration perpetually deployed
|
||||
//! that cleans them up before the MBMs start.
|
||||
//!
|
||||
//! ### Scenario: Successful upgrade
|
||||
//!
|
||||
//! The standard procedure for a successful runtime upgrade can look like this:
|
||||
//! 1. Migrations are configured in the `Migrations` config item. All migrations expose
|
||||
//! [`max_steps`][SteppedMigration::max_steps], are error tolerant, check their weight bounds and
|
||||
//! have a unique identifier.
|
||||
//! 2. The runtime upgrade is enacted. An `UpgradeStarted` event is
|
||||
//! followed by lots of `MigrationAdvanced` and `MigrationCompleted` events. Finally
|
||||
//! `UpgradeCompleted` is emitted.
|
||||
//! 3. Cleanup as described in the governance scenario be executed at any time after the migrations
|
||||
//! completed.
|
||||
//!
|
||||
//! ### Advice: Failed upgrades
|
||||
//!
|
||||
//! Failed upgrades cannot be recovered from automatically and require governance intervention. Set
|
||||
//! up monitoring for `UpgradeFailed` events to be made aware of any failures. The hook
|
||||
//! [`FailedMigrationHandler::failed`] should be setup in a way that it allows governance to act,
|
||||
//! but still prevent other transactions from interacting with the inconsistent storage state. Note
|
||||
//! that this is paramount, since the inconsistent state might contain a faulty balance amount or
|
||||
//! similar that could cause great harm if user transactions don't remain suspended. One way to
|
||||
//! implement this would be to use the `SafeMode` or `TxPause` pallets that can prevent most user
|
||||
//! interactions but still allow a whitelisted set of governance calls.
|
||||
//!
|
||||
//! ### Remark: Failed migrations
|
||||
//!
|
||||
//! Failed migrations are not added to the `Historic` set. This means that an erroneous
|
||||
//! migration must be removed and fixed manually. This already applies, even before considering the
|
||||
//! historic set.
|
||||
//!
|
||||
//! ### Remark: Transactional processing
|
||||
//!
|
||||
//! You can see the transactional semantics for migration steps as mostly useless, since in the
|
||||
//! stuck case the state is already messed up. This just prevents it from becoming even more messed
|
||||
//! up, but doesn't prevent it in the first place.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
mod benchmarking;
|
||||
pub mod migrations;
|
||||
mod mock;
|
||||
pub mod mock_helpers;
|
||||
mod tests;
|
||||
pub mod weights;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
|
||||
use core::ops::ControlFlow;
|
||||
use pezframe_support::{
|
||||
defensive, defensive_assert,
|
||||
migrations::*,
|
||||
pezpallet_prelude::*,
|
||||
traits::Get,
|
||||
weights::{Weight, WeightMeter},
|
||||
BoundedVec,
|
||||
};
|
||||
use pezframe_system::{
|
||||
pezpallet_prelude::{BlockNumberFor, *},
|
||||
Pallet as System,
|
||||
};
|
||||
use pezsp_runtime::Saturating;
|
||||
|
||||
/// Points to the next migration to execute.
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
scale_info::TypeInfo,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
pub enum MigrationCursor<Cursor, BlockNumber> {
|
||||
/// Points to the currently active migration and its inner cursor.
|
||||
Active(ActiveCursor<Cursor, BlockNumber>),
|
||||
|
||||
/// Migration got stuck and cannot proceed. This is bad.
|
||||
Stuck,
|
||||
}
|
||||
|
||||
impl<Cursor, BlockNumber> MigrationCursor<Cursor, BlockNumber> {
|
||||
/// Try to return self as an [`ActiveCursor`].
|
||||
pub fn as_active(&self) -> Option<&ActiveCursor<Cursor, BlockNumber>> {
|
||||
match self {
|
||||
MigrationCursor::Active(active) => Some(active),
|
||||
MigrationCursor::Stuck => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Cursor, BlockNumber> From<ActiveCursor<Cursor, BlockNumber>>
|
||||
for MigrationCursor<Cursor, BlockNumber>
|
||||
{
|
||||
fn from(active: ActiveCursor<Cursor, BlockNumber>) -> Self {
|
||||
MigrationCursor::Active(active)
|
||||
}
|
||||
}
|
||||
|
||||
/// Points to the currently active migration and its inner cursor.
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Encode,
|
||||
Decode,
|
||||
DecodeWithMemTracking,
|
||||
scale_info::TypeInfo,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
pub struct ActiveCursor<Cursor, BlockNumber> {
|
||||
/// The index of the migration in the MBM tuple.
|
||||
pub index: u32,
|
||||
/// The cursor of the migration that is referenced by `index`.
|
||||
pub inner_cursor: Option<Cursor>,
|
||||
/// The block number that the migration started at.
|
||||
///
|
||||
/// This is used to calculate how many blocks it took.
|
||||
pub started_at: BlockNumber,
|
||||
}
|
||||
|
||||
impl<Cursor, BlockNumber> ActiveCursor<Cursor, BlockNumber> {
|
||||
/// Advance the overarching cursor to the next migration.
|
||||
pub(crate) fn goto_next_migration(&mut self, current_block: BlockNumber) {
|
||||
self.index.saturating_inc();
|
||||
self.inner_cursor = None;
|
||||
self.started_at = current_block;
|
||||
}
|
||||
}
|
||||
|
||||
/// How to clear the records of historic migrations.
|
||||
#[derive(
|
||||
Debug, Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, scale_info::TypeInfo,
|
||||
)]
|
||||
pub enum HistoricCleanupSelector<Id> {
|
||||
/// Clear exactly these entries.
|
||||
///
|
||||
/// This is the advised way of doing it.
|
||||
Specific(Vec<Id>),
|
||||
|
||||
/// Clear up to this many entries
|
||||
Wildcard {
|
||||
/// How many should be cleared in this call at most.
|
||||
limit: Option<u32>,
|
||||
/// The cursor that was emitted from any previous `HistoricCleared`.
|
||||
///
|
||||
/// Does not need to be passed when clearing the first batch.
|
||||
previous_cursor: Option<Vec<u8>>,
|
||||
},
|
||||
}
|
||||
|
||||
/// The default number of entries that should be cleared by a `HistoricCleanupSelector::Wildcard`.
|
||||
///
|
||||
/// The caller can explicitly specify a higher amount. Benchmarks are run with twice this value.
|
||||
const DEFAULT_HISTORIC_BATCH_CLEAR_SIZE: u32 = 128;
|
||||
|
||||
impl<Id> HistoricCleanupSelector<Id> {
|
||||
/// The maximal number of entries that this will remove.
|
||||
///
|
||||
/// Needed for weight calculation.
|
||||
pub fn limit(&self) -> u32 {
|
||||
match self {
|
||||
Self::Specific(ids) => ids.len() as u32,
|
||||
Self::Wildcard { limit, .. } => limit.unwrap_or(DEFAULT_HISTORIC_BATCH_CLEAR_SIZE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience alias for [`MigrationCursor`].
|
||||
pub type CursorOf<T> = MigrationCursor<RawCursorOf<T>, BlockNumberFor<T>>;
|
||||
|
||||
/// Convenience alias for the raw inner cursor of a migration.
|
||||
pub type RawCursorOf<T> = BoundedVec<u8, <T as Config>::CursorMaxLen>;
|
||||
|
||||
/// Convenience alias for the identifier of a migration.
|
||||
pub type IdentifierOf<T> = BoundedVec<u8, <T as Config>::IdentifierMaxLen>;
|
||||
|
||||
/// Convenience alias for [`ActiveCursor`].
|
||||
pub type ActiveCursorOf<T> = ActiveCursor<RawCursorOf<T>, BlockNumberFor<T>>;
|
||||
|
||||
/// Trait for a tuple of No-OP migrations with one element.
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
pub trait MockedMigrations: SteppedMigrations {
|
||||
/// The migration should fail after `n` steps.
|
||||
fn set_fail_after(n: u32);
|
||||
/// The migration should succeed after `n` steps.
|
||||
fn set_success_after(n: u32);
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
/// Wrapper for pre-upgrade bytes, allowing us to impl MEL on it.
|
||||
///
|
||||
/// For `try-runtime` testing only.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, scale_info::TypeInfo, Default)]
|
||||
struct PreUpgradeBytesWrapper(pub Vec<u8>);
|
||||
|
||||
/// Data stored by the pre-upgrade hook of the MBMs. Only used for `try-runtime` testing.
|
||||
///
|
||||
/// Define this outside of the pallet so it is not confused with actual storage.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
#[pezframe_support::storage_alias]
|
||||
type PreUpgradeBytes<T: Config> =
|
||||
StorageMap<Pallet<T>, Twox64Concat, IdentifierOf<T>, PreUpgradeBytesWrapper, ValueQuery>;
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
/// The in-code storage version.
|
||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::storage_version(STORAGE_VERSION)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config(with_default)]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// The overarching event type of the runtime.
|
||||
#[pallet::no_default_bounds]
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as pezframe_system::Config>::RuntimeEvent>;
|
||||
|
||||
/// All the multi-block migrations to run.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// A good default needs to selected such that no migration will ever have a cursor with MEL
|
||||
/// above this limit. This is statically checked in `integrity_test`.
|
||||
#[pallet::constant]
|
||||
type CursorMaxLen: Get<u32>;
|
||||
|
||||
/// The maximal length of an encoded identifier.
|
||||
///
|
||||
/// A good default needs to selected such that no migration will ever have an identifier
|
||||
/// with MEL above this limit. This is statically checked in `integrity_test`.
|
||||
#[pallet::constant]
|
||||
type IdentifierMaxLen: Get<u32>;
|
||||
|
||||
/// Notifications for status updates of a runtime upgrade.
|
||||
///
|
||||
/// Could be used to pause XCM etc.
|
||||
type MigrationStatusHandler: MigrationStatusHandler;
|
||||
|
||||
/// Handler for failed migrations.
|
||||
type FailedMigrationHandler: FailedMigrationHandler;
|
||||
|
||||
/// The maximum weight to spend each block to execute migrations.
|
||||
type MaxServiceWeight: Get<Weight>;
|
||||
|
||||
/// Weight information for the calls and functions of this 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 pezframe_support::{
|
||||
derive_impl,
|
||||
migrations::FreezeChainOnFailedMigration,
|
||||
pezpallet_prelude::{ConstU32, *},
|
||||
};
|
||||
use pezframe_system::limits::BlockWeights;
|
||||
|
||||
/// Provides a viable default config that can be used with
|
||||
/// [`derive_impl`](`pezframe_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;
|
||||
|
||||
pezframe_support::parameter_types! {
|
||||
/// Maximal weight per block that can be spent on migrations in tests.
|
||||
pub TestMaxServiceWeight: Weight = <<TestDefaultConfig as pezframe_system::DefaultConfig>::BlockWeights as Get<BlockWeights>>::get().max_block.div(2);
|
||||
}
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
|
||||
impl pezframe_system::DefaultConfig for TestDefaultConfig {}
|
||||
|
||||
#[pezframe_support::register_default_impl(TestDefaultConfig)]
|
||||
impl DefaultConfig for TestDefaultConfig {
|
||||
#[inject_runtime_type]
|
||||
type RuntimeEvent = ();
|
||||
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.
|
||||
#[pallet::storage]
|
||||
pub type Cursor<T: Config> = StorageValue<_, CursorOf<T>, OptionQuery>;
|
||||
|
||||
/// Set of all successfully executed migrations.
|
||||
///
|
||||
/// This is used as blacklist, to not re-execute migrations that have not been removed from the
|
||||
/// codebase yet. Governance can regularly clear this out via `clear_historic`.
|
||||
#[pallet::storage]
|
||||
pub type Historic<T: Config> = StorageMap<_, Twox64Concat, IdentifierOf<T>, (), OptionQuery>;
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A Runtime upgrade started.
|
||||
///
|
||||
/// Its end is indicated by `UpgradeCompleted` or `UpgradeFailed`.
|
||||
UpgradeStarted {
|
||||
/// The number of migrations that this upgrade contains.
|
||||
///
|
||||
/// This can be used to design a progress indicator in combination with counting the
|
||||
/// `MigrationCompleted` and `MigrationSkipped` events.
|
||||
migrations: u32,
|
||||
},
|
||||
/// The current runtime upgrade completed.
|
||||
///
|
||||
/// This implies that all of its migrations completed successfully as well.
|
||||
UpgradeCompleted,
|
||||
/// Runtime upgrade failed.
|
||||
///
|
||||
/// This is very bad and will require governance intervention.
|
||||
UpgradeFailed,
|
||||
/// A migration was skipped since it was already executed in the past.
|
||||
MigrationSkipped {
|
||||
/// The index of the skipped migration within the [`Config::Migrations`] list.
|
||||
index: u32,
|
||||
},
|
||||
/// A migration progressed.
|
||||
MigrationAdvanced {
|
||||
/// The index of the migration within the [`Config::Migrations`] list.
|
||||
index: u32,
|
||||
/// The number of blocks that this migration took so far.
|
||||
took: BlockNumberFor<T>,
|
||||
},
|
||||
/// A Migration completed.
|
||||
MigrationCompleted {
|
||||
/// The index of the migration within the [`Config::Migrations`] list.
|
||||
index: u32,
|
||||
/// The number of blocks that this migration took so far.
|
||||
took: BlockNumberFor<T>,
|
||||
},
|
||||
/// A Migration failed.
|
||||
///
|
||||
/// This implies that the whole upgrade failed and governance intervention is required.
|
||||
MigrationFailed {
|
||||
/// The index of the migration within the [`Config::Migrations`] list.
|
||||
index: u32,
|
||||
/// The number of blocks that this migration took so far.
|
||||
took: BlockNumberFor<T>,
|
||||
},
|
||||
/// The set of historical migrations has been cleared.
|
||||
HistoricCleared {
|
||||
/// Should be passed to `clear_historic` in a successive call.
|
||||
next_cursor: Option<Vec<u8>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The operation cannot complete since some MBMs are ongoing.
|
||||
Ongoing,
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
Self::onboard_new_mbms()
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn integrity_test() {
|
||||
// Check that the migrations tuple is legit.
|
||||
pezframe_support::assert_ok!(T::Migrations::integrity_test());
|
||||
|
||||
// Very important! Ensure that the pallet is configured in `System::Config`.
|
||||
{
|
||||
assert!(!Cursor::<T>::exists(), "Externalities storage should be clean");
|
||||
assert!(!<T as pezframe_system::Config>::MultiBlockMigrator::ongoing());
|
||||
|
||||
Cursor::<T>::put(MigrationCursor::Stuck);
|
||||
assert!(<T as pezframe_system::Config>::MultiBlockMigrator::ongoing());
|
||||
|
||||
Cursor::<T>::kill();
|
||||
}
|
||||
|
||||
// The per-block service weight is sane.
|
||||
{
|
||||
let want = T::MaxServiceWeight::get();
|
||||
let max = <T as pezframe_system::Config>::BlockWeights::get().max_block;
|
||||
|
||||
assert!(want.all_lte(max), "Service weight is larger than a block: {want} > {max}");
|
||||
}
|
||||
|
||||
// Cursor MEL
|
||||
{
|
||||
let mel = T::Migrations::cursor_max_encoded_len();
|
||||
let max_mel = T::CursorMaxLen::get() as usize;
|
||||
assert!(
|
||||
mel <= max_mel,
|
||||
"A Cursor is not guaranteed to fit into the storage: {mel} > {max_mel}",
|
||||
);
|
||||
}
|
||||
|
||||
// Identifier MEL
|
||||
{
|
||||
let mel = T::Migrations::identifier_max_encoded_len();
|
||||
let max_mel = T::IdentifierMaxLen::get() as usize;
|
||||
assert!(
|
||||
mel <= max_mel,
|
||||
"An Identifier is not guaranteed to fit into the storage: {mel} > {max_mel}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call(weight = T::WeightInfo)]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Allows root to set a cursor to forcefully start, stop or forward the migration process.
|
||||
///
|
||||
/// Should normally not be needed and is only in place as emergency measure. Note that
|
||||
/// restarting the migration process in this manner will not call the
|
||||
/// [`MigrationStatusHandler::started`] hook or emit an `UpgradeStarted` event.
|
||||
#[pallet::call_index(0)]
|
||||
pub fn force_set_cursor(
|
||||
origin: OriginFor<T>,
|
||||
cursor: Option<CursorOf<T>>,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
Cursor::<T>::set(cursor);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Allows root to set an active cursor to forcefully start/forward the migration process.
|
||||
///
|
||||
/// This is an edge-case version of [`Self::force_set_cursor`] that allows to set the
|
||||
/// `started_at` value to the next block number. Otherwise this would not be possible, since
|
||||
/// `force_set_cursor` takes an absolute block number. Setting `started_at` to `None`
|
||||
/// indicates that the current block number plus one should be used.
|
||||
#[pallet::call_index(1)]
|
||||
pub fn force_set_active_cursor(
|
||||
origin: OriginFor<T>,
|
||||
index: u32,
|
||||
inner_cursor: Option<RawCursorOf<T>>,
|
||||
started_at: Option<BlockNumberFor<T>>,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
let started_at = started_at.unwrap_or(
|
||||
System::<T>::block_number().saturating_add(pezsp_runtime::traits::One::one()),
|
||||
);
|
||||
Cursor::<T>::put(MigrationCursor::Active(ActiveCursor {
|
||||
index,
|
||||
inner_cursor,
|
||||
started_at,
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Forces the onboarding of the migrations.
|
||||
///
|
||||
/// This process happens automatically on a runtime upgrade. It is in place as an emergency
|
||||
/// measurement. The cursor needs to be `None` for this to succeed.
|
||||
#[pallet::call_index(2)]
|
||||
pub fn force_onboard_mbms(origin: OriginFor<T>) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
ensure!(!Cursor::<T>::exists(), Error::<T>::Ongoing);
|
||||
Self::onboard_new_mbms();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears the `Historic` set.
|
||||
///
|
||||
/// `map_cursor` must be set to the last value that was returned by the
|
||||
/// `HistoricCleared` event. The first time `None` can be used. `limit` must be chosen in a
|
||||
/// way that will result in a sensible weight.
|
||||
#[pallet::call_index(3)]
|
||||
#[pallet::weight(T::WeightInfo::clear_historic(selector.limit()))]
|
||||
pub fn clear_historic(
|
||||
origin: OriginFor<T>,
|
||||
selector: HistoricCleanupSelector<IdentifierOf<T>>,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
match &selector {
|
||||
HistoricCleanupSelector::Specific(ids) => {
|
||||
for id in ids {
|
||||
Historic::<T>::remove(id);
|
||||
}
|
||||
Self::deposit_event(Event::HistoricCleared { next_cursor: None });
|
||||
},
|
||||
HistoricCleanupSelector::Wildcard { previous_cursor, .. } => {
|
||||
let next = Historic::<T>::clear(selector.limit(), previous_cursor.as_deref());
|
||||
Self::deposit_event(Event::HistoricCleared { next_cursor: next.maybe_cursor });
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Onboard all new Multi-Block-Migrations and start the process of executing them.
|
||||
///
|
||||
/// Should only be called once all previous migrations completed.
|
||||
fn onboard_new_mbms() -> Weight {
|
||||
if let Some(cursor) = Cursor::<T>::get() {
|
||||
log::error!("Ongoing migrations interrupted - chain stuck");
|
||||
|
||||
let maybe_index = cursor.as_active().map(|c| c.index);
|
||||
Self::upgrade_failed(maybe_index);
|
||||
return T::WeightInfo::onboard_new_mbms();
|
||||
}
|
||||
|
||||
let migrations = T::Migrations::len();
|
||||
log::debug!("Onboarding {migrations} new MBM migrations");
|
||||
|
||||
if migrations > 0 {
|
||||
// Set the cursor to the first migration:
|
||||
Cursor::<T>::set(Some(
|
||||
ActiveCursor {
|
||||
index: 0,
|
||||
inner_cursor: None,
|
||||
started_at: System::<T>::block_number(),
|
||||
}
|
||||
.into(),
|
||||
));
|
||||
Self::deposit_event(Event::UpgradeStarted { migrations });
|
||||
T::MigrationStatusHandler::started();
|
||||
}
|
||||
|
||||
T::WeightInfo::onboard_new_mbms()
|
||||
}
|
||||
|
||||
/// Tries to make progress on the Multi-Block-Migrations process.
|
||||
fn progress_mbms(n: BlockNumberFor<T>) -> Weight {
|
||||
let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
|
||||
meter.consume(T::WeightInfo::progress_mbms_none());
|
||||
|
||||
let mut cursor = match Cursor::<T>::get() {
|
||||
None => {
|
||||
log::trace!("[Block {n:?}] Waiting for cursor to become `Some`.");
|
||||
return meter.consumed();
|
||||
},
|
||||
Some(MigrationCursor::Active(cursor)) => {
|
||||
log::debug!("Progressing MBM #{}", cursor.index);
|
||||
cursor
|
||||
},
|
||||
Some(MigrationCursor::Stuck) => {
|
||||
log::error!("Migration stuck. Governance intervention required.");
|
||||
return meter.consumed();
|
||||
},
|
||||
};
|
||||
debug_assert!(Self::ongoing());
|
||||
|
||||
// The limit here is a defensive measure to prevent an infinite loop. It expresses that we
|
||||
// allow no more than 8 MBMs to finish in a single block. This should be harmless, since we
|
||||
// generally expect *Multi*-Block-Migrations to take *multiple* blocks.
|
||||
for i in 0..8 {
|
||||
match Self::exec_migration(cursor, i == 0, &mut meter) {
|
||||
None => return meter.consumed(),
|
||||
Some(ControlFlow::Continue(next_cursor)) => {
|
||||
cursor = next_cursor;
|
||||
},
|
||||
Some(ControlFlow::Break(last_cursor)) => {
|
||||
cursor = last_cursor;
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Cursor::<T>::set(Some(cursor.into()));
|
||||
|
||||
meter.consumed()
|
||||
}
|
||||
|
||||
/// Try to make progress on the current migration.
|
||||
///
|
||||
/// Returns whether processing should continue or break for this block. The return value means:
|
||||
/// - `None`: The migration process is completely finished.
|
||||
/// - `ControlFlow::Break`: Continue in the *next* block with the given cursor.
|
||||
/// - `ControlFlow::Continue`: Continue in the *current* block with the given cursor.
|
||||
fn exec_migration(
|
||||
mut cursor: ActiveCursorOf<T>,
|
||||
is_first: bool,
|
||||
meter: &mut WeightMeter,
|
||||
) -> Option<ControlFlow<ActiveCursorOf<T>, ActiveCursorOf<T>>> {
|
||||
// The differences between the single branches' weights is not that big. And since we do
|
||||
// only one step per block, we can just use the maximum instead of more precise accounting.
|
||||
if meter.try_consume(Self::exec_migration_max_weight()).is_err() {
|
||||
defensive_assert!(!is_first, "There should be enough weight to do this at least once");
|
||||
return Some(ControlFlow::Break(cursor));
|
||||
}
|
||||
|
||||
if cursor.index >= T::Migrations::len() {
|
||||
// No more migrations in the tuple - we are done.
|
||||
defensive_assert!(cursor.index == T::Migrations::len(), "Inconsistent MBMs tuple");
|
||||
Self::deposit_event(Event::UpgradeCompleted);
|
||||
Cursor::<T>::kill();
|
||||
T::MigrationStatusHandler::completed();
|
||||
return None;
|
||||
};
|
||||
|
||||
let id = T::Migrations::nth_id(cursor.index).map(TryInto::try_into);
|
||||
let Some(Ok(bounded_id)): Option<Result<IdentifierOf<T>, _>> = id else {
|
||||
defensive!("integrity_test ensures that all identifiers are present and bounde; qed.");
|
||||
Self::upgrade_failed(Some(cursor.index));
|
||||
return None;
|
||||
};
|
||||
|
||||
if Historic::<T>::contains_key(&bounded_id) {
|
||||
Self::deposit_event(Event::MigrationSkipped { index: cursor.index });
|
||||
cursor.goto_next_migration(System::<T>::block_number());
|
||||
return Some(ControlFlow::Continue(cursor));
|
||||
}
|
||||
|
||||
let max_steps = T::Migrations::nth_max_steps(cursor.index);
|
||||
|
||||
// If this is the first time running this migration, exec the pre-upgrade hook.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
if !PreUpgradeBytes::<T>::contains_key(&bounded_id) {
|
||||
let bytes = T::Migrations::nth_pre_upgrade(cursor.index)
|
||||
.expect("Invalid cursor.index")
|
||||
.expect("Pre-upgrade failed");
|
||||
PreUpgradeBytes::<T>::insert(&bounded_id, PreUpgradeBytesWrapper(bytes));
|
||||
}
|
||||
|
||||
let next_cursor = T::Migrations::nth_transactional_step(
|
||||
cursor.index,
|
||||
cursor.inner_cursor.clone().map(|c| c.into_inner()),
|
||||
meter,
|
||||
);
|
||||
let Some((max_steps, next_cursor)) = max_steps.zip(next_cursor) else {
|
||||
defensive!("integrity_test ensures that the tuple is valid; qed");
|
||||
Self::upgrade_failed(Some(cursor.index));
|
||||
return None;
|
||||
};
|
||||
|
||||
let took = System::<T>::block_number().saturating_sub(cursor.started_at);
|
||||
match next_cursor {
|
||||
Ok(Some(next_cursor)) => {
|
||||
let Ok(bound_next_cursor) = next_cursor.try_into() else {
|
||||
defensive!("The integrity check ensures that all cursors' MEL bound fits into CursorMaxLen; qed");
|
||||
Self::upgrade_failed(Some(cursor.index));
|
||||
return None;
|
||||
};
|
||||
|
||||
Self::deposit_event(Event::MigrationAdvanced { index: cursor.index, took });
|
||||
cursor.inner_cursor = Some(bound_next_cursor);
|
||||
|
||||
if max_steps.is_some_and(|max| took > max.into()) {
|
||||
Self::deposit_event(Event::MigrationFailed { index: cursor.index, took });
|
||||
Self::upgrade_failed(Some(cursor.index));
|
||||
None
|
||||
} else {
|
||||
// A migration cannot progress more than one step per block, we therefore break.
|
||||
Some(ControlFlow::Break(cursor))
|
||||
}
|
||||
},
|
||||
Ok(None) => {
|
||||
// A migration is done when it returns cursor `None`.
|
||||
|
||||
// Run post-upgrade checks.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
T::Migrations::nth_post_upgrade(
|
||||
cursor.index,
|
||||
PreUpgradeBytes::<T>::get(&bounded_id).0,
|
||||
)
|
||||
.expect("Invalid cursor.index.")
|
||||
.expect("Post-upgrade failed.");
|
||||
|
||||
Self::deposit_event(Event::MigrationCompleted { index: cursor.index, took });
|
||||
Historic::<T>::insert(&bounded_id, ());
|
||||
cursor.goto_next_migration(System::<T>::block_number());
|
||||
Some(ControlFlow::Continue(cursor))
|
||||
},
|
||||
Err(SteppedMigrationError::InsufficientWeight { required }) => {
|
||||
if is_first || required.any_gt(meter.limit()) {
|
||||
Self::deposit_event(Event::MigrationFailed { index: cursor.index, took });
|
||||
Self::upgrade_failed(Some(cursor.index));
|
||||
None
|
||||
} else {
|
||||
// Retry and hope that there is more weight in the next block.
|
||||
Some(ControlFlow::Break(cursor))
|
||||
}
|
||||
},
|
||||
Err(SteppedMigrationError::InvalidCursor | SteppedMigrationError::Failed) => {
|
||||
Self::deposit_event(Event::MigrationFailed { index: cursor.index, took });
|
||||
Self::upgrade_failed(Some(cursor.index));
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Fail the current runtime upgrade, caused by `migration`.
|
||||
///
|
||||
/// When the `try-runtime` feature is enabled, this function will panic.
|
||||
// Allow unreachable code so it can compile without warnings when `try-runtime` is enabled.
|
||||
fn upgrade_failed(migration: Option<u32>) {
|
||||
use FailedMigrationHandling::*;
|
||||
Self::deposit_event(Event::UpgradeFailed);
|
||||
|
||||
if cfg!(feature = "try-runtime") {
|
||||
panic!("Migration with index {migration:?} failed.");
|
||||
} else {
|
||||
match T::FailedMigrationHandler::failed(migration) {
|
||||
KeepStuck => Cursor::<T>::set(Some(MigrationCursor::Stuck)),
|
||||
ForceUnstuck => Cursor::<T>::kill(),
|
||||
Ignore => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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())
|
||||
.max(T::WeightInfo::exec_migration_skipped_historic())
|
||||
.max(T::WeightInfo::exec_migration_advance())
|
||||
.max(T::WeightInfo::exec_migration_fail())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> MultiStepMigrator for Pallet<T> {
|
||||
fn ongoing() -> bool {
|
||||
Cursor::<T>::exists()
|
||||
}
|
||||
|
||||
fn step() -> Weight {
|
||||
Self::progress_mbms(System::<T>::block_number())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// 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.
|
||||
|
||||
//! Generic multi block migrations not specific to any pallet.
|
||||
|
||||
use crate::{weights::WeightInfo, Config};
|
||||
use codec::Encode;
|
||||
use core::marker::PhantomData;
|
||||
use pezframe_support::{
|
||||
migrations::{SteppedMigration, SteppedMigrationError, StoreInCodeStorageVersion},
|
||||
traits::{GetStorageVersion, PalletInfoAccess},
|
||||
weights::WeightMeter,
|
||||
};
|
||||
use pezsp_core::{twox_128, Get};
|
||||
use pezsp_io::{storage::clear_prefix, KillStorageResult};
|
||||
use pezsp_runtime::SaturatedConversion;
|
||||
|
||||
/// Remove all of a pallet's state and re-initializes it to the current in-code storage version.
|
||||
///
|
||||
/// It uses the multi block migration frame. Hence it is safe to use even on
|
||||
/// pallets that contain a lot of storage.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - T: The runtime. Used to access the weight definition.
|
||||
/// - P: The pallet to resetted as defined in construct runtime
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If your pallet does rely of some state in genesis you need to take care of that
|
||||
/// separately. This migration only sets the storage version after wiping.
|
||||
pub struct ResetPallet<T, P>(PhantomData<(T, P)>);
|
||||
|
||||
impl<T, P> ResetPallet<T, P>
|
||||
where
|
||||
P: PalletInfoAccess,
|
||||
{
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn num_keys() -> u64 {
|
||||
let prefix = P::name_hash().to_vec();
|
||||
crate::storage::KeyPrefixIterator::new(prefix.clone(), prefix, |_| Ok(())).count() as _
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P, V> SteppedMigration for ResetPallet<T, P>
|
||||
where
|
||||
T: Config,
|
||||
P: PalletInfoAccess + GetStorageVersion<InCodeStorageVersion = V>,
|
||||
V: StoreInCodeStorageVersion<P>,
|
||||
{
|
||||
type Cursor = bool;
|
||||
type Identifier = [u8; 16];
|
||||
|
||||
fn id() -> Self::Identifier {
|
||||
("RemovePallet::", P::name()).using_encoded(twox_128)
|
||||
}
|
||||
|
||||
fn step(
|
||||
cursor: Option<Self::Cursor>,
|
||||
meter: &mut WeightMeter,
|
||||
) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
|
||||
// we write the storage version in a seperate block
|
||||
if cursor.unwrap_or(false) {
|
||||
let required = T::DbWeight::get().writes(1);
|
||||
meter
|
||||
.try_consume(required)
|
||||
.map_err(|_| SteppedMigrationError::InsufficientWeight { required })?;
|
||||
V::store_in_code_storage_version();
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let base_weight = T::WeightInfo::reset_pallet_migration(0);
|
||||
let weight_per_key = T::WeightInfo::reset_pallet_migration(1).saturating_sub(base_weight);
|
||||
let key_budget = meter
|
||||
.remaining()
|
||||
.saturating_sub(base_weight)
|
||||
.checked_div_per_component(&weight_per_key)
|
||||
.unwrap_or_default()
|
||||
.saturated_into();
|
||||
|
||||
if key_budget == 0 {
|
||||
return Err(SteppedMigrationError::InsufficientWeight {
|
||||
required: T::WeightInfo::reset_pallet_migration(1),
|
||||
});
|
||||
}
|
||||
|
||||
let (keys_removed, is_done) = match clear_prefix(&P::name_hash(), Some(key_budget)) {
|
||||
KillStorageResult::AllRemoved(value) => (value, true),
|
||||
KillStorageResult::SomeRemaining(value) => (value, false),
|
||||
};
|
||||
|
||||
meter.consume(T::WeightInfo::reset_pallet_migration(keys_removed));
|
||||
|
||||
Ok(Some(is_done))
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<alloc::vec::Vec<u8>, pezsp_runtime::TryRuntimeError> {
|
||||
let num_keys: u64 = Self::num_keys();
|
||||
log::info!("ResetPallet<{}>: Trying to remove {num_keys} keys.", P::name());
|
||||
Ok(num_keys.encode())
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: alloc::vec::Vec<u8>) -> Result<(), pezsp_runtime::TryRuntimeError> {
|
||||
use codec::Decode;
|
||||
let keys_before = u64::decode(&mut state.as_ref()).expect("We encoded as u64 above; qed");
|
||||
let keys_now = Self::num_keys();
|
||||
log::info!("ResetPallet<{}>: Keys remaining after migration: {keys_now}", P::name());
|
||||
|
||||
if keys_before <= keys_now {
|
||||
log::error!("ResetPallet<{}>: Did not remove any keys.", P::name());
|
||||
Err("ResetPallet failed")?;
|
||||
}
|
||||
|
||||
if keys_now != 1 {
|
||||
log::error!("ResetPallet<{}>: Should have a single key after reset", P::name());
|
||||
Err("ResetPallet failed")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
//! Mocked runtime for testing the migrations pallet.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::{mock_helpers::*, Event, Historic};
|
||||
|
||||
use pezframe_support::{derive_impl, migrations::*, weights::Weight};
|
||||
use pezframe_system::EventRecord;
|
||||
use pezsp_core::H256;
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<Test>;
|
||||
|
||||
// Configure a mock runtime to test the pallet.
|
||||
pezframe_support::construct_runtime!(
|
||||
pub enum Test {
|
||||
System: pezframe_system,
|
||||
Migrations: crate,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Test {
|
||||
type Block = Block;
|
||||
type PalletInfo = PalletInfo;
|
||||
type MultiBlockMigrator = Migrations;
|
||||
}
|
||||
|
||||
pezframe_support::parameter_types! {
|
||||
pub const MaxServiceWeight: Weight = Weight::MAX.div(10);
|
||||
}
|
||||
|
||||
#[derive_impl(crate::config_preludes::TestDefaultConfig)]
|
||||
impl crate::Config for Test {
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type Migrations = crate::mock_helpers::MockedMigrations;
|
||||
#[cfg(not(feature = "runtime-benchmarks"))]
|
||||
type Migrations = MockedMigrations;
|
||||
type MigrationStatusHandler = MockedMigrationStatusHandler;
|
||||
type FailedMigrationHandler = MockedFailedMigrationHandler;
|
||||
}
|
||||
|
||||
pezframe_support::parameter_types! {
|
||||
/// The number of started upgrades.
|
||||
pub static UpgradesStarted: u32 = 0;
|
||||
/// The number of completed upgrades.
|
||||
pub static UpgradesCompleted: u32 = 0;
|
||||
/// The migrations that failed.
|
||||
pub static UpgradesFailed: Vec<Option<u32>> = vec![];
|
||||
/// Return value of [`MockedFailedMigrationHandler::failed`].
|
||||
pub static FailedUpgradeResponse: FailedMigrationHandling = FailedMigrationHandling::KeepStuck;
|
||||
}
|
||||
|
||||
/// Records all started and completed upgrades in `UpgradesStarted` and `UpgradesCompleted`.
|
||||
pub struct MockedMigrationStatusHandler;
|
||||
impl MigrationStatusHandler for MockedMigrationStatusHandler {
|
||||
fn started() {
|
||||
log::info!("MigrationStatusHandler started");
|
||||
UpgradesStarted::mutate(|v| *v += 1);
|
||||
}
|
||||
|
||||
fn completed() {
|
||||
log::info!("MigrationStatusHandler completed");
|
||||
UpgradesCompleted::mutate(|v| *v += 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Records all failed upgrades in `UpgradesFailed`.
|
||||
pub struct MockedFailedMigrationHandler;
|
||||
impl FailedMigrationHandler for MockedFailedMigrationHandler {
|
||||
fn failed(migration: Option<u32>) -> FailedMigrationHandling {
|
||||
UpgradesFailed::mutate(|v| v.push(migration));
|
||||
let res = FailedUpgradeResponse::get();
|
||||
log::error!("FailedMigrationHandler failed at: {migration:?}, handling as {res:?}");
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of `(started, completed, failed)` upgrades and resets their numbers.
|
||||
pub fn upgrades_started_completed_failed() -> (u32, u32, u32) {
|
||||
(UpgradesStarted::take(), UpgradesCompleted::take(), UpgradesFailed::take().len() as u32)
|
||||
}
|
||||
|
||||
/// Build genesis storage according to the mock runtime.
|
||||
pub fn new_test_ext() -> pezsp_io::TestExternalities {
|
||||
pezsp_io::TestExternalities::new(Default::default())
|
||||
}
|
||||
|
||||
/// Run this closure in test externalities.
|
||||
pub fn test_closure<R>(f: impl FnOnce() -> R) -> R {
|
||||
let mut ext = new_test_ext();
|
||||
ext.execute_with(f)
|
||||
}
|
||||
|
||||
pub fn run_to_block(n: u64) {
|
||||
System::run_to_block_with::<AllPalletsWithSystem>(
|
||||
n,
|
||||
pezframe_system::RunToBlockHooks::default()
|
||||
.before_initialize(|bn| {
|
||||
log::debug!("Block {bn}");
|
||||
})
|
||||
.after_initialize(|_| {
|
||||
// Executive calls this:
|
||||
<Migrations as MultiStepMigrator>::step();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the historic migrations, sorted by their identifier.
|
||||
pub fn historic() -> Vec<MockedIdentifier> {
|
||||
let mut historic = Historic::<Test>::iter_keys().collect::<Vec<_>>();
|
||||
historic.sort();
|
||||
historic
|
||||
}
|
||||
|
||||
// Traits to make using events less insufferable:
|
||||
pub trait IntoRecord {
|
||||
fn into_record(self) -> EventRecord<<Test as pezframe_system::Config>::RuntimeEvent, H256>;
|
||||
}
|
||||
|
||||
impl IntoRecord for Event<Test> {
|
||||
fn into_record(self) -> EventRecord<<Test as pezframe_system::Config>::RuntimeEvent, H256> {
|
||||
let re: <Test as pezframe_system::Config>::RuntimeEvent = self.into();
|
||||
EventRecord { phase: pezframe_system::Phase::Initialization, event: re, topics: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoRecords {
|
||||
fn into_records(self) -> Vec<EventRecord<<Test as pezframe_system::Config>::RuntimeEvent, H256>>;
|
||||
}
|
||||
|
||||
impl<E: IntoRecord> IntoRecords for Vec<E> {
|
||||
fn into_records(self) -> Vec<EventRecord<<Test as pezframe_system::Config>::RuntimeEvent, H256>> {
|
||||
self.into_iter().map(|e| e.into_record()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_events<E: IntoRecord>(events: Vec<E>) {
|
||||
pretty_assertions::assert_eq!(events.into_records(), System::events());
|
||||
System::reset_events();
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
//! Test helpers for internal and external usage.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use alloc::{vec, vec::Vec};
|
||||
use codec::{Decode, Encode};
|
||||
use pezframe_support::{
|
||||
migrations::*,
|
||||
weights::{Weight, WeightMeter},
|
||||
};
|
||||
use pezsp_core::ConstU32;
|
||||
use pezsp_runtime::BoundedVec;
|
||||
|
||||
/// Opaque identifier of a migration.
|
||||
pub type MockedIdentifier = BoundedVec<u8, ConstU32<256>>;
|
||||
|
||||
/// How a mocked migration should behave.
|
||||
#[derive(Debug, Clone, Copy, Encode, Decode)]
|
||||
pub enum MockedMigrationKind {
|
||||
/// Succeed after its number of steps elapsed.
|
||||
SucceedAfter,
|
||||
/// Fail after its number of steps elapsed.
|
||||
FailAfter,
|
||||
/// Never terminate.
|
||||
TimeoutAfter,
|
||||
/// Cause an [`SteppedMigrationError::InsufficientWeight`] error after its number of steps
|
||||
/// elapsed.
|
||||
HighWeightAfter(Weight),
|
||||
/// PreUpgrade should fail.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
PreUpgradeFail,
|
||||
/// PostUpgrade should fail.
|
||||
#[cfg(feature = "try-runtime")]
|
||||
PostUpgradeFail,
|
||||
}
|
||||
use MockedMigrationKind::*; // C style
|
||||
|
||||
/// Creates a migration identifier with a specific `kind` and `steps`.
|
||||
pub fn mocked_id(kind: MockedMigrationKind, steps: u32) -> MockedIdentifier {
|
||||
(b"MockedMigration", kind, steps).encode().try_into().unwrap()
|
||||
}
|
||||
|
||||
pezframe_support::parameter_types! {
|
||||
/// The configs for the migrations to run.
|
||||
storage MIGRATIONS: Vec<(MockedMigrationKind, u32)> = vec![];
|
||||
}
|
||||
|
||||
/// Allows to set the migrations to run at runtime instead of compile-time.
|
||||
///
|
||||
/// It achieves this by using the storage to store the migrations to run.
|
||||
pub struct MockedMigrations;
|
||||
impl SteppedMigrations for MockedMigrations {
|
||||
fn len() -> u32 {
|
||||
MIGRATIONS::get().len() as u32
|
||||
}
|
||||
|
||||
fn nth_id(n: u32) -> Option<Vec<u8>> {
|
||||
let k = MIGRATIONS::get().get(n as usize).copied();
|
||||
k.map(|(kind, steps)| mocked_id(kind, steps).into_inner())
|
||||
}
|
||||
|
||||
fn nth_step(
|
||||
n: u32,
|
||||
cursor: Option<Vec<u8>>,
|
||||
_meter: &mut WeightMeter,
|
||||
) -> Option<Result<Option<Vec<u8>>, SteppedMigrationError>> {
|
||||
let (kind, steps) = MIGRATIONS::get()[n as usize];
|
||||
|
||||
let mut count: u32 =
|
||||
cursor.as_ref().and_then(|c| Decode::decode(&mut &c[..]).ok()).unwrap_or(0);
|
||||
log::debug!("MockedMigration: Step {count} vs max {steps}");
|
||||
if count != steps || matches!(kind, TimeoutAfter) {
|
||||
count += 1;
|
||||
return Some(Ok(Some(count.encode())));
|
||||
}
|
||||
|
||||
Some(match kind {
|
||||
SucceedAfter => {
|
||||
log::debug!("MockedMigration: Succeeded after {count} steps");
|
||||
Ok(None)
|
||||
},
|
||||
HighWeightAfter(required) => {
|
||||
log::debug!("MockedMigration: Not enough weight after {count} steps");
|
||||
Err(SteppedMigrationError::InsufficientWeight { required })
|
||||
},
|
||||
FailAfter => {
|
||||
log::debug!("MockedMigration: Failed after {count} steps");
|
||||
Err(SteppedMigrationError::Failed)
|
||||
},
|
||||
TimeoutAfter => unreachable!(),
|
||||
#[cfg(feature = "try-runtime")]
|
||||
PreUpgradeFail | PostUpgradeFail => Ok(None),
|
||||
})
|
||||
}
|
||||
|
||||
fn nth_transactional_step(
|
||||
n: u32,
|
||||
cursor: Option<Vec<u8>>,
|
||||
meter: &mut WeightMeter,
|
||||
) -> Option<Result<Option<Vec<u8>>, SteppedMigrationError>> {
|
||||
// This is a hack but should be fine. We don't need it in testing.
|
||||
Self::nth_step(n, cursor, meter)
|
||||
}
|
||||
|
||||
fn nth_max_steps(n: u32) -> Option<Option<u32>> {
|
||||
MIGRATIONS::get().get(n as usize).map(|(_, s)| Some(*s))
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn nth_pre_upgrade(n: u32) -> Option<Result<Vec<u8>, pezsp_runtime::TryRuntimeError>> {
|
||||
let (kind, _) = MIGRATIONS::get()[n as usize];
|
||||
|
||||
if let PreUpgradeFail = kind {
|
||||
return Some(Err("Some pre-upgrade error".into()));
|
||||
}
|
||||
|
||||
Some(Ok(vec![]))
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn nth_post_upgrade(
|
||||
n: u32,
|
||||
_state: Vec<u8>,
|
||||
) -> Option<Result<(), pezsp_runtime::TryRuntimeError>> {
|
||||
let (kind, _) = MIGRATIONS::get()[n as usize];
|
||||
|
||||
if let PostUpgradeFail = kind {
|
||||
return Some(Err("Some post-upgrade error".into()));
|
||||
}
|
||||
|
||||
Some(Ok(()))
|
||||
}
|
||||
|
||||
fn cursor_max_encoded_len() -> usize {
|
||||
65_536
|
||||
}
|
||||
|
||||
fn identifier_max_encoded_len() -> usize {
|
||||
256
|
||||
}
|
||||
}
|
||||
|
||||
impl MockedMigrations {
|
||||
/// Set the migrations to run.
|
||||
pub fn set(migrations: Vec<(MockedMigrationKind, u32)>) {
|
||||
MIGRATIONS::set(&migrations);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MockedMigrations for MockedMigrations {
|
||||
fn set_fail_after(steps: u32) {
|
||||
MIGRATIONS::set(&vec![(FailAfter, steps)]);
|
||||
}
|
||||
|
||||
fn set_success_after(steps: u32) {
|
||||
MIGRATIONS::set(&vec![(SucceedAfter, steps)]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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(test)]
|
||||
|
||||
use pezframe_support::{pezpallet_prelude::Weight, traits::OnRuntimeUpgrade};
|
||||
|
||||
use crate::{
|
||||
mock::{Test as T, *},
|
||||
mock_helpers::{MockedMigrationKind::*, *},
|
||||
Cursor, Event, FailedMigrationHandling, MigrationCursor,
|
||||
};
|
||||
|
||||
#[docify::export]
|
||||
#[test]
|
||||
fn simple_works() {
|
||||
use Event::*;
|
||||
test_closure(|| {
|
||||
// Add three migrations, each taking one block longer than the previous.
|
||||
MockedMigrations::set(vec![(SucceedAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Check that the executed migrations are recorded in `Historical`.
|
||||
assert_eq!(historic(), vec![mocked_id(SucceedAfter, 2),]);
|
||||
|
||||
// Check that we got all events.
|
||||
assert_events(vec![
|
||||
UpgradeStarted { migrations: 1 },
|
||||
MigrationAdvanced { index: 0, took: 1 },
|
||||
MigrationAdvanced { index: 0, took: 2 },
|
||||
MigrationCompleted { index: 0, took: 3 },
|
||||
UpgradeCompleted,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_multiple_works() {
|
||||
use Event::*;
|
||||
test_closure(|| {
|
||||
// Add three migrations, each taking one block longer than the previous.
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (SucceedAfter, 1), (SucceedAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Check that the executed migrations are recorded in `Historical`.
|
||||
assert_eq!(
|
||||
historic(),
|
||||
vec![
|
||||
mocked_id(SucceedAfter, 0),
|
||||
mocked_id(SucceedAfter, 1),
|
||||
mocked_id(SucceedAfter, 2),
|
||||
]
|
||||
);
|
||||
|
||||
// Check that we got all events.
|
||||
assert_events(vec![
|
||||
UpgradeStarted { migrations: 3 },
|
||||
MigrationCompleted { index: 0, took: 1 },
|
||||
MigrationAdvanced { index: 1, took: 0 },
|
||||
MigrationCompleted { index: 1, took: 1 },
|
||||
MigrationAdvanced { index: 2, took: 0 },
|
||||
MigrationAdvanced { index: 2, took: 1 },
|
||||
MigrationCompleted { index: 2, took: 2 },
|
||||
UpgradeCompleted,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn failing_migration_sets_cursor_to_stuck() {
|
||||
test_closure(|| {
|
||||
FailedUpgradeResponse::set(FailedMigrationHandling::KeepStuck);
|
||||
MockedMigrations::set(vec![(FailAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Failed migrations are not recorded in `Historical`.
|
||||
assert!(historic().is_empty());
|
||||
// Check that we got all events.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 2 },
|
||||
Event::MigrationFailed { index: 0, took: 3 },
|
||||
Event::UpgradeFailed,
|
||||
]);
|
||||
|
||||
// Check that the handler was called correctly.
|
||||
assert_eq!(UpgradesStarted::take(), 1);
|
||||
assert_eq!(UpgradesCompleted::take(), 0);
|
||||
assert_eq!(UpgradesFailed::take(), vec![Some(0)]);
|
||||
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck), "Must stuck the chain");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn failing_migration_force_unstuck_works() {
|
||||
test_closure(|| {
|
||||
FailedUpgradeResponse::set(FailedMigrationHandling::ForceUnstuck);
|
||||
MockedMigrations::set(vec![(FailAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Failed migrations are not recorded in `Historical`.
|
||||
assert!(historic().is_empty());
|
||||
// Check that we got all events.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 2 },
|
||||
Event::MigrationFailed { index: 0, took: 3 },
|
||||
Event::UpgradeFailed,
|
||||
]);
|
||||
|
||||
// Check that the handler was called correctly.
|
||||
assert_eq!(UpgradesStarted::take(), 1);
|
||||
assert_eq!(UpgradesCompleted::take(), 0);
|
||||
assert_eq!(UpgradesFailed::take(), vec![Some(0)]);
|
||||
|
||||
assert!(Cursor::<T>::get().is_none(), "Must unstuck the chain");
|
||||
});
|
||||
}
|
||||
|
||||
/// A migration that reports not getting enough weight errors if it is the first one to run in that
|
||||
/// block.
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn high_weight_migration_singular_fails() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![(HighWeightAfter(Weight::zero()), 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Failed migrations are not recorded in `Historical`.
|
||||
assert!(historic().is_empty());
|
||||
// Check that we got all events.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 2 },
|
||||
Event::MigrationFailed { index: 0, took: 3 },
|
||||
Event::UpgradeFailed,
|
||||
]);
|
||||
|
||||
// Check that the handler was called correctly.
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 0, 1));
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck));
|
||||
});
|
||||
}
|
||||
|
||||
/// A migration that reports of not getting enough weight is retried once, if it is not the first
|
||||
/// one to run in a block.
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn high_weight_migration_retries_once() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (HighWeightAfter(Weight::zero()), 0)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
assert_eq!(historic(), vec![mocked_id(SucceedAfter, 0)]);
|
||||
// Check that we got all events.
|
||||
assert_events::<Event<T>>(vec![
|
||||
Event::UpgradeStarted { migrations: 2 },
|
||||
Event::MigrationCompleted { index: 0, took: 1 },
|
||||
// `took=1` means that it was retried once.
|
||||
Event::MigrationFailed { index: 1, took: 1 },
|
||||
Event::UpgradeFailed,
|
||||
]);
|
||||
|
||||
// Check that the handler was called correctly.
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 0, 1));
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck));
|
||||
});
|
||||
}
|
||||
|
||||
/// If a migration uses more weight than the limit, then it will not retry but fail even when it is
|
||||
/// not the first one in the block.
|
||||
// Note: Same as `high_weight_migration_retries_once` but with different required weight for the
|
||||
// migration.
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn high_weight_migration_permanently_overweight_fails() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (HighWeightAfter(Weight::MAX), 0)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
assert_eq!(historic(), vec![mocked_id(SucceedAfter, 0)]);
|
||||
// Check that we got all events.
|
||||
assert_events::<Event<T>>(vec![
|
||||
Event::UpgradeStarted { migrations: 2 },
|
||||
Event::MigrationCompleted { index: 0, took: 1 },
|
||||
// `blocks=0` means that it was not retried.
|
||||
Event::MigrationFailed { index: 1, took: 0 },
|
||||
Event::UpgradeFailed,
|
||||
]);
|
||||
|
||||
// Check that the handler was called correctly.
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 0, 1));
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn historic_skipping_works() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![
|
||||
(SucceedAfter, 0),
|
||||
(SucceedAfter, 0), // duplicate
|
||||
(SucceedAfter, 1),
|
||||
(SucceedAfter, 2),
|
||||
(SucceedAfter, 1), // duplicate
|
||||
]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Just three historical ones, since two were added twice.
|
||||
assert_eq!(
|
||||
historic(),
|
||||
vec![
|
||||
mocked_id(SucceedAfter, 0),
|
||||
mocked_id(SucceedAfter, 1),
|
||||
mocked_id(SucceedAfter, 2),
|
||||
]
|
||||
);
|
||||
// Events received.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 5 },
|
||||
Event::MigrationCompleted { index: 0, took: 1 },
|
||||
Event::MigrationSkipped { index: 1 },
|
||||
Event::MigrationAdvanced { index: 2, took: 0 },
|
||||
Event::MigrationCompleted { index: 2, took: 1 },
|
||||
Event::MigrationAdvanced { index: 3, took: 0 },
|
||||
Event::MigrationAdvanced { index: 3, took: 1 },
|
||||
Event::MigrationCompleted { index: 3, took: 2 },
|
||||
Event::MigrationSkipped { index: 4 },
|
||||
Event::UpgradeCompleted,
|
||||
]);
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 1, 0));
|
||||
|
||||
// Now go for another upgrade; just to make sure that it wont execute again.
|
||||
System::reset_events();
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(20);
|
||||
|
||||
// Same historical ones as before.
|
||||
assert_eq!(
|
||||
historic(),
|
||||
vec![
|
||||
mocked_id(SucceedAfter, 0),
|
||||
mocked_id(SucceedAfter, 1),
|
||||
mocked_id(SucceedAfter, 2),
|
||||
]
|
||||
);
|
||||
|
||||
// Everything got skipped.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 5 },
|
||||
Event::MigrationSkipped { index: 0 },
|
||||
Event::MigrationSkipped { index: 1 },
|
||||
Event::MigrationSkipped { index: 2 },
|
||||
Event::MigrationSkipped { index: 3 },
|
||||
Event::MigrationSkipped { index: 4 },
|
||||
Event::UpgradeCompleted,
|
||||
]);
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 1, 0));
|
||||
});
|
||||
}
|
||||
|
||||
/// When another upgrade happens while a migration is still running, it should set the cursor to
|
||||
/// stuck.
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn upgrade_fails_when_migration_active() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![(SucceedAfter, 10)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(3);
|
||||
|
||||
// Events received.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 2 },
|
||||
]);
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 0, 0));
|
||||
|
||||
// Upgrade again.
|
||||
Migrations::on_runtime_upgrade();
|
||||
// -- Defensive path --
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck));
|
||||
assert_events(vec![Event::UpgradeFailed]);
|
||||
assert_eq!(upgrades_started_completed_failed(), (0, 0, 1));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(feature = "try-runtime", should_panic)]
|
||||
fn migration_timeout_errors() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![(TimeoutAfter, 3)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(5);
|
||||
|
||||
// Times out after taking more than 3 steps.
|
||||
assert_events(vec![
|
||||
Event::UpgradeStarted { migrations: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 1 },
|
||||
Event::MigrationAdvanced { index: 0, took: 2 },
|
||||
Event::MigrationAdvanced { index: 0, took: 3 },
|
||||
Event::MigrationAdvanced { index: 0, took: 4 },
|
||||
Event::MigrationFailed { index: 0, took: 4 },
|
||||
Event::UpgradeFailed,
|
||||
]);
|
||||
assert_eq!(upgrades_started_completed_failed(), (1, 0, 1));
|
||||
|
||||
// Failed migrations are not black-listed.
|
||||
assert!(historic().is_empty());
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck));
|
||||
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(6);
|
||||
|
||||
assert_events(vec![Event::UpgradeFailed]);
|
||||
assert_eq!(Cursor::<T>::get(), Some(MigrationCursor::Stuck));
|
||||
assert_eq!(upgrades_started_completed_failed(), (0, 0, 1));
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
#[test]
|
||||
fn try_runtime_success_case() {
|
||||
use Event::*;
|
||||
test_closure(|| {
|
||||
// Add three migrations, each taking one block longer than the previous.
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (SucceedAfter, 1), (SucceedAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
run_to_block(10);
|
||||
|
||||
// Check that we got all events.
|
||||
assert_events(vec![
|
||||
UpgradeStarted { migrations: 3 },
|
||||
MigrationCompleted { index: 0, took: 1 },
|
||||
MigrationAdvanced { index: 1, took: 0 },
|
||||
MigrationCompleted { index: 1, took: 1 },
|
||||
MigrationAdvanced { index: 2, took: 0 },
|
||||
MigrationAdvanced { index: 2, took: 1 },
|
||||
MigrationCompleted { index: 2, took: 2 },
|
||||
UpgradeCompleted,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "try-runtime")]
|
||||
#[should_panic]
|
||||
fn try_runtime_pre_upgrade_failure() {
|
||||
test_closure(|| {
|
||||
// Add three migrations, it should fail after the second one.
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (PreUpgradeFail, 1), (SucceedAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
|
||||
// should panic
|
||||
run_to_block(10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "try-runtime")]
|
||||
#[should_panic]
|
||||
fn try_runtime_post_upgrade_failure() {
|
||||
test_closure(|| {
|
||||
// Add three migrations, it should fail after the second one.
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (PostUpgradeFail, 1), (SucceedAfter, 2)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
|
||||
// should panic
|
||||
run_to_block(10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "try-runtime")]
|
||||
#[should_panic]
|
||||
fn try_runtime_migration_failure() {
|
||||
test_closure(|| {
|
||||
// Add three migrations, it should fail after the second one.
|
||||
MockedMigrations::set(vec![(SucceedAfter, 0), (FailAfter, 5), (SucceedAfter, 10)]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
|
||||
// should panic
|
||||
run_to_block(10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_runtime_no_migrations() {
|
||||
test_closure(|| {
|
||||
MockedMigrations::set(vec![]);
|
||||
|
||||
System::set_block_number(1);
|
||||
Migrations::on_runtime_upgrade();
|
||||
|
||||
run_to_block(10);
|
||||
|
||||
assert_eq!(System::events().len(), 0);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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.
|
||||
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// 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 `pezpallet_migrations`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `4563561839a5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
|
||||
|
||||
// Executed Command:
|
||||
// frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --extrinsic=*
|
||||
// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm
|
||||
// --pallet=pezpallet_migrations
|
||||
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
|
||||
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/migrations/src/weights.rs
|
||||
// --wasm-execution=compiled
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --heap-pages=4096
|
||||
// --template=bizinikiwi/.maintain/frame-umbrella-weight-template.hbs
|
||||
// --no-storage-info
|
||||
// --no-min-squares
|
||||
// --no-median-slopes
|
||||
// --genesis-builder-policy=none
|
||||
// --exclude-pallets=pezpallet_xcm,pezpallet_xcm_benchmarks::fungible,pezpallet_xcm_benchmarks::generic,pezpallet_nomination_pools,pezpallet_remark,pezpallet_transaction_storage,pezpallet_election_provider_multi_block,pezpallet_election_provider_multi_block::signed,pezpallet_election_provider_multi_block::unsigned,pezpallet_election_provider_multi_block::verifier
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use frame::weights_prelude::*;
|
||||
|
||||
/// Weight functions needed for `pezpallet_migrations`.
|
||||
pub trait WeightInfo {
|
||||
fn onboard_new_mbms() -> Weight;
|
||||
fn progress_mbms_none() -> Weight;
|
||||
fn exec_migration_completed() -> Weight;
|
||||
fn exec_migration_skipped_historic() -> Weight;
|
||||
fn exec_migration_advance() -> Weight;
|
||||
fn exec_migration_complete() -> Weight;
|
||||
fn exec_migration_fail() -> Weight;
|
||||
fn on_init_loop() -> Weight;
|
||||
fn force_set_cursor() -> Weight;
|
||||
fn force_set_active_cursor() -> Weight;
|
||||
fn force_onboard_mbms() -> Weight;
|
||||
fn clear_historic(n: u32, ) -> Weight;
|
||||
fn reset_pallet_migration(n: u32, ) -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_migrations` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
fn onboard_new_mbms() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `67035`
|
||||
// Minimum execution time: 4_411_000 picoseconds.
|
||||
Weight::from_parts(4_542_000, 67035)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn progress_mbms_none() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `67035`
|
||||
// Minimum execution time: 792_000 picoseconds.
|
||||
Weight::from_parts(834_000, 67035)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_completed() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3465`
|
||||
// Minimum execution time: 3_842_000 picoseconds.
|
||||
Weight::from_parts(3_951_000, 3465)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_skipped_historic() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `34`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 7_153_000 picoseconds.
|
||||
Weight::from_parts(7_407_000, 3731)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_advance() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 6_837_000 picoseconds.
|
||||
Weight::from_parts(7_033_000, 3731)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_complete() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 8_167_000 picoseconds.
|
||||
Weight::from_parts(8_455_000, 3731)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_fail() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 8_868_000 picoseconds.
|
||||
Weight::from_parts(9_053_000, 3731)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
fn on_init_loop() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 150_000 picoseconds.
|
||||
Weight::from_parts(163_000, 0)
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn force_set_cursor() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 2_142_000 picoseconds.
|
||||
Weight::from_parts(2_212_000, 0)
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn force_set_active_cursor() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 2_496_000 picoseconds.
|
||||
Weight::from_parts(2_609_000, 0)
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
fn force_onboard_mbms() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `67035`
|
||||
// Minimum execution time: 3_010_000 picoseconds.
|
||||
Weight::from_parts(3_114_000, 67035)
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:256 w:256)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
/// The range of component `n` is `[0, 256]`.
|
||||
fn clear_historic(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `960 + n * (271 ±0)`
|
||||
// Estimated: `3834 + n * (2740 ±0)`
|
||||
// Minimum execution time: 15_012_000 picoseconds.
|
||||
Weight::from_parts(12_864_005, 3834)
|
||||
// Standard Error: 3_561
|
||||
.saturating_add(Weight::from_parts(1_455_402, 0).saturating_mul(n.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into()))
|
||||
}
|
||||
/// Storage: `Skipped::Metadata` (r:0 w:0)
|
||||
/// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `n` is `[0, 2048]`.
|
||||
fn reset_pallet_migration(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `1605 + n * (38 ±0)`
|
||||
// Estimated: `686 + n * (39 ±0)`
|
||||
// Minimum execution time: 1_185_000 picoseconds.
|
||||
Weight::from_parts(6_858_633, 686)
|
||||
// Standard Error: 1_584
|
||||
.saturating_add(Weight::from_parts(834_871, 0).saturating_mul(n.into()))
|
||||
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(Weight::from_parts(0, 39).saturating_mul(n.into()))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
fn onboard_new_mbms() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `67035`
|
||||
// Minimum execution time: 4_411_000 picoseconds.
|
||||
Weight::from_parts(4_542_000, 67035)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn progress_mbms_none() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `67035`
|
||||
// Minimum execution time: 792_000 picoseconds.
|
||||
Weight::from_parts(834_000, 67035)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_completed() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3465`
|
||||
// Minimum execution time: 3_842_000 picoseconds.
|
||||
Weight::from_parts(3_951_000, 3465)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_skipped_historic() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `34`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 7_153_000 picoseconds.
|
||||
Weight::from_parts(7_407_000, 3731)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_advance() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 6_837_000 picoseconds.
|
||||
Weight::from_parts(7_033_000, 3731)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_complete() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 8_167_000 picoseconds.
|
||||
Weight::from_parts(8_455_000, 3731)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn exec_migration_fail() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `3731`
|
||||
// Minimum execution time: 8_868_000 picoseconds.
|
||||
Weight::from_parts(9_053_000, 3731)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
fn on_init_loop() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 150_000 picoseconds.
|
||||
Weight::from_parts(163_000, 0)
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn force_set_cursor() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 2_142_000 picoseconds.
|
||||
Weight::from_parts(2_212_000, 0)
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
fn force_set_active_cursor() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 2_496_000 picoseconds.
|
||||
Weight::from_parts(2_609_000, 0)
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0)
|
||||
/// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`)
|
||||
/// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
/// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0)
|
||||
fn force_onboard_mbms() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `67035`
|
||||
// Minimum execution time: 3_010_000 picoseconds.
|
||||
Weight::from_parts(3_114_000, 67035)
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
}
|
||||
/// Storage: `MultiBlockMigrations::Historic` (r:256 w:256)
|
||||
/// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`)
|
||||
/// The range of component `n` is `[0, 256]`.
|
||||
fn clear_historic(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `960 + n * (271 ±0)`
|
||||
// Estimated: `3834 + n * (2740 ±0)`
|
||||
// Minimum execution time: 15_012_000 picoseconds.
|
||||
Weight::from_parts(12_864_005, 3834)
|
||||
// Standard Error: 3_561
|
||||
.saturating_add(Weight::from_parts(1_455_402, 0).saturating_mul(n.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into()))
|
||||
}
|
||||
/// Storage: `Skipped::Metadata` (r:0 w:0)
|
||||
/// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`)
|
||||
/// The range of component `n` is `[0, 2048]`.
|
||||
fn reset_pallet_migration(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `1605 + n * (38 ±0)`
|
||||
// Estimated: `686 + n * (39 ±0)`
|
||||
// Minimum execution time: 1_185_000 picoseconds.
|
||||
Weight::from_parts(6_858_633, 686)
|
||||
// Standard Error: 1_584
|
||||
.saturating_add(Weight::from_parts(834_871, 0).saturating_mul(n.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into())))
|
||||
.saturating_add(Weight::from_parts(0, 39).saturating_mul(n.into()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user