XCM: ExpectTransactStatus instruction (#6578)

* Introduce ExpectTransactStatus instruction

* Remove other changes

* Implement

* Implement rest

* Benchmark

* Update xcm/src/v3/mod.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Update xcm/src/v3/mod.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Gavin Wood
2023-01-19 03:59:38 -03:00
committed by GitHub
parent 90aa798b76
commit 8eeb654b04
10 changed files with 120 additions and 9 deletions
@@ -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()
}
@@ -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)
@@ -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()
}
@@ -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)
@@ -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()
}
@@ -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)
@@ -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)?;
+20 -9
View File
@@ -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.
@@ -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.
///
@@ -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
@@ -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*.
///
@@ -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.
///
@@ -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`
@@ -806,7 +806,7 @@ 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*
///
@@ -814,7 +814,7 @@ pub enum Instruction<Call> {
/// - `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*
///
@@ -822,7 +822,7 @@ pub enum Instruction<Call> {
/// - `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*
///
@@ -830,6 +830,15 @@ pub enum Instruction<Call> {
/// - `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.
@@ -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 } =>
@@ -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 } =>
@@ -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()]);
+4
View File
@@ -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()