XCM v2: Scripting, Query responses, Exception handling and Error reporting (#3629)

* Intoduce XCM v2

Also some minor fix for v0/v1

* Minor version cleanup

* Minor version cleanup

* Introduce SendError for XcmSend trait to avoid cycles with having Outcome in Xcm

* comment

* Corrent type

* Docs

* Fix build

* Fixes

* Introduce the basic impl

* Docs

* Add function

* Basic implementation

* Weighed responses and on_report

* Make XCM more script-like

* Remove BuyExecution::orders

* Fixes

* Fixes

* Fixes

* Formatting

* Initial draft and make pallet-xcm build

* fix XCM tests

* Formatting

* Fixes

* Formatting

* spelling

* Fixes

* Fixes

* spelling

* tests for translation

* extra fields to XCM pallet

* Formatting

* Fixes

* spelling

* first integration test

* Another integration test

* Formatting

* fix tests

* all tests

* Fixes

* Fixes

* Formatting

* Fixes

* Fixes

* Formatting

* Bump

* Remove unneeded structuring

* add instruction

* Fixes

* spelling

* Fixes

* Fixes

* Formatting

* Fixes

* Fixes

* Formatting

* Introduce and use VersionedResponse

* Introduce versioning to dispatchables' params

* Fixes

* Formatting

* Rest of merge

* more work

* Formatting

* Basic logic

* Fixes

* Fixes

* Add test

* Fixes

* Formatting

* Fixes

* Fixes

* Fixes

* Nits

* Simplify

* Spelling

* Formatting

* Return weight of unexecuted instructions in case of error as surplus

* Formatting

* Fixes

* Test for instruction count limiting

* Formatting

* Docs
This commit is contained in:
Gavin Wood
2021-08-26 12:41:16 +02:00
committed by GitHub
parent 4193f05fa3
commit 8b80b283d4
37 changed files with 3070 additions and 966 deletions
+43 -30
View File
@@ -19,10 +19,10 @@
use frame_support::{ensure, traits::Contains, weights::Weight};
use polkadot_parachain::primitives::IsSystem;
use sp_std::{marker::PhantomData, result::Result};
use xcm::latest::{Junction, Junctions, MultiLocation, Order, Xcm};
use xcm::latest::{Instruction::*, Junction, Junctions, MultiLocation, WeightLimit::*, Xcm};
use xcm_executor::traits::{OnResponse, ShouldExecute};
/// Execution barrier that just takes `shallow_weight` from `weight_credit`.
/// Execution barrier that just takes `max_weight` from `weight_credit`.
///
/// Useful to allow XCM execution by local chain users via extrinsics.
/// E.g. `pallet_xcm::reserve_asset_transfer` to transfer a reserve asset
@@ -30,42 +30,53 @@ use xcm_executor::traits::{OnResponse, ShouldExecute};
pub struct TakeWeightCredit;
impl ShouldExecute for TakeWeightCredit {
fn should_execute<Call>(
_origin: &MultiLocation,
_origin: &Option<MultiLocation>,
_top_level: bool,
_message: &Xcm<Call>,
shallow_weight: Weight,
_message: &mut Xcm<Call>,
max_weight: Weight,
weight_credit: &mut Weight,
) -> Result<(), ()> {
*weight_credit = weight_credit.checked_sub(shallow_weight).ok_or(())?;
*weight_credit = weight_credit.checked_sub(max_weight).ok_or(())?;
Ok(())
}
}
/// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking payments into
/// account.
/// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking
/// payments into account.
///
/// Only allows for `TeleportAsset`, `WithdrawAsset` and `ReserveAssetDeposit` XCMs because they are the only ones
/// that place assets in the Holding Register to pay for execution.
/// Only allows for `TeleportAsset`, `WithdrawAsset` and `ReserveAssetDeposit` XCMs because they are
/// the only ones that place assets in the Holding Register to pay for execution.
pub struct AllowTopLevelPaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T> {
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Option<MultiLocation>,
top_level: bool,
message: &Xcm<Call>,
shallow_weight: Weight,
message: &mut Xcm<Call>,
max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
let origin = origin.as_ref().ok_or(())?;
ensure!(T::contains(origin), ());
ensure!(top_level, ());
match message {
Xcm::ReceiveTeleportedAsset { effects, .. } |
Xcm::WithdrawAsset { effects, .. } |
Xcm::ReserveAssetDeposited { effects, .. }
if matches!(
effects.first(),
Some(Order::BuyExecution { debt, ..}) if *debt >= shallow_weight
) =>
Ok(()),
let mut iter = message.0.iter_mut();
let i = iter.next().ok_or(())?;
match i {
ReceiveTeleportedAsset(..) | WithdrawAsset(..) | ReserveAssetDeposited(..) => (),
_ => return Err(()),
}
let mut i = iter.next().ok_or(())?;
while let ClearOrigin = i {
i = iter.next().ok_or(())?;
}
match i {
BuyExecution { weight_limit: Limited(ref mut weight), .. } if *weight >= max_weight => {
*weight = max_weight;
Ok(())
},
BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => {
*weight_limit = Limited(max_weight);
Ok(())
},
_ => Err(()),
}
}
@@ -76,12 +87,13 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
pub struct AllowUnpaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Option<MultiLocation>,
_top_level: bool,
_message: &Xcm<Call>,
_shallow_weight: Weight,
_message: &mut Xcm<Call>,
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
let origin = origin.as_ref().ok_or(())?;
ensure!(T::contains(origin), ());
Ok(())
}
@@ -103,14 +115,15 @@ impl<ParaId: IsSystem + From<u32>> Contains<MultiLocation> for IsChildSystemPara
pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler>);
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
fn should_execute<Call>(
origin: &MultiLocation,
origin: &Option<MultiLocation>,
_top_level: bool,
message: &Xcm<Call>,
_shallow_weight: Weight,
message: &mut Xcm<Call>,
_max_weight: Weight,
_weight_credit: &mut Weight,
) -> Result<(), ()> {
match message {
Xcm::QueryResponse { query_id, .. }
let origin = origin.as_ref().ok_or(())?;
match message.0.first() {
Some(QueryResponse { query_id, .. })
if ResponseHandler::expecting_response(origin, *query_id) =>
Ok(()),
_ => Err(()),