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

XCM: ExpectTransactStatus instruction #6578

Merged
merged 7 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions runtime/kusama/src/weights/xcm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for KusamaXcmWeight<RuntimeCall> {
fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
XcmGeneric::<Runtime>::expect_error()
}
fn expect_transact_status(_transact_status: &MaybeErrorCode) -> Weight {
XcmGeneric::<Runtime>::expect_transact_status()
}
fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
XcmGeneric::<Runtime>::query_pallet()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ impl<T: frame_system::Config> WeightInfo<T> {
pub(crate) fn expect_error() -> Weight {
Weight::from_ref_time(3_645_000 as u64)
}
pub(crate) fn expect_transact_status() -> Weight {
Weight::from_ref_time(3_645_000 as u64)
}
// Storage: XcmPallet SupportedVersion (r:1 w:0)
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
Expand Down
3 changes: 3 additions & 0 deletions runtime/rococo/src/weights/xcm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for RococoXcmWeight<RuntimeCall> {
fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
XcmGeneric::<Runtime>::expect_error()
}
fn expect_transact_status(_transact_status: &MaybeErrorCode) -> Weight {
XcmGeneric::<Runtime>::expect_transact_status()
}
fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
XcmGeneric::<Runtime>::query_pallet()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ impl<T: frame_system::Config> WeightInfo<T> {
pub(crate) fn expect_error() -> Weight {
Weight::from_ref_time(3_633_000 as u64)
}
pub(crate) fn expect_transact_status() -> Weight {
Weight::from_ref_time(3_633_000 as u64)
}
// Storage: XcmPallet SupportedVersion (r:1 w:0)
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
Expand Down
3 changes: 3 additions & 0 deletions runtime/westend/src/weights/xcm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for WestendXcmWeight<RuntimeCall> {
fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
XcmGeneric::<Runtime>::expect_error()
}
fn expect_transact_status(_transact_status: &MaybeErrorCode) -> Weight {
XcmGeneric::<Runtime>::expect_transact_status()
}
fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
XcmGeneric::<Runtime>::query_pallet()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ impl<T: frame_system::Config> WeightInfo<T> {
pub(crate) fn expect_error() -> Weight {
Weight::from_ref_time(5_775_000 as u64)
}
pub(crate) fn expect_transact_status() -> Weight {
Weight::from_ref_time(5_775_000 as u64)
}
// Storage: XcmPallet SupportedVersion (r:1 w:0)
// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1)
// Storage: XcmPallet SafeXcmVersion (r:1 w:0)
Expand Down
16 changes: 16 additions & 0 deletions xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,22 @@ benchmarks! {
})));
}

expect_transact_status {
let mut executor = new_executor::<T>(Default::default());
// 1024 is an overestimate but should be good enough until we have `max_encoded_len`.
// Eventually it should be replaced by `DispatchError::max_encoded_len()`.
let worst_error = || MaybeErrorCode::Error(vec![0; 1024]);
executor.set_transact_status(worst_error());

let instruction = Instruction::ExpectTransactStatus(worst_error());
let xcm = Xcm(vec![instruction]);
let mut _result = Ok(());
}: {
_result = executor.bench_process(xcm);
} verify {
assert!(matches!(_result, Ok(..)));
}

query_pallet {
let query_id = Default::default();
let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
Expand Down
29 changes: 20 additions & 9 deletions xcm/src/v3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ pub enum Instruction<Call> {
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets
/// under the ownership of `dest` within this consensus system (i.e. its sovereign account).
///
/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the wantn
/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given
/// `xcm`.
///
/// - `assets`: The asset(s) to be withdrawn.
Expand Down Expand Up @@ -588,7 +588,7 @@ pub enum Instruction<Call> {
/// Errors:
DescendOrigin(InteriorMultiLocation),

/// Immediately report the contents of the Error Register to the wantn destination via XCM.
/// Immediately report the contents of the Error Register to the given destination via XCM.
///
/// A `QueryResponse` message of type `ExecutionOutcome` is sent to the described destination.
///
Expand All @@ -614,7 +614,7 @@ pub enum Instruction<Call> {
/// the ownership of `dest` within this consensus system (i.e. deposit them into its sovereign
/// account).
///
/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the wantn `effects`.
/// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`.
///
/// - `assets`: The asset(s) to remove from holding.
/// - `dest`: The location whose sovereign account will own the assets and thus the effective
Expand Down Expand Up @@ -652,7 +652,7 @@ pub enum Instruction<Call> {
/// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The
/// sovereign account of this consensus system *on the reserve location* will have appropriate
/// assets withdrawn and `effects` will be executed on them. There will typically be only one
/// valid location on any wantn asset/chain combination.
/// valid location on any given asset/chain combination.
/// - `xcm`: The instructions to execute on the assets once withdrawn *on the reserve
/// location*.
///
Expand All @@ -677,7 +677,7 @@ pub enum Instruction<Call> {
/// Errors:
InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, xcm: Xcm<()> },

/// Report to a wantn destination the contents of the Holding Register.
/// Report to a given destination the contents of the Holding Register.
///
/// A `QueryResponse` message of type `Assets` is sent to the described destination.
///
Expand Down Expand Up @@ -795,7 +795,7 @@ pub enum Instruction<Call> {
/// Errors: *Fallible*
UnsubscribeVersion,

/// Reduce Holding by up to the wantn assets.
/// Reduce Holding by up to the given assets.
///
/// Holding is reduced by as much as possible up to the assets in the parameter. It is not an
/// error if the Holding does not contain the assets (to make this an error, use `ExpectAsset`
Expand All @@ -806,30 +806,39 @@ pub enum Instruction<Call> {
/// Errors: *Infallible*
BurnAsset(MultiAssets),

/// Throw an error if Holding does not contain at least the wantn assets.
/// Throw an error if Holding does not contain at least the given assets.
///
/// Kind: *Instruction*
///
/// Errors:
/// - `ExpectationFalse`: If Holding Register does not contain the assets in the parameter.
ExpectAsset(MultiAssets),

/// Ensure that the Origin Register equals some wantn value and throw an error if not.
/// Ensure that the Origin Register equals some given value and throw an error if not.
///
/// Kind: *Instruction*
///
/// Errors:
/// - `ExpectationFalse`: If Origin Register is not equal to the parameter.
ExpectOrigin(Option<MultiLocation>),

/// Ensure that the Error Register equals some wantn value and throw an error if not.
/// Ensure that the Error Register equals some given value and throw an error if not.
///
/// Kind: *Instruction*
///
/// Errors:
/// - `ExpectationFalse`: If the value of the Error Register is not equal to the parameter.
ExpectError(Option<(u32, Error)>),

/// Ensure that the Transact Status Register equals some given value and throw an error if
/// not.
///
/// Kind: *Instruction*
///
/// Errors:
/// - `ExpectationFalse`: If the value of the Transact Status Register is not equal to the parameter.
ExpectTransactStatus(MaybeErrorCode),

/// Query the existence of a particular pallet type.
///
/// - `module_name`: The module name of the pallet to query.
Expand Down Expand Up @@ -1088,6 +1097,7 @@ impl<Call> Instruction<Call> {
ExpectAsset(assets) => ExpectAsset(assets),
ExpectOrigin(origin) => ExpectOrigin(origin),
ExpectError(error) => ExpectError(error),
ExpectTransactStatus(transact_status) => ExpectTransactStatus(transact_status),
QueryPallet { module_name, response_info } =>
QueryPallet { module_name, response_info },
ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
Expand Down Expand Up @@ -1156,6 +1166,7 @@ impl<Call, W: XcmWeightInfo<Call>> GetWeight<W> for Instruction<Call> {
ExpectAsset(assets) => W::expect_asset(assets),
ExpectOrigin(origin) => W::expect_origin(origin),
ExpectError(error) => W::expect_error(error),
ExpectTransactStatus(transact_status) => W::expect_transact_status(transact_status),
QueryPallet { module_name, response_info } =>
W::query_pallet(module_name, response_info),
ExpectPallet { index, name, module_name, crate_major, min_crate_minor } =>
Expand Down
62 changes: 62 additions & 0 deletions xcm/xcm-builder/src/tests/transacting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,68 @@ fn report_failed_transact_status_should_work() {
assert_eq!(sent_xcm(), vec![(Parent.into(), expected_msg, expected_hash)]);
}

#[test]
fn expect_successful_transact_status_should_work() {
AllowUnpaidFrom::set(vec![Parent.into()]);

let message = Xcm::<TestCall>(vec![
Transact {
origin_kind: OriginKind::Native,
require_weight_at_most: Weight::from_parts(50, 50),
call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
},
ExpectTransactStatus(MaybeErrorCode::Success),
]);
let hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70)));

let message = Xcm::<TestCall>(vec![
Transact {
origin_kind: OriginKind::Native,
require_weight_at_most: Weight::from_parts(50, 50),
call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
},
ExpectTransactStatus(MaybeErrorCode::Success),
]);
let hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(70, 70), XcmError::ExpectationFalse));
}

#[test]
fn expect_failed_transact_status_should_work() {
AllowUnpaidFrom::set(vec![Parent.into()]);

let message = Xcm::<TestCall>(vec![
Transact {
origin_kind: OriginKind::Native,
require_weight_at_most: Weight::from_parts(50, 50),
call: TestCall::OnlyRoot(Weight::from_parts(50, 50), None).encode().into(),
},
ExpectTransactStatus(MaybeErrorCode::Error(vec![2])),
]);
let hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Complete(Weight::from_parts(70, 70)));

let message = Xcm::<TestCall>(vec![
Transact {
origin_kind: OriginKind::Native,
require_weight_at_most: Weight::from_parts(50, 50),
call: TestCall::Any(Weight::from_parts(50, 50), None).encode().into(),
},
ExpectTransactStatus(MaybeErrorCode::Error(vec![2])),
]);
let hash = fake_message_hash(&message);
let weight_limit = Weight::from_parts(70, 70);
let r = XcmExecutor::<TestConfig>::execute_xcm(Parent, message, hash, weight_limit);
assert_eq!(r, Outcome::Incomplete(Weight::from_parts(70, 70), XcmError::ExpectationFalse));
}

#[test]
fn clear_transact_status_should_work() {
AllowUnpaidFrom::set(vec![Parent.into()]);
Expand Down
4 changes: 4 additions & 0 deletions xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
ensure!(self.error == error, XcmError::ExpectationFalse);
Ok(())
},
ExpectTransactStatus(transact_status) => {
ensure!(self.transact_status == transact_status, XcmError::ExpectationFalse);
Ok(())
},
QueryPallet { module_name, response_info } => {
let pallets = Config::PalletInstancesInfo::infos()
.into_iter()
Expand Down