Skip to content

Commit

Permalink
{suspend, resume} xcm execution when {enter, exit}ing maintenance-mode (
Browse files Browse the repository at this point in the history
  • Loading branch information
4meta5 authored Mar 25, 2022
1 parent 3102faf commit c582e2f
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 129 deletions.
68 changes: 40 additions & 28 deletions pallets/maintenance-mode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,36 @@ pub use pallet::*;
pub mod pallet {
#[cfg(feature = "xcm-support")]
use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler,
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler,
};
#[cfg(feature = "xcm-support")]
use sp_std::vec::Vec;

use frame_support::pallet_prelude::*;
use frame_support::traits::{
Contains, EnsureOrigin, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade,
};
use frame_system::pallet_prelude::*;
use sp_runtime::DispatchResult;
#[cfg(feature = "xcm-support")]
use sp_std::vec::Vec;
/// Pallet for migrations
#[pallet::pallet]
#[pallet::without_storage_info]
pub struct Pallet<T>(PhantomData<T>);

/// Pause and resume execution of XCM
pub trait PauseXcmExecution {
fn suspend_xcm_execution() -> DispatchResult;
fn resume_xcm_execution() -> DispatchResult;
}

impl PauseXcmExecution for () {
fn suspend_xcm_execution() -> DispatchResult {
Ok(())
}
fn resume_xcm_execution() -> DispatchResult {
Ok(())
}
}

/// Configuration trait of this pallet.
#[pallet::config]
pub trait Config: frame_system::Config {
Expand All @@ -88,18 +103,17 @@ pub mod pallet {
/// able to return to normal mode. For example, if your MaintenanceOrigin is a council, make
/// sure that your councilors can still cast votes.
type MaintenanceOrigin: EnsureOrigin<Self::Origin>;
/// Handler to suspend and resume XCM execution
#[cfg(feature = "xcm-support")]
type XcmExecutionManager: PauseXcmExecution;
/// The DMP handler to be used in normal operating mode
/// TODO: remove once https://github.com/paritytech/polkadot/pull/5035 is merged
#[cfg(feature = "xcm-support")]
type NormalDmpHandler: DmpMessageHandler;
/// The DMP handler to be used in maintenance mode
/// TODO: remove once https://github.com/paritytech/polkadot/pull/5035 is merged
#[cfg(feature = "xcm-support")]
type MaintenanceDmpHandler: DmpMessageHandler;
/// The XCMP handler to be used in normal operating mode
#[cfg(feature = "xcm-support")]
type NormalXcmpHandler: XcmpMessageHandler;
/// The XCMP handler to be used in maintenance mode
#[cfg(feature = "xcm-support")]
type MaintenanceXcmpHandler: XcmpMessageHandler;
/// The executive hooks that will be used in normal operating mode
/// Important: Use AllPalletsReversedWithSystemFirst here if you dont want to modify the
/// hooks behaviour
Expand All @@ -125,6 +139,10 @@ pub mod pallet {
EnteredMaintenanceMode,
/// The chain returned to its normal operating state
NormalOperationResumed,
/// The call to suspend on_idle XCM execution failed with inner error
FailedToSuspendIdleXcmExecution { error: DispatchError },
/// The call to resume on_idle XCM execution failed with inner error
FailedToResumeIdleXcmExecution { error: DispatchError },
}

/// An error that can occur while executing this pallet's extrinsics.
Expand All @@ -147,8 +165,8 @@ pub mod pallet {
///
/// Weight cost is:
/// * One DB read to ensure we're not already in maintenance mode
/// * Two DB writes - 1 for the mode and 1 for the event
#[pallet::weight(T::DbWeight::get().read + 2 * T::DbWeight::get().write)]
/// * Three DB writes - 1 for the mode, 1 for suspending xcm execution, 1 for the event
#[pallet::weight(T::DbWeight::get().read + 3 * T::DbWeight::get().write)]
pub fn enter_maintenance_mode(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// Ensure Origin
T::MaintenanceOrigin::ensure_origin(origin)?;
Expand All @@ -163,6 +181,10 @@ pub mod pallet {

// Write to storage
MaintenanceMode::<T>::put(true);
// Suspend XCM execution
if let Err(error) = T::XcmExecutionManager::suspend_xcm_execution() {
<Pallet<T>>::deposit_event(Event::FailedToSuspendIdleXcmExecution { error });
}

// Event
<Pallet<T>>::deposit_event(Event::EnteredMaintenanceMode);
Expand All @@ -174,8 +196,8 @@ pub mod pallet {
///
/// Weight cost is:
/// * One DB read to ensure we're in maintenance mode
/// * Two DB writes - 1 for the mode and 1 for the event
#[pallet::weight(T::DbWeight::get().read + 2 * T::DbWeight::get().write)]
/// * Three DB writes - 1 for the mode, 1 for resuming xcm execution, 1 for the event
#[pallet::weight(T::DbWeight::get().read + 3 * T::DbWeight::get().write)]
pub fn resume_normal_operation(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// Ensure Origin
T::MaintenanceOrigin::ensure_origin(origin)?;
Expand All @@ -190,6 +212,10 @@ pub mod pallet {

// Write to storage
MaintenanceMode::<T>::put(false);
// Resume XCM execution
if let Err(error) = T::XcmExecutionManager::resume_xcm_execution() {
<Pallet<T>>::deposit_event(Event::FailedToResumeIdleXcmExecution { error });
}

// Event
<Pallet<T>>::deposit_event(Event::NormalOperationResumed);
Expand Down Expand Up @@ -237,18 +263,4 @@ pub mod pallet {
}
}
}

#[cfg(feature = "xcm-support")]
impl<T: Config> XcmpMessageHandler for Pallet<T> {
fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
iter: I,
limit: Weight,
) -> Weight {
if MaintenanceMode::<T>::get() {
T::MaintenanceXcmpHandler::handle_xcmp_messages(iter, limit)
} else {
T::NormalXcmpHandler::handle_xcmp_messages(iter, limit)
}
}
}
}
36 changes: 3 additions & 33 deletions pallets/maintenance-mode/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
//! A minimal runtime including the maintenance-mode pallet
use super::*;
use crate as pallet_maintenance_mode;
use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler,
};
use cumulus_primitives_core::{relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler};
use frame_support::{
construct_runtime, parameter_types,
traits::{
Expand Down Expand Up @@ -98,32 +96,6 @@ impl Contains<Call> for MaintenanceCallFilter {
}
}

pub struct MaintenanceXcmpHandler;
#[cfg(feature = "xcm-support")]
impl XcmpMessageHandler for MaintenanceXcmpHandler {
// This implementation makes messages be queued
// Since the limit is 0, messages are queued for next iteration
fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
_iter: I,
_limit: Weight,
) -> Weight {
return 1;
}
}

pub struct NormalXcmpHandler;
#[cfg(feature = "xcm-support")]
impl XcmpMessageHandler for NormalXcmpHandler {
// This implementation makes messages be queued
// Since the limit is 0, messages are queued for next iteration
fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
_iter: I,
_limit: Weight,
) -> Weight {
return 0;
}
}

pub struct MaintenanceDmpHandler;
#[cfg(feature = "xcm-support")]
impl DmpMessageHandler for MaintenanceDmpHandler {
Expand Down Expand Up @@ -284,13 +256,11 @@ impl Config for Test {
type MaintenanceCallFilter = MaintenanceCallFilter;
type MaintenanceOrigin = EnsureRoot<AccountId>;
#[cfg(feature = "xcm-support")]
type XcmExecutionManager = ();
#[cfg(feature = "xcm-support")]
type NormalDmpHandler = NormalDmpHandler;
#[cfg(feature = "xcm-support")]
type MaintenanceDmpHandler = MaintenanceDmpHandler;
#[cfg(feature = "xcm-support")]
type NormalXcmpHandler = NormalXcmpHandler;
#[cfg(feature = "xcm-support")]
type MaintenanceXcmpHandler = MaintenanceXcmpHandler;
type NormalExecutiveHooks = NormalHooks;
type MaitenanceExecutiveHooks = MaintenanceHooks;
}
Expand Down
14 changes: 3 additions & 11 deletions pallets/maintenance-mode/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::mock::{
events, mock_events, Call as OuterCall, ExtBuilder, MaintenanceMode, Origin, Test,
};
use crate::{Call, Error, Event, ExecutiveHooks};
use cumulus_primitives_core::{DmpMessageHandler, XcmpMessageHandler};
use cumulus_primitives_core::DmpMessageHandler;
use frame_support::{
assert_noop, assert_ok,
dispatch::Dispatchable,
Expand Down Expand Up @@ -126,7 +126,7 @@ fn cannot_resume_normal_operation_while_already_operating_normally() {

#[cfg(feature = "xcm-support")]
#[test]
fn normal_dmp_and_xcmp_in_non_maintenance() {
fn normal_dmp_in_non_maintenance() {
ExtBuilder::default()
.with_maintenance_mode(false)
.build()
Expand All @@ -135,16 +135,12 @@ fn normal_dmp_and_xcmp_in_non_maintenance() {
MaintenanceMode::handle_dmp_messages(vec![].into_iter(), 1),
0
);
assert_eq!(
MaintenanceMode::handle_xcmp_messages(vec![].into_iter(), 1),
0
);
})
}

#[cfg(feature = "xcm-support")]
#[test]
fn maintenance_dmp_and_xcmp_in_maintenance() {
fn maintenance_dmp_in_maintenance() {
ExtBuilder::default()
.with_maintenance_mode(true)
.build()
Expand All @@ -153,10 +149,6 @@ fn maintenance_dmp_and_xcmp_in_maintenance() {
MaintenanceMode::handle_dmp_messages(vec![].into_iter(), 1),
1
);
assert_eq!(
MaintenanceMode::handle_xcmp_messages(vec![].into_iter(), 1),
1
);
})
}

Expand Down
32 changes: 14 additions & 18 deletions runtime/moonbase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type DmpMessageHandler = MaintenanceMode;
type ReservedDmpWeight = ReservedDmpWeight;
type OutboundXcmpMessageSource = XcmpQueue;
type XcmpMessageHandler = MaintenanceMode;
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
}

Expand Down Expand Up @@ -1051,9 +1051,18 @@ impl Contains<Call> for NormalFilter {
}
}

use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler,
};
use cumulus_primitives_core::{relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler};

pub struct XcmExecutionManager;
impl pallet_maintenance_mode::PauseXcmExecution for XcmExecutionManager {
fn suspend_xcm_execution() -> DispatchResult {
XcmpQueue::suspend_xcm_execution(Origin::root())
}
fn resume_xcm_execution() -> DispatchResult {
XcmpQueue::resume_xcm_execution(Origin::root())
}
}

pub struct MaintenanceDmpHandler;
impl DmpMessageHandler for MaintenanceDmpHandler {
// This implementation makes messages be queued
Expand All @@ -1066,18 +1075,6 @@ impl DmpMessageHandler for MaintenanceDmpHandler {
}
}

pub struct MaintenanceXcmpHandler;
impl XcmpMessageHandler for MaintenanceXcmpHandler {
// This implementation makes messages be queued
// Since the limit is 0, messages are queued for next iteration
fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
iter: I,
_limit: Weight,
) -> Weight {
XcmpQueue::handle_xcmp_messages(iter, 0)
}
}

/// The hooks we wnat to run in Maintenance Mode
pub struct MaintenanceHooks;

Expand Down Expand Up @@ -1132,10 +1129,9 @@ impl pallet_maintenance_mode::Config for Runtime {
type MaintenanceCallFilter = MaintenanceFilter;
type MaintenanceOrigin =
pallet_collective::EnsureProportionAtLeast<_2, _3, AccountId, TechCommitteeInstance>;
type XcmExecutionManager = XcmExecutionManager;
type NormalDmpHandler = DmpQueue;
type MaintenanceDmpHandler = MaintenanceDmpHandler;
type NormalXcmpHandler = XcmpQueue;
type MaintenanceXcmpHandler = MaintenanceXcmpHandler;
// We use AllPalletsReversedWithSystemFirst because we dont want to change the hooks in normal
// operation
type NormalExecutiveHooks = AllPalletsReversedWithSystemFirst;
Expand Down
12 changes: 11 additions & 1 deletion runtime/moonbase/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use fp_evm::{Context, ExitSucceed, PrecompileOutput};
use frame_support::{
assert_noop, assert_ok,
dispatch::Dispatchable,
traits::{fungible::Inspect, PalletInfo, StorageInfo, StorageInfoTrait},
traits::{fungible::Inspect, EnsureOrigin, PalletInfo, StorageInfo, StorageInfoTrait},
weights::{DispatchClass, Weight},
StorageHasher, Twox128,
};
Expand Down Expand Up @@ -53,6 +53,16 @@ use sp_runtime::{
};
use xcm::latest::prelude::*;

#[test]
fn xcmp_queue_controller_origin_is_root() {
// important for the XcmExecutionManager impl of PauseExecution which uses root origin
// to suspend/resume XCM execution in xcmp_queue::on_idle
assert_ok!(
<moonbase_runtime::Runtime as cumulus_pallet_xcmp_queue::Config
>::ControllerOrigin::ensure_origin(root_origin())
);
}

#[test]
fn fast_track_available() {
assert!(get!(pallet_democracy, InstantAllowed, bool));
Expand Down
Loading

0 comments on commit c582e2f

Please sign in to comment.