Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Add the ability to suspend or resume XCM execution on the XCMP queue (#…
Browse files Browse the repository at this point in the history
…896)

* Add the ability to suspend or resume XCM execution on the XCMP queue

* Rename QueueActive to QueueSuspended

* Add the ability to suspend the DMP queue

* Rename XCMP to DMP in comments where appropriate

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Add a bypass for XCMP queue suspension

* Revert "Add the ability to suspend the DMP queue"

This reverts commit 363ca09.

* Change controller origin to either root or council-issued origin

* Rename to ControllerOriginConverter

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
  • Loading branch information
KiChjang and apopiak authored Jan 31, 2022
1 parent 88928d0 commit 7749187
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 4 deletions.
56 changes: 55 additions & 1 deletion pallets/xcmp-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError,
ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource,
};
use frame_support::weights::{constants::WEIGHT_PER_MILLIS, Weight};
use frame_support::{
traits::EnsureOrigin,
weights::{constants::WEIGHT_PER_MILLIS, Weight},
};
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaChaRng,
Expand All @@ -47,6 +50,7 @@ use scale_info::TypeInfo;
use sp_runtime::{traits::Hash, RuntimeDebug};
use sp_std::{convert::TryFrom, prelude::*};
use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH};
use xcm_executor::traits::ConvertOrigin;

pub use pallet::*;

Expand Down Expand Up @@ -82,6 +86,13 @@ pub mod pallet {

/// The origin that is allowed to execute overweight messages.
type ExecuteOverweightOrigin: EnsureOrigin<Self::Origin>;

/// The origin that is allowed to resume or suspend the XCMP queue.
type ControllerOrigin: EnsureOrigin<Self::Origin>;

/// The conversion function used to attempt to convert an XCM `MultiLocation` origin to a
/// superuser origin.
type ControllerOriginConverter: ConvertOrigin<Self::Origin>;
}

#[pallet::hooks]
Expand Down Expand Up @@ -130,6 +141,32 @@ pub mod pallet {
Self::deposit_event(Event::OverweightServiced(index, used));
Ok(Some(used.saturating_add(1_000_000)).into())
}

/// Suspends all XCM executions for the XCMP queue, regardless of the sender's origin.
///
/// - `origin`: Must pass `ControllerOrigin`.
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn suspend_xcm_execution(origin: OriginFor<T>) -> DispatchResult {
T::ControllerOrigin::ensure_origin(origin)?;

QueueSuspended::<T>::put(true);

Ok(())
}

/// Resumes all XCM executions for the XCMP queue.
///
/// Note that this function doesn't change the status of the in/out bound channels.
///
/// - `origin`: Must pass `ControllerOrigin`.
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn resume_xcm_execution(origin: OriginFor<T>) -> DispatchResult {
T::ControllerOrigin::ensure_origin(origin)?;

QueueSuspended::<T>::put(false);

Ok(())
}
}

#[pallet::event]
Expand Down Expand Up @@ -221,6 +258,10 @@ pub mod pallet {
/// available free overweight index.
#[pallet::storage]
pub(super) type OverweightCount<T: Config> = StorageValue<_, OverweightIndex, ValueQuery>;

/// Whether or not the XCMP queue is suspended from executing incoming XCMs or not.
#[pallet::storage]
pub(super) type QueueSuspended<T: Config> = StorageValue<_, bool, ValueQuery>;
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, TypeInfo)]
Expand Down Expand Up @@ -618,6 +659,8 @@ impl<T: Config> Pallet<T> {
/// for the second &c. though empirical and or practical factors may give rise to adjusting it
/// further.
fn service_xcmp_queue(max_weight: Weight) -> Weight {
let suspended = QueueSuspended::<T>::get();

let mut status = <InboundXcmpStatus<T>>::get(); // <- sorted.
if status.len() == 0 {
return 0
Expand Down Expand Up @@ -649,6 +692,17 @@ impl<T: Config> Pallet<T> {
{
let index = shuffled[shuffle_index];
let sender = status[index].sender;
let sender_origin = T::ControllerOriginConverter::convert_origin(
(1, Parachain(sender.into())),
OriginKind::Superuser,
);
let is_controller = sender_origin
.map_or(false, |origin| T::ControllerOrigin::try_origin(origin).is_ok());

if suspended && !is_controller {
shuffle_index += 1;
continue
}

if weight_available != max_weight {
// Get incrementally closer to freeing up max_weight for message execution over the
Expand Down
30 changes: 29 additions & 1 deletion pallets/xcmp-queue/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@

use super::*;
use crate as xcmp_queue;
use frame_support::parameter_types;
use core::marker::PhantomData;
use cumulus_primitives_core::{IsSystem, ParaId};
use frame_support::{parameter_types, traits::OriginTrait};
use frame_system::EnsureRoot;
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
};
use xcm::prelude::*;
use xcm_builder::{
CurrencyAdapter, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsPreset,
};
use xcm_executor::traits::ConvertOrigin;

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
Expand Down Expand Up @@ -154,12 +158,36 @@ pub type XcmRouter = (
XcmpQueue,
);

pub struct SystemParachainAsSuperuser<Origin>(PhantomData<Origin>);
impl<Origin: OriginTrait> ConvertOrigin<Origin> for SystemParachainAsSuperuser<Origin> {
fn convert_origin(
origin: impl Into<MultiLocation>,
kind: OriginKind,
) -> Result<Origin, MultiLocation> {
let origin = origin.into();
if kind == OriginKind::Superuser &&
matches!(
origin,
MultiLocation {
parents: 1,
interior: X1(Parachain(id)),
} if ParaId::from(id).is_system(),
) {
Ok(Origin::root())
} else {
Err(origin)
}
}
}

impl Config for Test {
type Event = Event;
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
type ChannelInfo = ParachainSystem;
type VersionWrapper = ();
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = SystemParachainAsSuperuser<Origin>;
}

pub fn new_test_ext() -> sp_io::TestExternalities {
Expand Down
28 changes: 27 additions & 1 deletion pallets/xcmp-queue/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use super::*;
use cumulus_primitives_core::XcmpMessageHandler;
use frame_support::assert_noop;
use mock::{new_test_ext, Origin, Test, XcmpQueue};
use mock::{new_test_ext, Call, Origin, Test, XcmpQueue};

#[test]
fn one_message_does_not_panic() {
Expand Down Expand Up @@ -83,3 +83,29 @@ fn service_overweight_bad_xcm_format() {
assert_noop!(XcmpQueue::service_overweight(Origin::root(), 0, 1000), Error::<Test>::BadXcm);
});
}

#[test]
fn suspend_xcm_execution_works() {
new_test_ext().execute_with(|| {
QueueSuspended::<Test>::put(true);

let xcm = VersionedXcm::from(Xcm::<Call>(vec![Instruction::<Call>::ClearOrigin])).encode();
let mut message_format = XcmpMessageFormat::ConcatenatedVersionedXcm.encode();
message_format.extend(xcm.clone());
let messages = vec![(ParaId::from(999), 1u32.into(), message_format.as_slice())];

// This should have executed the incoming XCM, because it came from a system parachain
XcmpQueue::handle_xcmp_messages(messages.into_iter(), Weight::max_value());

let queued_xcm = InboundXcmpMessages::<Test>::get(ParaId::from(999), 1u32);
assert!(queued_xcm.is_empty());

let messages = vec![(ParaId::from(2000), 1u32.into(), message_format.as_slice())];

// This shouldn't have executed the incoming XCM
XcmpQueue::handle_xcmp_messages(messages.into_iter(), Weight::max_value());

let queued_xcm = InboundXcmpMessages::<Test>::get(ParaId::from(2000), 1u32);
assert_eq!(queued_xcm, xcm);
});
}
2 changes: 2 additions & 0 deletions parachain-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ChannelInfo = ParachainSystem;
type VersionWrapper = ();
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
2 changes: 2 additions & 0 deletions polkadot-parachains/rococo-parachain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ChannelInfo = ParachainSystem;
type VersionWrapper = ();
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
3 changes: 3 additions & 0 deletions polkadot-parachains/statemine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ChannelInfo = ParachainSystem;
type VersionWrapper = PolkadotXcm;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type ControllerOrigin =
EnsureOneOf<EnsureRoot<AccountId>, EnsureXcm<IsMajorityOfBody<KsmLocation, ExecutiveBody>>>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
3 changes: 3 additions & 0 deletions polkadot-parachains/statemint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,9 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ChannelInfo = ParachainSystem;
type VersionWrapper = PolkadotXcm;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type ControllerOrigin =
EnsureOneOf<EnsureRoot<AccountId>, EnsureXcm<IsMajorityOfBody<DotLocation, ExecutiveBody>>>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
2 changes: 2 additions & 0 deletions polkadot-parachains/westmint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
type ChannelInfo = ParachainSystem;
type VersionWrapper = PolkadotXcm;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
}

impl cumulus_pallet_dmp_queue::Config for Runtime {
Expand Down
2 changes: 1 addition & 1 deletion primitives/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use sp_std::prelude::*;

pub use polkadot_core_primitives::InboundDownwardMessage;
pub use polkadot_parachain::primitives::{
DmpMessageHandler, Id as ParaId, UpwardMessage, ValidationParams, XcmpMessageFormat,
DmpMessageHandler, Id as ParaId, IsSystem, UpwardMessage, ValidationParams, XcmpMessageFormat,
XcmpMessageHandler,
};
pub use polkadot_primitives::v1::{
Expand Down

0 comments on commit 7749187

Please sign in to comment.