--- a/pallets/app-promotion/src/lib.rs +++ b/pallets/app-promotion/src/lib.rs @@ -153,6 +153,9 @@ #[pallet::constant] type Nominal: Get>; + /// Maintenance mode status. + type IsMaintenanceModeEnabled: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -288,6 +291,10 @@ where ::BlockNumber: From, { + if T::IsMaintenanceModeEnabled::get() { + return T::DbWeight::get().reads_writes(1, 0); + } + let block_pending = PendingUnstake::::take(current_block_number); let counter = block_pending.len() as u32; @@ -846,7 +853,7 @@ .into_iter() .try_for_each(|s| -> Result<_, DispatchError> { if let Some(BalanceLock { amount, .. }) = Self::get_locked_balance(&s) { - if let Some(_) = Self::get_frozen_balance(&s) { + if Self::get_frozen_balance(&s).is_some() { return Err(Error::::InconsistencyState.into()); } @@ -864,6 +871,47 @@ Ok(()) } + + /// Called for blocks that, for some reason, have not been unstacked + /// + /// # Permissions + /// + /// * Sudo + /// + /// # Arguments + /// + /// * `origin`: Must be `Signed`. + /// * `pending_blocks`: Block numbers that will be processed. + #[pallet::call_index(10)] + #[pallet::weight(::WeightInfo::on_initialize(PENDING_LIMIT_PER_BLOCK*pending_blocks.len() as u32))] + pub fn force_unstake( + origin: OriginFor, + pending_blocks: Vec, + ) -> DispatchResult { + ensure_root(origin)?; + + ensure!( + pending_blocks + .iter() + .all(|b| *b < >::block_number()), + >::NoPermission + ); + + let mut pendings = + Vec::with_capacity(PENDING_LIMIT_PER_BLOCK as usize * pending_blocks.len()); + pending_blocks + .into_iter() + .for_each(|b| pendings.append(&mut PendingUnstake::::take(b).into_inner())); + + pendings.into_iter().for_each(|(staker, amount)| { + Self::get_frozen_balance(&staker).map(|b| { + let new_state = b.checked_sub(&amount).unwrap_or_default(); + Self::set_freeze_unchecked(&staker, new_state); + }); + }); + + Ok(()) + } } } @@ -1158,7 +1206,7 @@ } fn get_next_calculated_key() -> Option> { - Self::get_next_calculated_record().map(|key| Staked::::hashed_key_for(key)) + Self::get_next_calculated_record().map(Staked::::hashed_key_for) } }