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

XCM: Implement a blocking barrier #7098

Merged
merged 12 commits into from
Apr 27, 2023
Merged
43 changes: 38 additions & 5 deletions xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ use frame_system::pallet_prelude::*;
pub use pallet::*;
use xcm_executor::{
traits::{
ClaimAssets, DropAssets, MatchesFungible, OnResponse, VersionChangeNotifier, WeightBounds,
CheckSuspension, ClaimAssets, DropAssets, MatchesFungible, OnResponse,
VersionChangeNotifier, WeightBounds,
},
Assets,
};
Expand All @@ -66,6 +67,7 @@ pub trait WeightInfo {
fn force_default_xcm_version() -> Weight;
fn force_subscribe_version_notify() -> Weight;
fn force_unsubscribe_version_notify() -> Weight;
fn force_suspension() -> Weight;
fn migrate_supported_version() -> Weight;
fn migrate_version_notifiers() -> Weight;
fn already_notified_target() -> Weight;
Expand Down Expand Up @@ -110,6 +112,10 @@ impl WeightInfo for TestWeightInfo {
Weight::from_parts(100_000_000, 0)
}

fn force_suspension() -> Weight {
Weight::from_parts(100_000_000, 0)
}

fn migrate_supported_version() -> Weight {
Weight::from_parts(100_000_000, 0)
}
Expand Down Expand Up @@ -612,6 +618,10 @@ pub mod pallet {
OptionQuery,
>;

/// Global suspension state of the XCM executor.
#[pallet::storage]
pub(super) type XcmExecutionSuspended<T: Config> = StorageValue<_, bool, ValueQuery>;

#[pallet::genesis_config]
pub struct GenesisConfig {
/// The default version to encode outgoing XCM messages with.
Expand Down Expand Up @@ -908,7 +918,7 @@ pub mod pallet {
/// Extoll that a particular destination can be communicated with through a particular
/// version of XCM.
///
/// - `origin`: Must be Root.
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `location`: The destination that is being described.
/// - `xcm_version`: The latest version of XCM that `location` supports.
#[pallet::call_index(4)]
Expand All @@ -932,7 +942,7 @@ pub mod pallet {
/// Set a safe XCM version (the version that XCM should be encoded with if the most recent
/// version a destination can accept is unknown).
///
/// - `origin`: Must be Root.
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `maybe_xcm_version`: The default XCM encoding version, or `None` to disable.
#[pallet::call_index(5)]
#[pallet::weight(T::WeightInfo::force_default_xcm_version())]
Expand All @@ -947,7 +957,7 @@ pub mod pallet {

/// Ask a location to notify us regarding their XCM version and any changes to it.
///
/// - `origin`: Must be Root.
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `location`: The location to which we should subscribe for XCM version notifications.
#[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::force_subscribe_version_notify())]
Expand All @@ -970,7 +980,7 @@ pub mod pallet {
/// Require that a particular destination should no longer notify us regarding any XCM
/// version changes.
///
/// - `origin`: Must be Root.
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `location`: The location to which we are currently subscribed for XCM version
/// notifications which we no longer desire.
#[pallet::call_index(7)]
Expand Down Expand Up @@ -1092,6 +1102,18 @@ pub mod pallet {
Some(weight_limit),
)
}

/// Set or unset the global suspension state of the XCM executor.
///
/// - `origin`: Must be an origin specified by AdminOrigin.
/// - `suspended`: `true` to suspend, `false` to resume.
#[pallet::call_index(10)]
#[pallet::weight(T::WeightInfo::force_suspension())]
pub fn force_suspension(origin: OriginFor<T>, suspended: bool) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
XcmExecutionSuspended::<T>::set(suspended);
Ok(())
}
}
}

Expand Down Expand Up @@ -2040,6 +2062,17 @@ impl<T: Config> OnResponse for Pallet<T> {
}
}

impl<T: Config> CheckSuspension for Pallet<T> {
fn is_suspended<Call>(
_origin: &MultiLocation,
_instructions: &mut [Instruction<Call>],
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> bool {
XcmExecutionSuspended::<T>::get()
}
}

/// Ensure that the origin `o` represents an XCM (`Transact`) origin.
///
/// Returns `Ok` with the location of the XCM sender or an `Err` otherwise.
Expand Down
84 changes: 0 additions & 84 deletions xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#![no_std]
extern crate alloc;

use core::ops::ControlFlow;
use derivative::Derivative;
use parity_scale_codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen};
use scale_info::TypeInfo;
Expand Down Expand Up @@ -51,89 +50,6 @@ pub const MAX_XCM_DECODE_DEPTH: u32 = 8;
/// A version of XCM.
pub type Version = u32;

/// Creates an instruction matcher from an XCM. Since XCM versions differ, we need to make a trait
/// here to unify the interfaces among them.
pub trait CreateMatcher {
/// The concrete matcher type.
type Matcher;

/// Method that creates and returns the matcher type from `Self`.
fn matcher(self) -> Self::Matcher;
}

/// API that allows to pattern-match against anything that is contained within an XCM.
///
/// The intended usage of the matcher API is to enable the ability to chain successive methods of
/// this trait together, along with the ? operator for the purpose of facilitating the writing,
/// maintenance and auditability of XCM barriers.
///
/// Example:
/// ```rust
/// use xcm::{
/// v3::{Instruction, Matcher},
/// CreateMatcher, MatchXcm,
/// };
///
/// let mut msg = [Instruction::<()>::ClearOrigin];
/// let res = msg
/// .matcher()
/// .assert_remaining_insts(1)?
/// .match_next_inst(|inst| match inst {
/// Instruction::<()>::ClearOrigin => Ok(()),
/// _ => Err(()),
/// });
/// assert!(res.is_ok());
///
/// Ok::<(), ()>(())
/// ```
pub trait MatchXcm {
/// The concrete instruction type. Necessary to specify as it changes between XCM versions.
type Inst;
/// The `MultiLocation` type. Necessary to specify as it changes between XCM versions.
type Loc;
/// The error type to throw when errors happen during matching.
type Error;

/// Returns success if the number of instructions that still have not been iterated over
/// equals `n`, otherwise returns an error.
fn assert_remaining_insts(self, n: usize) -> Result<Self, Self::Error>
where
Self: Sized;

/// Accepts a closure `f` that contains an argument signifying the next instruction to be
/// iterated over. The closure can then be used to check whether the instruction matches a
/// given condition, and can also be used to mutate the fields of an instruction.
///
/// The closure `f` returns success when the instruction passes the condition, otherwise it
/// returns an error, which will ultimately be returned by this function.
fn match_next_inst<F>(self, f: F) -> Result<Self, Self::Error>
where
Self: Sized,
F: FnMut(&mut Self::Inst) -> Result<(), Self::Error>;

/// Attempts to continuously iterate through the instructions while applying `f` to each of
/// them, until either the last instruction or `cond` returns false.
///
/// If `f` returns an error, then iteration halts and the function returns that error.
/// Otherwise, `f` returns a `ControlFlow` which signifies whether the iteration breaks or
/// continues.
fn match_next_inst_while<C, F>(self, cond: C, f: F) -> Result<Self, Self::Error>
where
Self: Sized,
C: Fn(&Self::Inst) -> bool,
F: FnMut(&mut Self::Inst) -> Result<ControlFlow<()>, Self::Error>;

/// Iterate instructions forward until `cond` returns false. When there are no more instructions
/// to be read, an error is returned.
fn skip_inst_while<C>(self, cond: C) -> Result<Self, Self::Error>
where
Self: Sized,
C: Fn(&Self::Inst) -> bool,
{
Self::match_next_inst_while(self, cond, |_| Ok(ControlFlow::Continue(())))
}
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Unsupported {}
impl Encode for Unsupported {}
Expand Down
109 changes: 0 additions & 109 deletions xcm/src/v3/matcher.rs

This file was deleted.

2 changes: 0 additions & 2 deletions xcm/src/v3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ use scale_info::TypeInfo;

mod junction;
pub(crate) mod junctions;
mod matcher;
mod multiasset;
mod multilocation;
mod traits;

pub use junction::{BodyId, BodyPart, Junction, NetworkId};
pub use junctions::Junctions;
pub use matcher::Matcher;
pub use multiasset::{
AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
WildFungibility, WildMultiAsset,
Expand Down
Loading