From 0096d7af5a2233907e8015f04f30bcd924306d34 Mon Sep 17 00:00:00 2001 From: Igor Papandinas <26460174+ipapandinas@users.noreply.github.com> Date: Wed, 5 Mar 2025 10:18:19 +0100 Subject: [PATCH] use versioned migration --- pallets/dapp-staking/src/migration.rs | 502 +------------------------- runtime/shiden/src/lib.rs | 16 +- 2 files changed, 10 insertions(+), 508 deletions(-) diff --git a/pallets/dapp-staking/src/migration.rs b/pallets/dapp-staking/src/migration.rs index ed83b2c12..09c66317d 100644 --- a/pallets/dapp-staking/src/migration.rs +++ b/pallets/dapp-staking/src/migration.rs @@ -21,7 +21,6 @@ use core::marker::PhantomData; use frame_support::{ migration::clear_storage_prefix, migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, - storage_alias, traits::{GetStorageVersion, OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}, weights::WeightMeter, }; @@ -36,33 +35,12 @@ use sp_runtime::TryRuntimeError; pub mod versioned_migrations { use super::*; - /// Migration V6 to V7 wrapped in a [`frame_support::migrations::VersionedMigration`], ensuring - /// the migration is only performed when on-chain version is 6. - pub type V6ToV7 = frame_support::migrations::VersionedMigration< - 6, - 7, - v7::VersionMigrateV6ToV7, - Pallet, - ::DbWeight, - >; - - /// Migration V7 to V8 wrapped in a [`frame_support::migrations::VersionedMigration`], ensuring - /// the migration is only performed when on-chain version is 7. - pub type V7ToV8 = - frame_support::migrations::VersionedMigration< - 7, - 8, - v8::VersionMigrateV7ToV8, - Pallet, - ::DbWeight, - >; - /// Migration V8 to V9 wrapped in a [`frame_support::migrations::VersionedMigration`], ensuring /// the migration is only performed when on-chain version is 9. - pub type V8ToV9 = frame_support::migrations::VersionedMigration< + pub type V8ToV9 = frame_support::migrations::VersionedMigration< 8, 9, - v9::VersionMigrateV8ToV9, + v9::VersionMigrateV8ToV9, Pallet, ::DbWeight, >; @@ -70,490 +48,28 @@ pub mod versioned_migrations { mod v9 { use super::*; - use frame_support::DefaultNoBound; - - #[derive( - Encode, - Decode, - MaxEncodedLen, - RuntimeDebugNoBound, - PartialEqNoBound, - DefaultNoBound, - EqNoBound, - CloneNoBound, - TypeInfo, - )] - #[scale_info(skip_type_params(NT))] - pub struct TierParametersV8> { - /// Reward distribution per tier, in percentage. - /// First entry refers to the first tier, and so on. - /// The sum of all values must not exceed 100%. - /// In case it is less, portion of rewards will never be distributed. - pub(crate) reward_portion: BoundedVec, - /// Distribution of number of slots per tier, in percentage. - /// First entry refers to the first tier, and so on. - /// The sum of all values must not exceed 100%. - /// In case it is less, slot capacity will never be fully filled. - pub(crate) slot_distribution: BoundedVec, - /// Requirements for entry into each tier. - /// First entry refers to the first tier, and so on. - pub(crate) tier_thresholds: BoundedVec, - } - // The loyal staker flag is updated to `u8` with the new MaxBonusSafeMovesPerPeriod from config - // for all already existing StakerInfo. - pub struct VersionMigrateV8ToV9(PhantomData<(T, InitArgs)>); + // Only update pallet version + pub struct VersionMigrateV8ToV9(PhantomData); - impl> UncheckedOnRuntimeUpgrade - for VersionMigrateV8ToV9 - { + impl UncheckedOnRuntimeUpgrade for VersionMigrateV8ToV9 { fn on_runtime_upgrade() -> Weight { - let result = StaticTierParams::::translate::, _>( - |maybe_old_params| match maybe_old_params { - Some(old_params) => Some(TierParameters { - slot_distribution: old_params.slot_distribution, - reward_portion: old_params.reward_portion, - tier_thresholds: old_params.tier_thresholds, - slot_number_args: InitArgs::get(), - }), - _ => None, - }, - ); - - if result.is_err() { - log::error!("Failed to translate StaticTierParams from previous V8 type to current V9 type."); - // Enable maintenance mode. - ActiveProtocolState::::mutate(|state| { - state.maintenance = true; - }); - log::warn!("Maintenance mode enabled."); - return T::DbWeight::get().reads_writes(2, 1); - } - - T::DbWeight::get().reads_writes(1, 1) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - assert!( - !ActiveProtocolState::::get().maintenance, - "Maintenance mode must be disabled before the runtime upgrade." - ); - Ok(Vec::new()) + Weight::zero() } #[cfg(feature = "try-runtime")] fn post_upgrade(_: Vec) -> Result<(), TryRuntimeError> { - assert!( - Pallet::::on_chain_storage_version() >= 9, + assert_eq!( + Pallet::::on_chain_storage_version(), + EXPECTED_PALLET_DAPP_STAKING_VERSION, "dapp-staking::migration::v9: wrong storage version" ); - assert!( - !ActiveProtocolState::::get().maintenance, - "Maintenance mode must be disabled after the successful runtime upgrade." - ); - - let new_tier_params = StaticTierParams::::get(); - assert!( - new_tier_params.is_valid(), - "New tier params are invalid, re-check the values!" - ); - assert_eq!(new_tier_params.slot_number_args, InitArgs::get()); - - Ok(()) - } - } -} - -// TierThreshold as percentage of the total issuance -pub mod v8 { - use super::*; - use crate::migration::v7::TierParameters as TierParametersV7; - use crate::migration::v7::TiersConfiguration as TiersConfigurationV7; - - /// Information about how much a particular staker staked on a particular smart contract. - #[derive( - Encode, Decode, MaxEncodedLen, Copy, Clone, Debug, PartialEq, Eq, TypeInfo, Default, - )] - pub struct SingularStakingInfo { - /// Amount staked before, if anything. - pub(crate) previous_staked: StakeAmount, - /// Staked amount - pub(crate) staked: StakeAmount, - /// Indicates whether a staker is a loyal staker or not. - pub(crate) loyal_staker: bool, - } - - /// v8 type for [`crate::StakerInfo`] - #[storage_alias] - pub type StakerInfo = StorageDoubleMap< - Pallet, - Blake2_128Concat, - ::AccountId, - Blake2_128Concat, - ::SmartContract, - SingularStakingInfo, - OptionQuery, - >; - - pub struct VersionMigrateV7ToV8( - PhantomData<(T, TierThresholds, ThresholdVariationPercentage)>, - ); - - impl< - T: Config, - TierThresholds: Get<[TierThreshold; 4]>, - ThresholdVariationPercentage: Get, - > UncheckedOnRuntimeUpgrade - for VersionMigrateV7ToV8 - { - fn on_runtime_upgrade() -> Weight { - // 1. Update static tier parameters with new thresholds from the runtime configurable param TierThresholds - let result = StaticTierParams::::translate::, _>( - |maybe_old_params| match maybe_old_params { - Some(old_params) => { - let tier_thresholds: Result< - BoundedVec, - _, - > = BoundedVec::try_from(TierThresholds::get().to_vec()); - - match tier_thresholds { - Ok(tier_thresholds) => Some(TierParameters { - slot_distribution: old_params.slot_distribution, - reward_portion: old_params.reward_portion, - tier_thresholds, - slot_number_args: Default::default(), - }), - Err(err) => { - log::error!( - "Failed to convert TierThresholds parameters: {:?}", - err - ); - None - } - } - } - _ => None, - }, - ); - - if result.is_err() { - log::error!("Failed to translate StaticTierParams from previous V7 type to current V8 type. Check TierParametersV7 decoding."); - // Enable maintenance mode. - ActiveProtocolState::::mutate(|state| { - state.maintenance = true; - }); - log::warn!("Maintenance mode enabled."); - return T::DbWeight::get().reads_writes(1, 0); - } - - // 2. Translate tier thresholds from V7 TierThresholds to Balance - let result = TierConfig::::translate::< - TiersConfigurationV7, - _, - >(|maybe_old_config| match maybe_old_config { - Some(old_config) => { - let new_tier_thresholds: Result, _> = - old_config - .tier_thresholds - .iter() - .map(|t| match t { - v7::TierThreshold::DynamicTvlAmount { amount, .. } => *amount, - v7::TierThreshold::FixedTvlAmount { amount } => *amount, - }) - .collect::>() - .try_into(); - - match new_tier_thresholds { - Ok(new_tier_thresholds) => Some(TiersConfiguration { - slots_per_tier: old_config.slots_per_tier, - reward_portion: old_config.reward_portion, - tier_thresholds: new_tier_thresholds, - _phantom: Default::default(), - }), - Err(err) => { - log::error!("Failed to convert tier thresholds to balances: {:?}", err); - None - } - } - } - _ => None, - }); - - if result.is_err() { - log::error!("Failed to translate TierConfig from previous V7 type to current V8 type. Check TiersConfigurationV7 decoding."); - // Enable maintenance mode. - ActiveProtocolState::::mutate(|state| { - state.maintenance = true; - }); - log::warn!("Maintenance mode enabled."); - return T::DbWeight::get().reads_writes(2, 1); - } - - T::DbWeight::get().reads_writes(2, 2) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let tier_thresholds: Result, _> = - BoundedVec::try_from(TierThresholds::get().to_vec()); - assert!(tier_thresholds.is_ok()); - - let old_config = v7::TierConfig::::get().ok_or_else(|| { - TryRuntimeError::Other( - "dapp-staking::migration::v8: No old configuration found for TierConfig", - ) - })?; - Ok((old_config.number_of_slots, old_config.tier_thresholds).encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(data: Vec) -> Result<(), TryRuntimeError> { - let (old_number_of_slots, old_tier_thresholds): ( - u16, - BoundedVec, - ) = Decode::decode(&mut &data[..]).map_err(|_| { - TryRuntimeError::Other( - "dapp-staking::migration::v8: Failed to decode old v7 version of tier config", - ) - })?; - - // 0. Prerequisites - let actual_config = TierConfig::::get(); - assert!(actual_config.is_valid()); - - ensure!( - Pallet::::on_chain_storage_version() >= 8, - "dapp-staking::migration::v8: Wrong storage version." - ); - - // 1. Ensure the number of slots is preserved - let actual_number_of_slots = actual_config.total_number_of_slots(); - let within_tolerance = - (old_number_of_slots.saturating_sub(1))..=old_number_of_slots.saturating_add(1); - - assert!( - within_tolerance.contains(&actual_number_of_slots), - "dapp-staking::migration::v8: New TiersConfiguration format not set correctly, number of slots has diverged. Old: {}. Actual: {}.", - old_number_of_slots, - actual_number_of_slots - ); - - // 2. Ensure the provided static tier params are applied - let actual_tier_params = StaticTierParams::::get(); - assert!(actual_tier_params.is_valid()); - - let expected_tier_thresholds: Result, _> = - BoundedVec::try_from(TierThresholds::get().to_vec()); - ensure!( - expected_tier_thresholds.is_ok(), - "dapp-staking::migration::v8: Failed to convert expected tier thresholds." - ); - let actual_tier_thresholds = actual_tier_params.clone().tier_thresholds; - assert_eq!(expected_tier_thresholds.unwrap(), actual_tier_thresholds); - - // 3. Double check new threshold amounts allowing - let variation_percentage = ThresholdVariationPercentage::get(); - let total_issuance = T::Currency::total_issuance(); - let average_price = T::NativePriceProvider::average_price(); - - let old_threshold_amounts: Result, _> = - old_tier_thresholds - .iter() - .map(|t| t.threshold()) - .collect::>() - .try_into(); - - ensure!( - old_threshold_amounts.is_ok(), - "dapp-staking::migration::v8: Failed to convert old v7 version tier thresholds to balance amounts." - ); - let old_threshold_amounts = old_threshold_amounts.unwrap(); - let expected_new_threshold_amounts = actual_config - .calculate_new(&actual_tier_params, average_price, total_issuance) - .tier_thresholds; - - for (old_amount, actual_amount) in old_threshold_amounts - .iter() - .zip(expected_new_threshold_amounts) - { - let lower_bound = old_amount - .saturating_mul(100u32.saturating_sub(variation_percentage).into()) - .saturating_div(100u32.into()); - let upper_bound = old_amount - .saturating_mul(100u32.saturating_add(variation_percentage).into()) - .saturating_div(100u32.into()); - - assert!( - (lower_bound..=upper_bound).contains(&actual_amount), - "dapp-staking::migration::v8: New tier threshold amounts diverged to much from old values, consider adjusting static tier parameters. Old: {}. Actual: {}.", - old_amount, - actual_amount - ); - } - - Ok(()) - } - } -} -/// Translate DAppTiers to include rank rewards. -mod v7 { - use super::*; - use crate::migration::v6::DAppTierRewards as DAppTierRewardsV6; - use astar_primitives::dapp_staking::TierSlots as TierSlotsFunc; - - /// Description of tier entry requirement. - #[derive(Encode, Decode)] - pub enum TierThreshold { - FixedTvlAmount { - amount: Balance, - }, - DynamicTvlAmount { - amount: Balance, - minimum_amount: Balance, - }, - } - - #[cfg(feature = "try-runtime")] - impl TierThreshold { - /// Return threshold for the tier. - pub fn threshold(&self) -> Balance { - match self { - Self::FixedTvlAmount { amount } => *amount, - Self::DynamicTvlAmount { amount, .. } => *amount, - } - } - } - - /// Top level description of tier slot parameters used to calculate tier configuration. - #[derive(Encode, Decode)] - pub struct TierParameters> { - /// Reward distribution per tier, in percentage. - /// First entry refers to the first tier, and so on. - /// The sum of all values must not exceed 100%. - /// In case it is less, portion of rewards will never be distributed. - pub reward_portion: BoundedVec, - /// Distribution of number of slots per tier, in percentage. - /// First entry refers to the first tier, and so on. - /// The sum of all values must not exceed 100%. - /// In case it is less, slot capacity will never be fully filled. - pub slot_distribution: BoundedVec, - /// Requirements for entry into each tier. - /// First entry refers to the first tier, and so on. - pub tier_thresholds: BoundedVec, - } - - /// v7 type for configuration of dApp tiers. - #[derive(Encode, Decode)] - pub struct TiersConfiguration, T: TierSlotsFunc, P: Get> { - /// Total number of slots. - #[codec(compact)] - pub number_of_slots: u16, - /// Number of slots per tier. - /// First entry refers to the first tier, and so on. - pub slots_per_tier: BoundedVec, - /// Reward distribution per tier, in percentage. - /// First entry refers to the first tier, and so on. - /// The sum of all values must be exactly equal to 1. - pub reward_portion: BoundedVec, - /// Requirements for entry into each tier. - /// First entry refers to the first tier, and so on. - pub tier_thresholds: BoundedVec, - /// Phantom data to keep track of the tier slots function. - #[codec(skip)] - pub(crate) _phantom: PhantomData<(T, P)>, - } - - /// v7 type for [`crate::StaticTierParams`] - #[storage_alias] - pub type StaticTierParams = - StorageValue, TierParameters<::NumberOfTiers>, ValueQuery>; - - /// v7 type for [`crate::TierConfig`] - #[storage_alias] - pub type TierConfig = StorageValue< - Pallet, - TiersConfiguration< - ::NumberOfTiers, - ::TierSlots, - ::BaseNativeCurrencyPrice, - >, - OptionQuery, - >; - - pub struct VersionMigrateV6ToV7(PhantomData); - - impl UncheckedOnRuntimeUpgrade for VersionMigrateV6ToV7 { - fn on_runtime_upgrade() -> Weight { - let current = Pallet::::in_code_storage_version(); - - let mut translated = 0usize; - DAppTiers::::translate::< - DAppTierRewardsV6, - _, - >(|_key, old_value| { - translated.saturating_inc(); - - // fill rank_rewards with zero - let mut rank_rewards = Vec::new(); - rank_rewards.resize_with(old_value.rewards.len(), || Balance::zero()); - - Some(DAppTierRewards { - dapps: old_value.dapps, - rewards: old_value.rewards, - period: old_value.period, - rank_rewards: BoundedVec::::try_from(rank_rewards) - .unwrap_or_default(), - }) - }); - - current.put::>(); - - log::info!("Upgraded {translated} dAppTiers to {current:?}"); - - T::DbWeight::get().reads_writes(1 + translated as u64, 1 + translated as u64) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - Ok(Vec::new()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_data: Vec) -> Result<(), TryRuntimeError> { - ensure!( - Pallet::::on_chain_storage_version() >= 7, - "dapp-staking::migration::v7: wrong storage version" - ); Ok(()) } } } -pub mod v6 { - use astar_primitives::{ - dapp_staking::{DAppId, PeriodNumber, RankedTier}, - Balance, - }; - use frame_support::{ - pallet_prelude::{Decode, Get}, - BoundedBTreeMap, BoundedVec, - }; - - /// Information about all of the dApps that got into tiers, and tier rewards - #[derive(Decode)] - pub struct DAppTierRewards, NT: Get> { - /// DApps and their corresponding tiers (or `None` if they have been claimed in the meantime) - pub dapps: BoundedBTreeMap, - /// Rewards for each tier. First entry refers to the first tier, and so on. - pub rewards: BoundedVec, - /// Period during which this struct was created. - #[codec(compact)] - pub period: PeriodNumber, - } -} - const PALLET_MIGRATIONS_ID: &[u8; 16] = b"dapp-staking-mbm"; pub struct LazyMigration(PhantomData<(T, W)>); diff --git a/runtime/shiden/src/lib.rs b/runtime/shiden/src/lib.rs index 0b0fe3510..ef83cbb3c 100644 --- a/runtime/shiden/src/lib.rs +++ b/runtime/shiden/src/lib.rs @@ -1284,22 +1284,8 @@ pub type Executive = frame_executive::Executive< /// __NOTE:__ THE ORDER IS IMPORTANT. pub type Migrations = (Unreleased, Permanent); -use frame_support::traits::{OnRuntimeUpgrade, StorageVersion}; -use pallet_dapp_staking::migration::EXPECTED_PALLET_DAPP_STAKING_VERSION; - -// Bump dAppStaking pallet version to 9 (move extrinsic release) -pub struct BumpDappStakingVersion; - -impl OnRuntimeUpgrade for BumpDappStakingVersion { - fn on_runtime_upgrade() -> Weight { - StorageVersion::new(EXPECTED_PALLET_DAPP_STAKING_VERSION) - .put::>(); - ::DbWeight::get().writes(1) - } -} - /// Unreleased migrations. Add new ones here: -pub type Unreleased = BumpDappStakingVersion; +pub type Unreleased = pallet_dapp_staking::migration::versioned_migrations::V8ToV9; /// Migrations/checks that do not need to be versioned and can run on every upgrade. pub type Permanent = (pallet_xcm::migration::MigrateToLatestXcmVersion,);