Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{suspend, resume} xcm execution when {enter, exit}ing maintenance-mode #1359

Merged
merged 15 commits into from
Mar 25, 2022
Merged
44 changes: 37 additions & 7 deletions pallets/maintenance-mode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,34 @@ pub mod pallet {
use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler,
};
#[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,6 +103,9 @@ 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
#[cfg(feature = "xcm-support")]
type NormalDmpHandler: DmpMessageHandler;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the Handlers at all now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm I think we do, the new code just stops executing XCM in xcmp_queue::on_idle. I don't think it changes how messages are otherwise handled...

Expand Down Expand Up @@ -125,6 +143,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 +169,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 +185,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 +200,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 +216,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
2 changes: 2 additions & 0 deletions pallets/maintenance-mode/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ 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;
Expand Down
12 changes: 12 additions & 0 deletions runtime/moonbase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,17 @@ impl Contains<Call> for NormalFilter {
use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler,
};

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 Down Expand Up @@ -1217,6 +1228,7 @@ 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;
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!(<moonbase_runtime::Runtime as pallet_democracy::Config>::InstantAllowed::get());
Expand Down
11 changes: 11 additions & 0 deletions runtime/moonbeam/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,16 @@ impl Contains<Call> for NormalFilter {
}
}

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 Down Expand Up @@ -1164,6 +1174,7 @@ 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;
Expand Down
12 changes: 11 additions & 1 deletion runtime/moonbeam/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 All @@ -52,6 +52,16 @@ use xcm::latest::prelude::*;
use xcm::{VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation};
use xtokens_precompiles::Action as XtokensAction;

#[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!(
<moonbeam_runtime::Runtime as cumulus_pallet_xcmp_queue::Config
>::ControllerOrigin::ensure_origin(root_origin())
);
}

#[test]
fn fast_track_available() {
assert!(<moonbeam_runtime::Runtime as pallet_democracy::Config>::InstantAllowed::get());
Expand Down
11 changes: 11 additions & 0 deletions runtime/moonriver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,16 @@ impl Contains<Call> for NormalFilter {
}
}

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 Down Expand Up @@ -1194,6 +1204,7 @@ 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;
Expand Down
12 changes: 11 additions & 1 deletion runtime/moonriver/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 All @@ -50,6 +50,16 @@ use xcm::latest::prelude::*;
use xcm::{VersionedMultiAssets, VersionedMultiLocation};
use xtokens_precompiles::Action as XtokensAction;

#[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!(
<moonriver_runtime::Runtime as cumulus_pallet_xcmp_queue::Config
>::ControllerOrigin::ensure_origin(root_origin())
);
}

#[test]
fn fast_track_available() {
assert!(<moonriver_runtime::Runtime as pallet_democracy::Config>::InstantAllowed::get());
Expand Down