From 03df158a8b0060fb3b6a890bbd8a946a5ad094b4 Mon Sep 17 00:00:00 2001 From: Igor Papandinas <26460174+ipapandinas@users.noreply.github.com> Date: Tue, 18 Feb 2025 16:05:51 +0400 Subject: [PATCH] fix: add BonusUpdateState for migration --- pallets/dapp-staking/src/lib.rs | 96 ++++++++++++++------------- pallets/dapp-staking/src/migration.rs | 1 + pallets/dapp-staking/src/types.rs | 27 ++++++++ 3 files changed, 77 insertions(+), 47 deletions(-) diff --git a/pallets/dapp-staking/src/lib.rs b/pallets/dapp-staking/src/lib.rs index 22fa1ebbb..a8d778813 100644 --- a/pallets/dapp-staking/src/lib.rs +++ b/pallets/dapp-staking/src/lib.rs @@ -519,8 +519,8 @@ pub mod pallet { /// Temporary cursor to persist latest BonusStatus item updated. /// TODO: remove it once all BonusStatus are updated and this storage value is cleanup. #[pallet::storage] - pub type ActiveBonusUpdateCursor = - StorageValue<_, (T::AccountId, T::SmartContract), OptionQuery>; + pub type ActiveBonusUpdateState = + StorageValue<_, BonusUpdateStateFor, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { @@ -2707,55 +2707,60 @@ pub mod pallet { /// If no progress is made, `Err(_)` is returned. pub fn do_update(weight_limit: Weight) -> Result { // Find out if update is still in progress - let maybe_cursor = ActiveBonusUpdateCursor::::get(); + let init_bonus_update_state = ActiveBonusUpdateState::::get(); let mut consumed_weight = T::DbWeight::get().reads(1); - let mut new_cursor = None; + + if init_bonus_update_state == BonusUpdateStateFor::::Finished { + log::trace!( + target: LOG_TARGET, + "Update has finished, skipping any action." + ); + return Err(consumed_weight); + } + + let mut bonus_update_state = init_bonus_update_state.clone(); let mut entries_updated = 0u32; - let mut iter = if let Some(last_key_pair) = maybe_cursor.clone() { - StakerInfo::::iter_from(StakerInfo::::hashed_key_for( - last_key_pair.0, - last_key_pair.1, - )) - } else { - // Enable maintenance mode on the first run - // Likely to be already set in the runtime upgrade migration - ActiveProtocolState::::mutate(|state| { - state.maintenance = true; - }); - log::warn!("Maintenance mode enabled."); - consumed_weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); - StakerInfo::::iter() - }; + let mut iter = + if let BonusUpdateStateFor::::InProgress(last_key_pair) = &bonus_update_state { + StakerInfo::::iter_from(StakerInfo::::hashed_key_for( + last_key_pair.0.clone(), + last_key_pair.1.clone(), + )) + } else { + StakerInfo::::iter() + }; + let weight_margin = Self::update_weight_margin(); while weight_limit .saturating_sub(consumed_weight) - .all_gte(Self::update_weight_margin()) + .all_gte(weight_margin) { match Self::update_bonus_step(&mut iter) { Ok((weight, updated_cursor)) => { consumed_weight.saturating_accrue(weight); entries_updated.saturating_inc(); - new_cursor = Some(updated_cursor); + bonus_update_state = BonusUpdateStateFor::::InProgress(updated_cursor); } Err(weight) => { consumed_weight.saturating_accrue(weight); - new_cursor = None; // Mark migration as complete + bonus_update_state = BonusUpdateStateFor::::Finished; // Mark migration as complete break; } } } - if let Some(c) = new_cursor { - ActiveBonusUpdateCursor::::put(c); // Save latest progress - consumed_weight = T::DbWeight::get().writes(1); - } else if maybe_cursor.is_some() { - consumed_weight = T::DbWeight::get().reads_writes(1, 3); - ActiveBonusUpdateCursor::::take(); // Clear storage if update is finished + if bonus_update_state != init_bonus_update_state { + consumed_weight.saturating_accrue(T::DbWeight::get().writes(1)); + ActiveBonusUpdateState::::put(bonus_update_state.clone()); + } + + if bonus_update_state == crate::types::BonusUpdateStateFor::::Finished { + consumed_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); ActiveProtocolState::::mutate(|state| { state.maintenance = false; }); - log::warn!("Maintenance mode disabled."); + log::info!("Maintenance mode disabled."); } log::info!(target: LOG_TARGET, "🚚 updated entries {entries_updated}"); @@ -2764,26 +2769,23 @@ pub mod pallet { pub(crate) fn update_bonus_step( iter: &mut impl Iterator, - ) -> Result<(Weight, (T::AccountId, T::SmartContract)), Weight> { - let new_default_bonus_status = *BonusStatusWrapperFor::::default(); - - if let Some((account, smart_contract, staking_info)) = iter.next() { - let new_staking_info = SingularStakingInfo { - previous_staked: staking_info.previous_staked, - staked: staking_info.staked, - bonus_status: new_default_bonus_status, - }; + ) -> Result<(Weight, BonusUpdateCursorFor), Weight> { + iter.next() + .map(|(account, smart_contract, staking_info)| { + let new_staking_info = SingularStakingInfo { + previous_staked: staking_info.previous_staked, + staked: staking_info.staked, + bonus_status: *BonusStatusWrapperFor::::default(), + }; - StakerInfo::::insert(&account, &smart_contract, new_staking_info); + StakerInfo::::insert(&account, &smart_contract, new_staking_info); - Ok(( - ::WeightInfo::update_bonus_step_success(), - (account, smart_contract), // new cursor - )) - } else { - // No more entries to process, update is finished - Err(::WeightInfo::update_bonus_step_noop()) - } + Ok(( + ::WeightInfo::update_bonus_step_success(), + (account, smart_contract), + )) + }) + .unwrap_or_else(|| Err(::WeightInfo::update_bonus_step_noop())) } /// Max allowed weight that update should be allowed to consume. diff --git a/pallets/dapp-staking/src/migration.rs b/pallets/dapp-staking/src/migration.rs index 013395b58..16c87e505 100644 --- a/pallets/dapp-staking/src/migration.rs +++ b/pallets/dapp-staking/src/migration.rs @@ -79,6 +79,7 @@ mod v9 { ActiveProtocolState::::mutate(|state| { state.maintenance = true; }); + log::info!("Maintenance mode enabled."); // In case of try-runtime, we want to execute the whole logic, to ensure it works // with on-chain data. diff --git a/pallets/dapp-staking/src/types.rs b/pallets/dapp-staking/src/types.rs index 8d6163e0a..0d5da12e2 100644 --- a/pallets/dapp-staking/src/types.rs +++ b/pallets/dapp-staking/src/types.rs @@ -98,6 +98,33 @@ pub type DAppInfoFor = DAppInfo<::AccountId>; // Convenience type for `BonusStatusWrapper` usage. pub type BonusStatusWrapperFor = BonusStatusWrapper<::MaxBonusSafeMovesPerPeriod>; +/// TODO: remove it once all BonusStatus are updated and the `ActiveBonusUpdateCursor` storage value is cleanup. +pub type BonusUpdateStateFor = + BonusUpdateState<::AccountId, ::SmartContract>; + +pub type BonusUpdateCursorFor = ( + ::AccountId, + ::SmartContract, +); + +pub type BonusUpdateCursor = (AccountId, SmartContract); + +#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug, PartialEq, Eq, TypeInfo)] +pub enum BonusUpdateState { + /// No update in progress yet + NotInProgress, + /// Update in progress for the current cursor + InProgress(BonusUpdateCursor), + /// All updates have been finished + Finished, +} + +impl Default for BonusUpdateState { + fn default() -> Self { + BonusUpdateState::::NotInProgress + } +} + /// Simple enum representing errors possible when using sparse bounded vector. #[derive(Debug, PartialEq, Eq)] pub enum AccountLedgerError {