diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 570f9b7e5c..908e8da5dc 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -5692,6 +5692,7 @@ dependencies = [ "frame-benchmarking-cli", "frame-support", "frame-system-rpc-runtime-api", + "frame-try-runtime", "futures 0.3.30", "jsonrpsee", "litentry-parachain-runtime", diff --git a/parachain/node/Cargo.toml b/parachain/node/Cargo.toml index 1ff4a6d02c..b81edacd32 100644 --- a/parachain/node/Cargo.toml +++ b/parachain/node/Cargo.toml @@ -105,6 +105,7 @@ xcm = { workspace = true } frame-benchmarking = { workspace = true } frame-benchmarking-cli = { workspace = true } frame-system-rpc-runtime-api = { workspace = true } +frame-try-runtime = { workspace = true, optional = true } core-primitives = { workspace = true, features = ["std"] } litentry-parachain-runtime = { workspace = true, features = ["std"] } @@ -148,5 +149,6 @@ try-runtime = [ "polkadot-service/try-runtime", "runtime-common/try-runtime", "sp-runtime/try-runtime", + "frame-try-runtime", ] std = [] diff --git a/parachain/runtime/litentry/Cargo.toml b/parachain/runtime/litentry/Cargo.toml index d1f8b10039..b82890181a 100644 --- a/parachain/runtime/litentry/Cargo.toml +++ b/parachain/runtime/litentry/Cargo.toml @@ -308,7 +308,6 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime", - "frame-try-runtime?/try-runtime", "hex", "pallet-account-fix/try-runtime", "pallet-asset-manager/try-runtime", diff --git a/parachain/runtime/litentry/src/lib.rs b/parachain/runtime/litentry/src/lib.rs index 80e06926d1..e801e211a2 100644 --- a/parachain/runtime/litentry/src/lib.rs +++ b/parachain/runtime/litentry/src/lib.rs @@ -99,6 +99,7 @@ pub mod asset_config; pub mod constants; pub mod precompiles; +pub mod migration; pub mod weights; pub mod xcm_config; @@ -156,6 +157,7 @@ pub type Executive = frame_executive::Executive< // It was reverse order before. // See the comment before collation related pallets too. AllPalletsWithSystem, + migration::Migrations, >; impl fp_self_contained::SelfContainedCall for RuntimeCall { diff --git a/parachain/runtime/litentry/src/migration/mod.rs b/parachain/runtime/litentry/src/migration/mod.rs index d3f5a12faa..15209e348d 100644 --- a/parachain/runtime/litentry/src/migration/mod.rs +++ b/parachain/runtime/litentry/src/migration/mod.rs @@ -1 +1,462 @@ - +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// By the time of this migration on Litentry 9220 (polkadot stable2407) +// The current storage version: pallet version: +// scheduler: - 0 +// multisig: - 0 +// preimage: - 0 +// balances: - 0 +// democracy: - 0 +// bounties: - 0 +// xcmpQueue: - 3 +// polkadotXcm: - 0 +// developerCommittee - 0 +// developerCommitteeMembership - 0 +// transactionPayment: V1Ancient 0 +// vesting: V1 0 + +// Our target storage version: pallet version: (stable2407) +// scheduler: - 0 => 4 +// multisig: - 0 => 1 +// preimage: - 0 => 1 +// balances: - 0 => 1 +// democracy: - 0 => 1 +// bounties: - 0 => 4 +// xcmpQueue: - 3 => 5 +// polkadotXcm: - 0 => 1 +// developerCommittee - 0 => 4 +// developerCommitteeMembership - 0 => 4 +// transactionPayment: V1Ancient => V2 0 (it is built by genesis, so maybe no fix is fine) +// vesting: V1 0 + +// In try-runtime, current implementation, the storage version is not checked, +// Pallet version is used instead. +#[cfg(feature = "try-runtime")] +use frame_support::ensure; +use frame_support::traits::{ + Get, GetStorageVersion, OnRuntimeUpgrade, PalletInfoAccess, StorageVersion, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_scheduler::Agenda; +use sp_std::marker::PhantomData; +use sp_std::vec::Vec; + +extern crate alloc; +use alloc::collections::btree_map::BTreeMap; + +pub type Migrations = ( + // Scheduler V0 => V4 + // The official pallet does not provide any available migration + // We, Litentry Storage have two old unexecuted expired root tasks. + // This storage should be clean up and update storage version to V4 directly. + // PS: Looks like two old tasks fits V2/V3 structure + RemoveSchedulerOldStorage, + // Multsig V0 => V1 + // Remove old unsettled call storage and do the refund + // Does not matter if we do have old storage or not + // Should simply works + pallet_multisig::migrations::v1::MigrateToV1, + // Clean correpted preimage storage + RemoveCorreptedPreimageStorage, + // Preimage V0 => V1 + // Migrate old StatusFor and PreimageFor Storage into new Storage + pallet_preimage::migration::v1::Migration, + // Balances V0 => V1 + // The official pallet migration is not need since we do not have any XCM deactive accounts + // But our onchain inactiveIssuance storage of pallet_balance is non-negative + // TODO: Where does this number come from? + BalancesUpdateStorageVersionResetInactive, + // Democracy V0 => V1 + // This migration only effects onging proposal/referedum, NextExternal + // The referedum info's proposal hash is migrated if the hash is in old form (In our case, even for an onging one it will do nothing) + pallet_democracy::migrations::v1::v1::Migration, + // Bounties V0 => V4 + // The official migration does nothing but change pallet name and bump version + // So we just bump version storage instead + BountiesUpdateStorageVersion, + // V3 to V4 + // XCMP QueueConfig has different default value + // Migration targeting at changing storage value to new default value if old value matched + // Our current Litentry setting has already hard-coded + // This migration should have no effect except bumping storage version + cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + // V4 to V5 + // Did nothing to storage + // Just checking MaxActiveOutboundChannels is not exceeded + // Our current Litentry Storage is 0 + // This migration should have no effect except bumping storage version + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, + // PolkadotXcm V0 => V1 + // Our storage is already correct + // This migration is for can old weightInfo into new weightInfo form + // Should do nothing but bump version storage for us + pallet_xcm::migration::v1::MigrateToV1, + // DeveloperCommittee V0 => V4 + // The official migration does nothing but change pallet name and bump version + // So we just bump version storage instead + DeveloperCommitteeUpdateStorageVersion, + // DeveloperCommitteeMembership V0 => V4 + // The official migration does nothing but change pallet name and bump version + // So we just bump version storage instead + DeveloperCommitteeMembershipUpdateStorageVersion, +); + +pub struct RemoveSchedulerOldStorage(PhantomData); +impl OnRuntimeUpgrade for RemoveSchedulerOldStorage +where + T: frame_system::Config + pallet_scheduler::Config, + BlockNumberFor: From, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + log::info!("Pre check pallet scheduler storage only has two precise tasks leftover"); + let one: BlockNumberFor = 3067200u32.into(); + let two: BlockNumberFor = 2995200u32.into(); + for (when, _vec_schedule) in >::iter() { + assert!(when == one || when == two, "Extra schedule exists"); + } + Ok(Vec::::new()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + log::info!("Begin cleaning pallet scheduler storage two precise tasks leftover"); + // Remove Scheduler Storage precisely of according block agenda only + // TODO: Very Weak safety + let one: BlockNumberFor = 3067200u32.into(); + let two: BlockNumberFor = 2995200u32.into(); + Agenda::::remove(one); + Agenda::::remove(two); + + #[allow(deprecated)] + frame_support::storage::migration::remove_storage_prefix( + b"Scheduler", + b"StorageVersion", + &[], + ); + StorageVersion::new(4).put::>(); + ::DbWeight::get().reads_writes(2, 4) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::DispatchError> { + log::info!("Post check pallet scheduler storage two precise tasks cleaned"); + let one: BlockNumberFor = 3067200u32.into(); + let two: BlockNumberFor = 2995200u32.into(); + for (when, _vec_schedule) in >::iter() { + assert!(when != one && when != two, "Old schedule still exists"); + } + + ensure!(StorageVersion::get::>() == 4, "Must upgrade"); + + Ok(()) + } +} + +/// The original data layout of the preimage pallet without a specific version number. +mod preimage_helper { + use frame_support::{pallet_prelude::*, storage_alias, traits::Currency}; + + type BalanceOf = <::Currency as Currency< + ::AccountId, + >>::Balance; + + #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] + pub enum OldRequestStatus { + Unrequested(Option<(AccountId, Balance)>), + Requested(u32), + } + + #[storage_alias] + pub type PreimageFor = StorageMap< + pallet_preimage::Pallet, + Identity, + ::Hash, + BoundedVec>, + >; + + #[storage_alias] + pub type StatusFor = StorageMap< + pallet_preimage::Pallet, + Identity, + ::Hash, + OldRequestStatus<::AccountId, BalanceOf>, + >; + + /// Returns the number of images or `None` if the storage is corrupted. + #[cfg(feature = "try-runtime")] + pub fn image_count() -> (u32, u32) { + let images = PreimageFor::::iter_values().count() as u32; + let status = StatusFor::::iter_values().count() as u32; + + (images, status) + } +} + +const PREIMAGE_LOG_TARGET: &str = "runtime::preimage"; +pub struct RemoveCorreptedPreimageStorage(PhantomData); +impl OnRuntimeUpgrade for RemoveCorreptedPreimageStorage +where + T: frame_system::Config + pallet_preimage::Config, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + let (image, status) = preimage_helper::image_count::(); + assert!(image != status, "Preimage storage not correpted"); + Ok(Vec::::new()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Remove preimage correpted storage + // TODO: Very Weak safety + let mut weight = T::DbWeight::get().reads(1); + if StorageVersion::get::>() != 0 { + log::warn!( + target: PREIMAGE_LOG_TARGET, + "skipping MovePreimagesIntoBuckets: executed on wrong storage version.\ + Expected version 0" + ); + return weight; + } + + let status = preimage_helper::StatusFor::::drain().collect::>(); + weight.saturating_accrue(T::DbWeight::get().reads(status.len() as u64)); + + let preimages = preimage_helper::PreimageFor::::drain().collect::>(); + weight.saturating_accrue(T::DbWeight::get().reads(preimages.len() as u64)); + + for (hash, _status) in status.into_iter() { + if !preimages.contains_key(&hash) { + log::info!(target: PREIMAGE_LOG_TARGET, "Clean status for hash {:?}", &hash); + preimage_helper::StatusFor::::remove(hash); + }; + weight + .saturating_accrue(::DbWeight::get().reads_writes(1, 1)); + } + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::DispatchError> { + let (image, status) = preimage_helper::image_count::(); + assert!(image == status, "Preimage storage still correpted"); + + Ok(()) + } +} + +const BALANCES_LOG_TARGET: &str = "runtime::balances"; +pub struct BalancesUpdateStorageVersionResetInactive(PhantomData); +impl OnRuntimeUpgrade for BalancesUpdateStorageVersionResetInactive +where + T: frame_system::Config + pallet_balances::Config, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + ensure!( + StorageVersion::get::>() == 0, + "Already upgrade to some non-zero version" + ); + Ok(Vec::::new()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let on_chain_version = pallet_balances::Pallet::::on_chain_storage_version(); + + if on_chain_version == 0 { + // Remove the old `StorageVersion` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + pallet_balances::Pallet::::name().as_bytes(), + "StorageVersion".as_bytes(), + )); + + // For security purpose, we may not want to do this now + // InactiveIssuance::::kill(); + + // Set storage version to `1`. + StorageVersion::new(1).put::>(); + + log::info!(target: BALANCES_LOG_TARGET, "Storage to version 1"); + T::DbWeight::get().reads_writes(1, 3) + } else { + log::info!( + target: BALANCES_LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::DispatchError> { + ensure!(StorageVersion::get::>() == 1, "Must upgrade"); + Ok(()) + } +} + +const BOUNTIES_LOG_TARGET: &str = "runtime::bounties"; +pub struct BountiesUpdateStorageVersion(PhantomData); +impl OnRuntimeUpgrade for BountiesUpdateStorageVersion +where + T: frame_system::Config + pallet_bounties::Config, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + ensure!( + StorageVersion::get::>() == 0, + "Already upgrade to some non-zero version" + ); + Ok(Vec::::new()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let on_chain_version = pallet_bounties::Pallet::::on_chain_storage_version(); + + if on_chain_version == 0 { + // Remove the old `StorageVersion` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + pallet_bounties::Pallet::::name().as_bytes(), + "StorageVersion".as_bytes(), + )); + + // Set storage version to `4`. + StorageVersion::new(4).put::>(); + + log::info!(target: BOUNTIES_LOG_TARGET, "Storage to version 4"); + T::DbWeight::get().reads_writes(1, 3) + } else { + log::info!( + target: BOUNTIES_LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::DispatchError> { + ensure!(StorageVersion::get::>() == 4, "Must upgrade"); + Ok(()) + } +} + +const DEVELOPER_COMMITTEE_LOG_TARGET: &str = "runtime::collective3"; +pub struct DeveloperCommitteeUpdateStorageVersion(PhantomData); +impl OnRuntimeUpgrade for DeveloperCommitteeUpdateStorageVersion +where + T: frame_system::Config + pallet_collective::Config, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + ensure!( + StorageVersion::get::>() + == 0, + "Already upgrade to some non-zero version" + ); + Ok(Vec::::new()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let on_chain_version = + pallet_collective::Pallet::::on_chain_storage_version( + ); + + if on_chain_version == 0 { + // Remove the old `StorageVersion` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + pallet_collective::Pallet::::name().as_bytes(), + "StorageVersion".as_bytes(), + )); + + // Set storage version to `4`. + StorageVersion::new(4) + .put::>(); + + log::info!(target: DEVELOPER_COMMITTEE_LOG_TARGET, "Storage to version 4"); + T::DbWeight::get().reads_writes(1, 3) + } else { + log::info!( + target: DEVELOPER_COMMITTEE_LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::DispatchError> { + ensure!( + StorageVersion::get::>() + == 4, + "Must upgrade" + ); + Ok(()) + } +} + +const DEVELOPER_COMMITTEE_MEMBERSHIP_LOG_TARGET: &str = "runtime::membership3"; +pub struct DeveloperCommitteeMembershipUpdateStorageVersion(PhantomData); +impl OnRuntimeUpgrade for DeveloperCommitteeMembershipUpdateStorageVersion +where + T: frame_system::Config + pallet_membership::Config, +{ + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + ensure!( + StorageVersion::get::>() + == 0, + "Already upgrade to some non-zero version" + ); + Ok(Vec::::new()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let on_chain_version = + pallet_membership::Pallet::::on_chain_storage_version( + ); + + if on_chain_version == 0 { + // Remove the old `StorageVersion` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + pallet_membership::Pallet::::name().as_bytes(), + "StorageVersion".as_bytes(), + )); + + // Set storage version to `4`. + StorageVersion::new(4) + .put::>(); + + log::info!(target: DEVELOPER_COMMITTEE_MEMBERSHIP_LOG_TARGET, "Storage to version 4"); + T::DbWeight::get().reads_writes(1, 3) + } else { + log::info!( + target: DEVELOPER_COMMITTEE_MEMBERSHIP_LOG_TARGET, + "Migration did not execute. This probably should be removed" + ); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::DispatchError> { + ensure!( + StorageVersion::get::>() + == 4, + "Must upgrade" + ); + Ok(()) + } +} diff --git a/parachain/runtime/litentry/src/xcm_config.rs b/parachain/runtime/litentry/src/xcm_config.rs index c18fd3c7f2..ab90c4b9b5 100644 --- a/parachain/runtime/litentry/src/xcm_config.rs +++ b/parachain/runtime/litentry/src/xcm_config.rs @@ -244,3 +244,9 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; type PriceForSiblingDelivery = NoPriceForMessageDelivery; } + +// TODO:: remove after migration of storage version finished +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} diff --git a/parachain/runtime/paseo/Cargo.toml b/parachain/runtime/paseo/Cargo.toml index 2fb76e12e4..1fc6d5fa19 100644 --- a/parachain/runtime/paseo/Cargo.toml +++ b/parachain/runtime/paseo/Cargo.toml @@ -353,7 +353,6 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime", - "frame-try-runtime?/try-runtime", "pallet-account-fix/try-runtime", "pallet-asset-manager/try-runtime", "pallet-assets-handler/try-runtime", diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index 38402cc395..107e9cfc55 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -102,6 +102,7 @@ pub mod constants; pub mod governance_v2; pub mod precompiles; +pub mod migration; #[cfg(test)] mod tests; pub mod weights; @@ -158,6 +159,7 @@ pub type Executive = frame_executive::Executive< // it was reverse order before. // See the comment before collation related pallets too. AllPalletsWithSystem, + migration::Migrations, >; impl fp_self_contained::SelfContainedCall for RuntimeCall { diff --git a/parachain/runtime/paseo/src/migration/migration.md b/parachain/runtime/paseo/src/migration/migration.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/parachain/runtime/paseo/src/migration/mod.rs b/parachain/runtime/paseo/src/migration/mod.rs new file mode 100644 index 0000000000..3b492ef07a --- /dev/null +++ b/parachain/runtime/paseo/src/migration/mod.rs @@ -0,0 +1,44 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// By the time of this migration on Paseo 9221 (polkadot stable2407) +// The current storage version: pallet version: +// xcmpQueue: - 3 +// transactionPayment: V2 0 +// vesting: V1 0 + +// Our target storage version: pallet version: (stable2407) +// xcmpQueue: - 3 => 5 +// transactionPayment: V2 0 +// vesting: V1 0 + +// In try-runtime, current implementation, the storage version is not checked, +// Pallet version is used instead. + +pub type Migrations = ( + // V3 to V4 + // XCMP QueueConfig has different default value + // Migration targeting at changing storage value to new default value if old value matched + // Our current Paseo setting has already hard-coded + // This migration should have no effect except bumping storage version + cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + // V4 to V5 + // Did nothing to storage + // Just checking MaxActiveOutboundChannels is not exceeded + // Our current Paseo Storage is 0 + // This migration should have no effect except bumping storage version + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, +); diff --git a/parachain/runtime/paseo/src/xcm_config.rs b/parachain/runtime/paseo/src/xcm_config.rs index c18fd3c7f2..ab90c4b9b5 100644 --- a/parachain/runtime/paseo/src/xcm_config.rs +++ b/parachain/runtime/paseo/src/xcm_config.rs @@ -244,3 +244,9 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; type PriceForSiblingDelivery = NoPriceForMessageDelivery; } + +// TODO:: remove after migration of storage version finished +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +}