XCM: Implement a blocking barrier (#7098)

* Move XCM matcher to xcm-builder

* Use ProcessMessageError as the error type in MatchXcm and ShouldExecute

* Implement a blocking barrier

* Fixes

* Add benchmarking for force_suspension

* ".git/.scripts/commands/bench/bench.sh" runtime westend pallet_xcm

* ".git/.scripts/commands/bench/bench.sh" runtime rococo pallet_xcm

* ".git/.scripts/commands/bench/bench.sh" runtime kusama pallet_xcm

* ".git/.scripts/commands/bench/bench.sh" runtime polkadot pallet_xcm

* ".git/.scripts/commands/bench/bench.sh" runtime westend pallet_xcm

* ".git/.scripts/commands/bench/bench.sh" runtime rococo pallet_xcm

---------

Co-authored-by: command-bot <>
This commit is contained in:
Keith Yeung
2023-04-27 18:22:39 +08:00
committed by GitHub
parent 1125655024
commit d20e3c1145
18 changed files with 644 additions and 444 deletions
+53 -29
View File
@@ -16,23 +16,21 @@
//! Various implementations for `ShouldExecute`.
use crate::{CreateMatcher, MatchXcm};
use frame_support::{
ensure,
traits::{Contains, Get},
traits::{Contains, Get, ProcessMessageError},
};
use polkadot_parachain::primitives::IsSystem;
use sp_std::{cell::Cell, marker::PhantomData, ops::ControlFlow, result::Result};
use xcm::{
latest::{
Instruction::{self, *},
InteriorMultiLocation, Junction, Junctions,
Junctions::X1,
MultiLocation, Weight,
WeightLimit::*,
},
CreateMatcher, MatchXcm,
use xcm::latest::{
Instruction::{self, *},
InteriorMultiLocation, Junction, Junctions,
Junctions::X1,
MultiLocation, Weight,
WeightLimit::*,
};
use xcm_executor::traits::{OnResponse, ShouldExecute};
use xcm_executor::traits::{CheckSuspension, OnResponse, ShouldExecute};
/// Execution barrier that just takes `max_weight` from `weight_credit`.
///
@@ -46,13 +44,15 @@ impl ShouldExecute for TakeWeightCredit {
_instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"TakeWeightCredit origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
_origin, _instructions, max_weight, weight_credit,
);
*weight_credit = weight_credit.checked_sub(&max_weight).ok_or(())?;
*weight_credit = weight_credit
.checked_sub(&max_weight)
.ok_or(ProcessMessageError::Overweight(max_weight))?;
Ok(())
}
}
@@ -69,14 +69,14 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"AllowTopLevelPaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
origin, instructions, max_weight, _weight_credit,
);
ensure!(T::contains(origin), ());
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
// We will read up to 5 instructions. This allows up to 3 `ClearOrigin` instructions. We
// allow for more than one since anything beyond the first is a no-op and it's conceivable
// that composition of operations might result in more than one being appended.
@@ -88,7 +88,7 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
WithdrawAsset(..) |
ReserveAssetDeposited(..) |
ClaimAsset { .. } => Ok(()),
_ => Err(()),
_ => Err(ProcessMessageError::BadFormat),
})?
.skip_inst_while(|inst| matches!(inst, ClearOrigin))?
.match_next_inst(|inst| match inst {
@@ -102,7 +102,7 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
*weight_limit = Limited(max_weight);
Ok(())
},
_ => Err(()),
_ => Err(ProcessMessageError::Overweight(max_weight)),
})?;
Ok(())
}
@@ -167,7 +167,7 @@ impl<
instructions: &mut [Instruction<Call>],
max_weight: Weight,
weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"WithComputedOrigin origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
@@ -191,7 +191,9 @@ impl<
actual_origin = X1(*new_global).relative_to(&LocalUniversal::get());
},
DescendOrigin(j) => {
let Ok(_) = actual_origin.append_with(*j) else { return Err(()) };
let Ok(_) = actual_origin.append_with(*j) else {
return Err(ProcessMessageError::Unsupported)
};
},
_ => return Ok(ControlFlow::Break(())),
};
@@ -208,6 +210,28 @@ impl<
}
}
/// Barrier condition that allows for a `SuspensionChecker` that controls whether or not the XCM
/// executor will be suspended from executing the given XCM.
pub struct RespectSuspension<Inner, SuspensionChecker>(PhantomData<(Inner, SuspensionChecker)>);
impl<Inner, SuspensionChecker> ShouldExecute for RespectSuspension<Inner, SuspensionChecker>
where
Inner: ShouldExecute,
SuspensionChecker: CheckSuspension,
{
fn should_execute<Call>(
origin: &MultiLocation,
instructions: &mut [Instruction<Call>],
max_weight: Weight,
weight_credit: &mut Weight,
) -> Result<(), ProcessMessageError> {
if SuspensionChecker::is_suspended(origin, instructions, max_weight, weight_credit) {
Err(ProcessMessageError::Yield)
} else {
Inner::should_execute(origin, instructions, max_weight, weight_credit)
}
}
}
/// Allows execution from any origin that is contained in `T` (i.e. `T::Contains(origin)`).
///
/// Use only for executions from completely trusted origins, from which no unpermissioned messages
@@ -219,13 +243,13 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"AllowUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
origin, instructions, _max_weight, _weight_credit,
);
ensure!(T::contains(origin), ());
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
Ok(())
}
}
@@ -241,17 +265,17 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowExplicitUnpaidExecutionF
instructions: &mut [Instruction<Call>],
max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"AllowExplicitUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
origin, instructions, max_weight, _weight_credit,
);
ensure!(T::contains(origin), ());
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
instructions.matcher().match_next_inst(|inst| match inst {
UnpaidExecution { weight_limit: Limited(m), .. } if m.all_gte(max_weight) => Ok(()),
UnpaidExecution { weight_limit: Unlimited, .. } => Ok(()),
_ => Err(()),
_ => Err(ProcessMessageError::Overweight(max_weight)),
})?;
Ok(())
}
@@ -277,7 +301,7 @@ impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<Res
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"AllowKnownQueryResponses origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
@@ -290,7 +314,7 @@ impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<Res
QueryResponse { query_id, querier, .. }
if ResponseHandler::expecting_response(origin, *query_id, querier.as_ref()) =>
Ok(()),
_ => Err(()),
_ => Err(ProcessMessageError::BadFormat),
})?;
Ok(())
}
@@ -305,19 +329,19 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowSubscriptionsFrom<T> {
instructions: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
) -> Result<(), ProcessMessageError> {
log::trace!(
target: "xcm::barriers",
"AllowSubscriptionsFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
origin, instructions, _max_weight, _weight_credit,
);
ensure!(T::contains(origin), ());
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
instructions
.matcher()
.assert_remaining_insts(1)?
.match_next_inst(|inst| match inst {
SubscribeVersion { .. } | UnsubscribeVersion => Ok(()),
_ => Err(()),
_ => Err(ProcessMessageError::BadFormat),
})?;
Ok(())
}
+4 -1
View File
@@ -51,7 +51,7 @@ mod barriers;
pub use barriers::{
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, IsChildSystemParachain,
TakeWeightCredit, WithComputedOrigin,
RespectSuspension, TakeWeightCredit, WithComputedOrigin,
};
mod currency_adapter;
@@ -76,6 +76,9 @@ pub use weight::{
mod matches_token;
pub use matches_token::{IsAbstract, IsConcrete};
mod matcher;
pub use matcher::{CreateMatcher, MatchXcm, Matcher};
mod filter_asset_location;
pub use filter_asset_location::{Case, NativeAsset};
+191
View File
@@ -0,0 +1,191 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! XCM matcher API, used primarily for writing barrier conditions.
use core::ops::ControlFlow;
use frame_support::traits::ProcessMessageError;
use xcm::latest::{Instruction, MultiLocation};
/// 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;
}
impl<'a, Call> CreateMatcher for &'a mut [Instruction<Call>] {
type Matcher = Matcher<'a, Call>;
fn matcher(self) -> Self::Matcher {
let total_inst = self.len();
Matcher { xcm: self, current_idx: 0, total_inst }
}
}
/// 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 frame_support::traits::ProcessMessageError;
/// use xcm::latest::Instruction;
/// use xcm_builder::{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(ProcessMessageError::BadFormat),
/// });
/// assert!(res.is_ok());
///
/// Ok::<(), ProcessMessageError>(())
/// ```
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(())))
}
}
/// Struct created from calling `fn matcher()` on a mutable slice of `Instruction`s.
///
/// Implements `MatchXcm` to allow an iterator-like API to match against each `Instruction`
/// contained within the slice, which facilitates the building of XCM barriers.
pub struct Matcher<'a, Call> {
pub(crate) xcm: &'a mut [Instruction<Call>],
pub(crate) current_idx: usize,
pub(crate) total_inst: usize,
}
impl<'a, Call> MatchXcm for Matcher<'a, Call> {
type Error = ProcessMessageError;
type Inst = Instruction<Call>;
type Loc = MultiLocation;
fn assert_remaining_insts(self, n: usize) -> Result<Self, Self::Error>
where
Self: Sized,
{
if self.total_inst - self.current_idx != n {
return Err(ProcessMessageError::BadFormat)
}
Ok(self)
}
fn match_next_inst<F>(mut self, mut f: F) -> Result<Self, Self::Error>
where
Self: Sized,
F: FnMut(&mut Self::Inst) -> Result<(), Self::Error>,
{
if self.current_idx < self.total_inst {
f(&mut self.xcm[self.current_idx])?;
self.current_idx += 1;
Ok(self)
} else {
Err(ProcessMessageError::BadFormat)
}
}
fn match_next_inst_while<C, F>(mut self, cond: C, mut f: F) -> Result<Self, Self::Error>
where
Self: Sized,
C: Fn(&Self::Inst) -> bool,
F: FnMut(&mut Self::Inst) -> Result<ControlFlow<()>, Self::Error>,
{
if self.current_idx >= self.total_inst {
return Err(ProcessMessageError::BadFormat)
}
while self.current_idx < self.total_inst && cond(&self.xcm[self.current_idx]) {
if let ControlFlow::Break(()) = f(&mut self.xcm[self.current_idx])? {
break
}
self.current_idx += 1;
}
Ok(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{vec, vec::Vec};
use xcm::latest::prelude::*;
#[test]
fn match_next_inst_while_works() {
let mut xcm: Vec<Instruction<()>> = vec![ClearOrigin];
let _ = xcm
.matcher()
.match_next_inst_while(|_| true, |_| Ok(ControlFlow::Continue(())))
.unwrap();
}
}
+39 -12
View File
@@ -36,7 +36,7 @@ fn take_weight_credit_barrier_should_work() {
Weight::from_parts(10, 10),
&mut weight_credit,
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(10, 10))));
assert_eq!(weight_credit, Weight::zero());
}
@@ -69,7 +69,7 @@ fn computed_origin_should_work() {
Weight::from_parts(100, 100),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = WithComputedOrigin::<
AllowTopLevelPaidExecutionFrom<IsInVec<AllowPaidFrom>>,
@@ -81,7 +81,7 @@ fn computed_origin_should_work() {
Weight::from_parts(100, 100),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = WithComputedOrigin::<
AllowTopLevelPaidExecutionFrom<IsInVec<AllowPaidFrom>>,
@@ -109,7 +109,7 @@ fn allow_unpaid_should_work() {
Weight::from_parts(10, 10),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
&Parent.into(),
@@ -149,7 +149,7 @@ fn allow_explicit_unpaid_should_work() {
Weight::from_parts(20, 20),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = AllowExplicitUnpaidExecutionFrom::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
@@ -157,7 +157,7 @@ fn allow_explicit_unpaid_should_work() {
Weight::from_parts(20, 20),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = AllowExplicitUnpaidExecutionFrom::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
@@ -165,7 +165,7 @@ fn allow_explicit_unpaid_should_work() {
Weight::from_parts(20, 20),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = AllowExplicitUnpaidExecutionFrom::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
@@ -189,7 +189,7 @@ fn allow_explicit_unpaid_should_work() {
Weight::from_parts(20, 20),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = AllowExplicitUnpaidExecutionFrom::<IsInVec<AllowExplicitUnpaidFrom>>::should_execute(
&Parent.into(),
@@ -213,7 +213,7 @@ fn allow_paid_should_work() {
Weight::from_parts(10, 10),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let fees = (Parent, 1).into();
let mut underpaying_message = Xcm::<()>(vec![
@@ -228,7 +228,7 @@ fn allow_paid_should_work() {
Weight::from_parts(30, 30),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30))));
let fees = (Parent, 1).into();
let mut paying_message = Xcm::<()>(vec![
@@ -243,7 +243,7 @@ fn allow_paid_should_work() {
Weight::from_parts(30, 30),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Unsupported));
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
@@ -266,7 +266,7 @@ fn allow_paid_should_work() {
Weight::from_parts(20, 20),
&mut Weight::zero(),
);
assert_eq!(r, Err(()));
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&Parent.into(),
@@ -276,3 +276,30 @@ fn allow_paid_should_work() {
);
assert_eq!(r, Ok(()))
}
#[test]
fn suspension_should_work() {
TestSuspender::set_suspended(true);
AllowUnpaidFrom::set(vec![Parent.into()]);
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let r = RespectSuspension::<AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>, TestSuspender>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut Weight::zero(),
);
assert_eq!(r, Err(ProcessMessageError::Yield));
TestSuspender::set_suspended(false);
let mut message =
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
let r = RespectSuspension::<AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>, TestSuspender>::should_execute(
&Parent.into(),
message.inner_mut(),
Weight::from_parts(10, 10),
&mut Weight::zero(),
);
assert_eq!(r, Ok(()));
}
+27 -5
View File
@@ -14,7 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use crate::{barriers::AllowSubscriptionsFrom, test_utils::*};
use crate::{
barriers::{AllowSubscriptionsFrom, RespectSuspension},
test_utils::*,
};
pub use crate::{
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom,
AllowUnpaidExecutionFrom, FixedRateOfFungible, FixedWeightBounds, TakeWeightCredit,
@@ -32,7 +35,7 @@ pub use frame_support::{
pub use parity_scale_codec::{Decode, Encode};
pub use sp_io::hashing::blake2_256;
pub use sp_std::{
cell::RefCell,
cell::{Cell, RefCell},
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
fmt::Debug,
marker::PhantomData,
@@ -40,8 +43,8 @@ pub use sp_std::{
pub use xcm::latest::{prelude::*, Weight};
pub use xcm_executor::{
traits::{
AssetExchange, AssetLock, ConvertOrigin, Enact, ExportXcm, FeeManager, FeeReason,
LockError, OnResponse, TransactAsset,
AssetExchange, AssetLock, CheckSuspension, ConvertOrigin, Enact, ExportXcm, FeeManager,
FeeReason, LockError, OnResponse, TransactAsset,
},
Assets, Config,
};
@@ -128,6 +131,7 @@ thread_local! {
) -> Result<XcmHash, SendError>,
)>> = RefCell::new(None);
pub static SEND_PRICE: RefCell<MultiAssets> = RefCell::new(MultiAssets::new());
pub static SUSPENDED: Cell<bool> = Cell::new(false);
}
pub fn sent_xcm() -> Vec<(MultiLocation, opaque::Xcm, XcmHash)> {
SENT_XCM.with(|q| (*q.borrow()).clone())
@@ -419,6 +423,24 @@ parameter_types! {
pub static MaxInstructions: u32 = 100;
}
pub struct TestSuspender;
impl CheckSuspension for TestSuspender {
fn is_suspended<Call>(
_origin: &MultiLocation,
_instructions: &mut [Instruction<Call>],
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> bool {
SUSPENDED.with(|s| s.get())
}
}
impl TestSuspender {
pub fn set_suspended(suspended: bool) {
SUSPENDED.with(|s| s.set(suspended));
}
}
pub type TestBarrier = (
TakeWeightCredit,
AllowKnownQueryResponses<TestResponseHandler>,
@@ -629,7 +651,7 @@ impl Config for TestConfig {
type IsReserve = TestIsReserve;
type IsTeleporter = TestIsTeleporter;
type UniversalLocation = ExecutorUniversalLocation;
type Barrier = TestBarrier;
type Barrier = RespectSuspension<TestBarrier, TestSuspender>;
type Weigher = FixedWeightBounds<UnitWeightCost, TestCall, MaxInstructions>;
type Trader = FixedRateOfFungible<WeightPrice, ()>;
type ResponseHandler = TestResponseHandler;
+1 -1
View File
@@ -18,7 +18,7 @@ use super::{test_utils::*, *};
use core::convert::TryInto;
use frame_support::{
assert_err,
traits::{ConstU32, ContainsPair},
traits::{ConstU32, ContainsPair, ProcessMessageError},
weights::constants::{WEIGHT_PROOF_SIZE_PER_MB, WEIGHT_REF_TIME_PER_SECOND},
};
use xcm_executor::{traits::prelude::*, Config, XcmExecutor};