diff --git a/pallets/maintenance-mode/src/lib.rs b/pallets/maintenance-mode/src/lib.rs index 51ad775608..88d8b19ab8 100644 --- a/pallets/maintenance-mode/src/lib.rs +++ b/pallets/maintenance-mode/src/lib.rs @@ -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(PhantomData); + /// 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 { @@ -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; + /// 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 @@ -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. @@ -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) -> DispatchResultWithPostInfo { // Ensure Origin T::MaintenanceOrigin::ensure_origin(origin)?; @@ -163,6 +181,10 @@ pub mod pallet { // Write to storage MaintenanceMode::::put(true); + // Suspend XCM execution + if let Err(error) = T::XcmExecutionManager::suspend_xcm_execution() { + >::deposit_event(Event::FailedToSuspendIdleXcmExecution { error }); + } // Event >::deposit_event(Event::EnteredMaintenanceMode); @@ -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) -> DispatchResultWithPostInfo { // Ensure Origin T::MaintenanceOrigin::ensure_origin(origin)?; @@ -190,6 +212,10 @@ pub mod pallet { // Write to storage MaintenanceMode::::put(false); + // Resume XCM execution + if let Err(error) = T::XcmExecutionManager::resume_xcm_execution() { + >::deposit_event(Event::FailedToResumeIdleXcmExecution { error }); + } // Event >::deposit_event(Event::NormalOperationResumed); @@ -237,18 +263,4 @@ pub mod pallet { } } } - - #[cfg(feature = "xcm-support")] - impl XcmpMessageHandler for Pallet { - fn handle_xcmp_messages<'a, I: Iterator>( - iter: I, - limit: Weight, - ) -> Weight { - if MaintenanceMode::::get() { - T::MaintenanceXcmpHandler::handle_xcmp_messages(iter, limit) - } else { - T::NormalXcmpHandler::handle_xcmp_messages(iter, limit) - } - } - } } diff --git a/pallets/maintenance-mode/src/mock.rs b/pallets/maintenance-mode/src/mock.rs index f0b2e58874..b509c8ed6e 100644 --- a/pallets/maintenance-mode/src/mock.rs +++ b/pallets/maintenance-mode/src/mock.rs @@ -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::{ @@ -98,32 +96,6 @@ impl Contains 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>( - _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>( - _iter: I, - _limit: Weight, - ) -> Weight { - return 0; - } -} - pub struct MaintenanceDmpHandler; #[cfg(feature = "xcm-support")] impl DmpMessageHandler for MaintenanceDmpHandler { @@ -284,13 +256,11 @@ impl Config for Test { type MaintenanceCallFilter = MaintenanceCallFilter; type MaintenanceOrigin = EnsureRoot; #[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; } diff --git a/pallets/maintenance-mode/src/tests.rs b/pallets/maintenance-mode/src/tests.rs index a1f926b320..557ad50327 100644 --- a/pallets/maintenance-mode/src/tests.rs +++ b/pallets/maintenance-mode/src/tests.rs @@ -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, @@ -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() @@ -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() @@ -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 - ); }) } diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index 4316f8c2bb..ea22a648e6 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -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; } @@ -1051,9 +1051,18 @@ impl Contains 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 @@ -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>( - iter: I, - _limit: Weight, - ) -> Weight { - XcmpQueue::handle_xcmp_messages(iter, 0) - } -} - /// The hooks we wnat to run in Maintenance Mode pub struct MaintenanceHooks; @@ -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; diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs index 2438d81a07..03cc6b8c1d 100644 --- a/runtime/moonbase/tests/integration_test.rs +++ b/runtime/moonbase/tests/integration_test.rs @@ -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, }; @@ -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!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + #[test] fn fast_track_available() { assert!(get!(pallet_democracy, InstantAllowed, bool)); diff --git a/runtime/moonbeam/src/lib.rs b/runtime/moonbeam/src/lib.rs index 86814a06b1..b758778c00 100644 --- a/runtime/moonbeam/src/lib.rs +++ b/runtime/moonbeam/src/lib.rs @@ -83,9 +83,7 @@ use pallet_evm_precompile_assets_erc20::AccountIdAssetIdConversion; use xcm::latest::prelude::*; -use cumulus_primitives_core::{ - relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler, -}; +use cumulus_primitives_core::{relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler}; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -626,7 +624,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type DmpMessageHandler = MaintenanceMode; type ReservedDmpWeight = ConstU64<{ MAXIMUM_BLOCK_WEIGHT / 4 }>; type OutboundXcmpMessageSource = XcmpQueue; - type XcmpMessageHandler = MaintenanceMode; + type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ConstU64<{ MAXIMUM_BLOCK_WEIGHT / 4 }>; } impl parachain_info::Config for Runtime {} @@ -996,6 +994,16 @@ impl Contains 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 @@ -1008,18 +1016,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>( - iter: I, - _limit: Weight, - ) -> Weight { - XcmpQueue::handle_xcmp_messages(iter, 0) - } -} - /// The hooks we want to run in Maintenance Mode pub struct MaintenanceHooks; @@ -1074,10 +1070,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; diff --git a/runtime/moonbeam/tests/integration_test.rs b/runtime/moonbeam/tests/integration_test.rs index be590f0f4c..d1b2445868 100644 --- a/runtime/moonbeam/tests/integration_test.rs +++ b/runtime/moonbeam/tests/integration_test.rs @@ -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, }; @@ -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!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + #[test] fn fast_track_available() { assert!(moonbeam_runtime::get!( diff --git a/runtime/moonriver/src/lib.rs b/runtime/moonriver/src/lib.rs index 6dd0e2f7ef..5e2914a1c5 100644 --- a/runtime/moonriver/src/lib.rs +++ b/runtime/moonriver/src/lib.rs @@ -81,9 +81,7 @@ use sp_runtime::{ }; use sp_std::{convert::TryFrom, prelude::*}; -use cumulus_primitives_core::{ - relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId, XcmpMessageHandler, -}; +use cumulus_primitives_core::{relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler}; use smallvec::smallvec; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -653,7 +651,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; } @@ -1031,6 +1029,16 @@ impl Contains 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 @@ -1043,18 +1051,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>( - iter: I, - _limit: Weight, - ) -> Weight { - XcmpQueue::handle_xcmp_messages(iter, 0) - } -} - /// The hooks we wantt to run in Maintenance Mode pub struct MaintenanceHooks; @@ -1109,10 +1105,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; diff --git a/runtime/moonriver/tests/integration_test.rs b/runtime/moonriver/tests/integration_test.rs index 539cb259e2..8dc4086a28 100644 --- a/runtime/moonriver/tests/integration_test.rs +++ b/runtime/moonriver/tests/integration_test.rs @@ -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, }; @@ -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!( + ::ControllerOrigin::ensure_origin(root_origin()) + ); +} + #[test] fn fast_track_available() { assert!(moonriver_runtime::get!(