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
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;
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...

/// 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