From 9210c42a44232b0ed3052516fa93cbdb28824eae Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 27 Apr 2023 18:22:39 +0800 Subject: [PATCH] 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 <> --- runtime/kusama/src/weights/pallet_xcm.rs | 106 +++++----- runtime/polkadot/src/weights/pallet_xcm.rs | 112 +++++----- runtime/rococo/src/weights/pallet_xcm.rs | 116 ++++++----- runtime/westend/src/weights/pallet_xcm.rs | 102 ++++++---- xcm/pallet-xcm/src/benchmarking.rs | 2 + xcm/pallet-xcm/src/lib.rs | 43 +++- xcm/src/lib.rs | 84 -------- xcm/src/v3/matcher.rs | 109 ---------- xcm/src/v3/mod.rs | 2 - xcm/xcm-builder/src/barriers.rs | 82 +++++--- xcm/xcm-builder/src/lib.rs | 5 +- xcm/xcm-builder/src/matcher.rs | 191 ++++++++++++++++++ xcm/xcm-builder/src/tests/barriers.rs | 51 +++-- xcm/xcm-builder/src/tests/mock.rs | 32 ++- xcm/xcm-builder/src/tests/mod.rs | 2 +- xcm/xcm-builder/tests/mock/mod.rs | 4 +- xcm/xcm-executor/src/traits/mod.rs | 2 +- xcm/xcm-executor/src/traits/should_execute.rs | 43 +++- 18 files changed, 644 insertions(+), 444 deletions(-) delete mode 100644 xcm/src/v3/matcher.rs create mode 100644 xcm/xcm-builder/src/matcher.rs diff --git a/runtime/kusama/src/weights/pallet_xcm.rs b/runtime/kusama/src/weights/pallet_xcm.rs index 0f2eb1eb4731..0d948a5f9ec1 100644 --- a/runtime/kusama/src/weights/pallet_xcm.rs +++ b/runtime/kusama/src/weights/pallet_xcm.rs @@ -13,25 +13,28 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=kusama-dev // --steps=50 // --repeat=20 -// --pallet=pallet_xcm // --extrinsic=* // --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=kusama-dev // --header=./file_header.txt // --output=./runtime/kusama/src/weights/ @@ -40,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); @@ -58,10 +61,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `211` - // Estimated: `14420` - // Minimum execution time: 32_211_000 picoseconds. - Weight::from_parts(32_864_000, 0) - .saturating_add(Weight::from_parts(0, 14420)) + // Estimated: `3676` + // Minimum execution time: 32_058_000 picoseconds. + Weight::from_parts(32_630_000, 0) + .saturating_add(Weight::from_parts(0, 3676)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -69,24 +72,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_186_000 picoseconds. - Weight::from_parts(21_501_000, 0) + // Minimum execution time: 21_569_000 picoseconds. + Weight::from_parts(21_969_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 20_009_000 picoseconds. - Weight::from_parts(20_431_000, 0) + // Minimum execution time: 20_667_000 picoseconds. + Weight::from_parts(21_006_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_031_000 picoseconds. - Weight::from_parts(10_350_000, 0) + // Minimum execution time: 9_993_000 picoseconds. + Weight::from_parts(10_278_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: XcmPallet SupportedVersion (r:0 w:1) @@ -95,8 +98,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_202_000 picoseconds. - Weight::from_parts(10_401_000, 0) + // Minimum execution time: 10_234_000 picoseconds. + Weight::from_parts(10_498_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -106,8 +109,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_042_000 picoseconds. - Weight::from_parts(3_161_000, 0) + // Minimum execution time: 3_272_000 picoseconds. + Weight::from_parts(3_469_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -130,10 +133,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `211` - // Estimated: `20003` - // Minimum execution time: 37_152_000 picoseconds. - Weight::from_parts(37_637_000, 0) - .saturating_add(Weight::from_parts(0, 20003)) + // Estimated: `3676` + // Minimum execution time: 36_157_000 picoseconds. + Weight::from_parts(36_777_000, 0) + .saturating_add(Weight::from_parts(0, 3676)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -154,21 +157,32 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `483` - // Estimated: `20211` - // Minimum execution time: 40_068_000 picoseconds. - Weight::from_parts(40_408_000, 0) - .saturating_add(Weight::from_parts(0, 20211)) + // Estimated: `3948` + // Minimum execution time: 39_613_000 picoseconds. + Weight::from_parts(39_905_000, 0) + .saturating_add(Weight::from_parts(0, 3948)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } + /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) + /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_296_000 picoseconds. + Weight::from_parts(3_485_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: XcmPallet SupportedVersion (r:4 w:2) /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `229` // Estimated: `11119` - // Minimum execution time: 16_679_000 picoseconds. - Weight::from_parts(17_372_000, 0) + // Minimum execution time: 16_201_000 picoseconds. + Weight::from_parts(16_681_000, 0) .saturating_add(Weight::from_parts(0, 11119)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -179,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `233` // Estimated: `11123` - // Minimum execution time: 17_113_000 picoseconds. - Weight::from_parts(17_539_000, 0) + // Minimum execution time: 16_157_000 picoseconds. + Weight::from_parts(16_674_000, 0) .saturating_add(Weight::from_parts(0, 11123)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -191,8 +205,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `243` // Estimated: `13608` - // Minimum execution time: 17_831_000 picoseconds. - Weight::from_parts(18_222_000, 0) + // Minimum execution time: 17_502_000 picoseconds. + Weight::from_parts(18_000_000, 0) .saturating_add(Weight::from_parts(0, 13608)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -211,10 +225,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `281` - // Estimated: `20991` - // Minimum execution time: 34_239_000 picoseconds. - Weight::from_parts(34_714_000, 0) - .saturating_add(Weight::from_parts(0, 20991)) + // Estimated: `6221` + // Minimum execution time: 33_198_000 picoseconds. + Weight::from_parts(33_742_000, 0) + .saturating_add(Weight::from_parts(0, 6221)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -224,8 +238,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `272` // Estimated: `8687` - // Minimum execution time: 9_813_000 picoseconds. - Weight::from_parts(10_050_000, 0) + // Minimum execution time: 8_989_000 picoseconds. + Weight::from_parts(9_241_000, 0) .saturating_add(Weight::from_parts(0, 8687)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -235,8 +249,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `240` // Estimated: `11130` - // Minimum execution time: 17_449_000 picoseconds. - Weight::from_parts(17_898_000, 0) + // Minimum execution time: 16_709_000 picoseconds. + Weight::from_parts(17_237_000, 0) .saturating_add(Weight::from_parts(0, 11130)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -256,10 +270,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `285` - // Estimated: `25965` - // Minimum execution time: 41_651_000 picoseconds. - Weight::from_parts(42_184_000, 0) - .saturating_add(Weight::from_parts(0, 25965)) + // Estimated: `11175` + // Minimum execution time: 40_749_000 picoseconds. + Weight::from_parts(41_154_000, 0) + .saturating_add(Weight::from_parts(0, 11175)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/runtime/polkadot/src/weights/pallet_xcm.rs b/runtime/polkadot/src/weights/pallet_xcm.rs index a2a7d1861d58..d3c08f33d927 100644 --- a/runtime/polkadot/src/weights/pallet_xcm.rs +++ b/runtime/polkadot/src/weights/pallet_xcm.rs @@ -13,25 +13,28 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=polkadot-dev // --steps=50 // --repeat=20 -// --pallet=pallet_xcm // --extrinsic=* // --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=polkadot-dev // --header=./file_header.txt // --output=./runtime/polkadot/src/weights/ @@ -40,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); @@ -59,11 +62,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `438` - // Estimated: `17478` - // Minimum execution time: 34_675_000 picoseconds. - Weight::from_parts(35_527_000, 0) - .saturating_add(Weight::from_parts(0, 17478)) + // Measured: `514` + // Estimated: `3979` + // Minimum execution time: 36_060_000 picoseconds. + Weight::from_parts(36_761_000, 0) + .saturating_add(Weight::from_parts(0, 3979)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -71,16 +74,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 22_653_000 picoseconds. - Weight::from_parts(23_050_000, 0) + // Minimum execution time: 23_222_000 picoseconds. + Weight::from_parts(23_506_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 21_214_000 picoseconds. - Weight::from_parts(21_604_000, 0) + // Minimum execution time: 21_932_000 picoseconds. + Weight::from_parts(22_343_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: Benchmark Override (r:0 w:0) @@ -99,8 +102,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_275_000 picoseconds. - Weight::from_parts(10_563_000, 0) + // Minimum execution time: 10_103_000 picoseconds. + Weight::from_parts(10_429_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -110,8 +113,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_001_000 picoseconds. - Weight::from_parts(3_085_000, 0) + // Minimum execution time: 3_244_000 picoseconds. + Weight::from_parts(3_367_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -135,11 +138,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `438` - // Estimated: `23742` - // Minimum execution time: 39_910_000 picoseconds. - Weight::from_parts(40_847_000, 0) - .saturating_add(Weight::from_parts(0, 23742)) + // Measured: `514` + // Estimated: `3979` + // Minimum execution time: 40_198_000 picoseconds. + Weight::from_parts(40_837_000, 0) + .saturating_add(Weight::from_parts(0, 3979)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -161,22 +164,33 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `710` - // Estimated: `23995` - // Minimum execution time: 43_293_000 picoseconds. - Weight::from_parts(43_774_000, 0) - .saturating_add(Weight::from_parts(0, 23995)) + // Measured: `786` + // Estimated: `4251` + // Minimum execution time: 42_735_000 picoseconds. + Weight::from_parts(43_343_000, 0) + .saturating_add(Weight::from_parts(0, 4251)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } + /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) + /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_333_000 picoseconds. + Weight::from_parts(3_513_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: XcmPallet SupportedVersion (r:4 w:2) /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `229` // Estimated: `11119` - // Minimum execution time: 17_985_000 picoseconds. - Weight::from_parts(18_376_000, 0) + // Minimum execution time: 16_716_000 picoseconds. + Weight::from_parts(17_399_000, 0) .saturating_add(Weight::from_parts(0, 11119)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -187,8 +201,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `233` // Estimated: `11123` - // Minimum execution time: 18_007_000 picoseconds. - Weight::from_parts(18_507_000, 0) + // Minimum execution time: 17_034_000 picoseconds. + Weight::from_parts(17_743_000, 0) .saturating_add(Weight::from_parts(0, 11123)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -199,8 +213,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `243` // Estimated: `13608` - // Minimum execution time: 18_954_000 picoseconds. - Weight::from_parts(19_612_000, 0) + // Minimum execution time: 18_741_000 picoseconds. + Weight::from_parts(19_096_000, 0) .saturating_add(Weight::from_parts(0, 13608)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -220,11 +234,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `508` - // Estimated: `24346` - // Minimum execution time: 38_137_000 picoseconds. - Weight::from_parts(38_547_000, 0) - .saturating_add(Weight::from_parts(0, 24346)) + // Measured: `584` + // Estimated: `6524` + // Minimum execution time: 37_105_000 picoseconds. + Weight::from_parts(37_579_000, 0) + .saturating_add(Weight::from_parts(0, 6524)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -234,8 +248,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `272` // Estimated: `8687` - // Minimum execution time: 9_454_000 picoseconds. - Weight::from_parts(9_729_000, 0) + // Minimum execution time: 9_111_000 picoseconds. + Weight::from_parts(9_442_000, 0) .saturating_add(Weight::from_parts(0, 8687)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -245,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `240` // Estimated: `11130` - // Minimum execution time: 17_957_000 picoseconds. - Weight::from_parts(18_748_000, 0) + // Minimum execution time: 17_846_000 picoseconds. + Weight::from_parts(18_193_000, 0) .saturating_add(Weight::from_parts(0, 11130)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -267,11 +281,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `512` - // Estimated: `29324` - // Minimum execution time: 44_805_000 picoseconds. - Weight::from_parts(45_461_000, 0) - .saturating_add(Weight::from_parts(0, 29324)) + // Measured: `588` + // Estimated: `11478` + // Minimum execution time: 43_680_000 picoseconds. + Weight::from_parts(44_528_000, 0) + .saturating_add(Weight::from_parts(0, 11478)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/runtime/rococo/src/weights/pallet_xcm.rs b/runtime/rococo/src/weights/pallet_xcm.rs index 71123a15208a..8622a60ca144 100644 --- a/runtime/rococo/src/weights/pallet_xcm.rs +++ b/runtime/rococo/src/weights/pallet_xcm.rs @@ -13,25 +13,28 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --pallet=pallet_xcm // --extrinsic=* // --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=rococo-dev // --header=./file_header.txt // --output=./runtime/rococo/src/weights/ @@ -40,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); @@ -59,11 +62,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `580` - // Estimated: `18330` - // Minimum execution time: 36_658_000 picoseconds. - Weight::from_parts(37_475_000, 0) - .saturating_add(Weight::from_parts(0, 18330)) + // Measured: `585` + // Estimated: `4050` + // Minimum execution time: 35_808_000 picoseconds. + Weight::from_parts(36_542_000, 0) + .saturating_add(Weight::from_parts(0, 4050)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -71,24 +74,24 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 23_580_000 picoseconds. - Weight::from_parts(23_929_000, 0) + // Minimum execution time: 21_646_000 picoseconds. + Weight::from_parts(21_965_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 22_900_000 picoseconds. - Weight::from_parts(23_356_000, 0) + // Minimum execution time: 20_760_000 picoseconds. + Weight::from_parts(21_030_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_655_000 picoseconds. - Weight::from_parts(10_827_000, 0) + // Minimum execution time: 10_418_000 picoseconds. + Weight::from_parts(10_625_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: XcmPallet SupportedVersion (r:0 w:1) @@ -97,8 +100,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_442_000 picoseconds. - Weight::from_parts(10_716_000, 0) + // Minimum execution time: 10_336_000 picoseconds. + Weight::from_parts(10_725_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -108,8 +111,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_056_000 picoseconds. - Weight::from_parts(3_246_000, 0) + // Minimum execution time: 3_387_000 picoseconds. + Weight::from_parts(3_515_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -133,11 +136,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `580` - // Estimated: `25020` - // Minimum execution time: 42_106_000 picoseconds. - Weight::from_parts(42_782_000, 0) - .saturating_add(Weight::from_parts(0, 25020)) + // Measured: `585` + // Estimated: `4050` + // Minimum execution time: 40_120_000 picoseconds. + Weight::from_parts(41_122_000, 0) + .saturating_add(Weight::from_parts(0, 4050)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -159,22 +162,33 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `852` - // Estimated: `25131` - // Minimum execution time: 45_010_000 picoseconds. - Weight::from_parts(45_326_000, 0) - .saturating_add(Weight::from_parts(0, 25131)) + // Measured: `857` + // Estimated: `4322` + // Minimum execution time: 43_082_000 picoseconds. + Weight::from_parts(44_150_000, 0) + .saturating_add(Weight::from_parts(0, 4322)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } + /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) + /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_375_000 picoseconds. + Weight::from_parts(3_532_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: XcmPallet SupportedVersion (r:4 w:2) /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `229` // Estimated: `11119` - // Minimum execution time: 17_856_000 picoseconds. - Weight::from_parts(18_388_000, 0) + // Minimum execution time: 17_470_000 picoseconds. + Weight::from_parts(17_718_000, 0) .saturating_add(Weight::from_parts(0, 11119)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -185,8 +199,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `233` // Estimated: `11123` - // Minimum execution time: 19_236_000 picoseconds. - Weight::from_parts(20_053_000, 0) + // Minimum execution time: 17_235_000 picoseconds. + Weight::from_parts(17_767_000, 0) .saturating_add(Weight::from_parts(0, 11123)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -197,8 +211,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `243` // Estimated: `13608` - // Minimum execution time: 21_784_000 picoseconds. - Weight::from_parts(22_509_000, 0) + // Minimum execution time: 17_793_000 picoseconds. + Weight::from_parts(18_606_000, 0) .saturating_add(Weight::from_parts(0, 13608)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -218,11 +232,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `650` - // Estimated: `25340` - // Minimum execution time: 44_384_000 picoseconds. - Weight::from_parts(45_288_000, 0) - .saturating_add(Weight::from_parts(0, 25340)) + // Measured: `655` + // Estimated: `6595` + // Minimum execution time: 36_577_000 picoseconds. + Weight::from_parts(37_312_000, 0) + .saturating_add(Weight::from_parts(0, 6595)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -232,8 +246,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `272` // Estimated: `8687` - // Minimum execution time: 10_704_000 picoseconds. - Weight::from_parts(11_054_000, 0) + // Minimum execution time: 8_756_000 picoseconds. + Weight::from_parts(9_029_000, 0) .saturating_add(Weight::from_parts(0, 8687)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -243,8 +257,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `240` // Estimated: `11130` - // Minimum execution time: 21_567_000 picoseconds. - Weight::from_parts(22_017_000, 0) + // Minimum execution time: 17_871_000 picoseconds. + Weight::from_parts(18_325_000, 0) .saturating_add(Weight::from_parts(0, 11130)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -265,11 +279,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `30318` - // Minimum execution time: 54_062_000 picoseconds. - Weight::from_parts(54_891_000, 0) - .saturating_add(Weight::from_parts(0, 30318)) + // Measured: `659` + // Estimated: `11549` + // Minimum execution time: 43_569_000 picoseconds. + Weight::from_parts(44_261_000, 0) + .saturating_add(Weight::from_parts(0, 11549)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/runtime/westend/src/weights/pallet_xcm.rs b/runtime/westend/src/weights/pallet_xcm.rs index 2282c6df48f2..84f4d0b7c103 100644 --- a/runtime/westend/src/weights/pallet_xcm.rs +++ b/runtime/westend/src/weights/pallet_xcm.rs @@ -13,25 +13,28 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . + //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-04-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=westend-dev // --steps=50 // --repeat=20 -// --pallet=pallet_xcm // --extrinsic=* // --execution=wasm // --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=westend-dev // --header=./file_header.txt // --output=./runtime/westend/src/weights/ @@ -40,7 +43,7 @@ #![allow(unused_imports)] use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); @@ -58,10 +61,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `169` - // Estimated: `14210` - // Minimum execution time: 30_377_000 picoseconds. - Weight::from_parts(30_906_000, 0) - .saturating_add(Weight::from_parts(0, 14210)) + // Estimated: `3634` + // Minimum execution time: 30_115_000 picoseconds. + Weight::from_parts(30_754_000, 0) + .saturating_add(Weight::from_parts(0, 3634)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -69,16 +72,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 20_605_000 picoseconds. - Weight::from_parts(20_951_000, 0) + // Minimum execution time: 21_511_000 picoseconds. + Weight::from_parts(21_766_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 20_055_000 picoseconds. - Weight::from_parts(20_427_000, 0) + // Minimum execution time: 20_678_000 picoseconds. + Weight::from_parts(21_141_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: Benchmark Override (r:0 w:0) @@ -97,8 +100,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_682_000 picoseconds. - Weight::from_parts(10_137_000, 0) + // Minimum execution time: 10_345_000 picoseconds. + Weight::from_parts(10_700_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -108,8 +111,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_064_000 picoseconds. - Weight::from_parts(3_201_000, 0) + // Minimum execution time: 3_317_000 picoseconds. + Weight::from_parts(3_432_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -132,10 +135,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `169` - // Estimated: `19667` - // Minimum execution time: 35_049_000 picoseconds. - Weight::from_parts(35_549_000, 0) - .saturating_add(Weight::from_parts(0, 19667)) + // Estimated: `3634` + // Minimum execution time: 34_794_000 picoseconds. + Weight::from_parts(35_424_000, 0) + .saturating_add(Weight::from_parts(0, 3634)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -156,21 +159,32 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `326` - // Estimated: `19112` - // Minimum execution time: 35_083_000 picoseconds. - Weight::from_parts(35_580_000, 0) - .saturating_add(Weight::from_parts(0, 19112)) + // Estimated: `3791` + // Minimum execution time: 35_678_000 picoseconds. + Weight::from_parts(36_056_000, 0) + .saturating_add(Weight::from_parts(0, 3791)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } + /// Storage: XcmPallet XcmExecutionSuspended (r:0 w:1) + /// Proof Skipped: XcmPallet XcmExecutionSuspended (max_values: Some(1), max_size: None, mode: Measured) + fn force_suspension() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_271_000 picoseconds. + Weight::from_parts(3_404_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: XcmPallet SupportedVersion (r:4 w:2) /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `229` // Estimated: `11119` - // Minimum execution time: 16_113_000 picoseconds. - Weight::from_parts(16_592_000, 0) + // Minimum execution time: 16_601_000 picoseconds. + Weight::from_parts(16_888_000, 0) .saturating_add(Weight::from_parts(0, 11119)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -181,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `233` // Estimated: `11123` - // Minimum execution time: 18_071_000 picoseconds. - Weight::from_parts(18_527_000, 0) + // Minimum execution time: 16_714_000 picoseconds. + Weight::from_parts(17_048_000, 0) .saturating_add(Weight::from_parts(0, 11123)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -193,8 +207,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `243` // Estimated: `13608` - // Minimum execution time: 18_498_000 picoseconds. - Weight::from_parts(19_091_000, 0) + // Minimum execution time: 17_552_000 picoseconds. + Weight::from_parts(17_860_000, 0) .saturating_add(Weight::from_parts(0, 13608)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -213,10 +227,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `239` - // Estimated: `20739` - // Minimum execution time: 31_568_000 picoseconds. - Weight::from_parts(32_163_000, 0) - .saturating_add(Weight::from_parts(0, 20739)) + // Estimated: `6179` + // Minimum execution time: 31_655_000 picoseconds. + Weight::from_parts(32_201_000, 0) + .saturating_add(Weight::from_parts(0, 6179)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -226,8 +240,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `272` // Estimated: `8687` - // Minimum execution time: 9_139_000 picoseconds. - Weight::from_parts(9_619_000, 0) + // Minimum execution time: 8_969_000 picoseconds. + Weight::from_parts(9_314_000, 0) .saturating_add(Weight::from_parts(0, 8687)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -237,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `240` // Estimated: `11130` - // Minimum execution time: 16_944_000 picoseconds. - Weight::from_parts(17_505_000, 0) + // Minimum execution time: 17_142_000 picoseconds. + Weight::from_parts(17_694_000, 0) .saturating_add(Weight::from_parts(0, 11130)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -258,10 +272,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `243` - // Estimated: `25713` - // Minimum execution time: 38_715_000 picoseconds. - Weight::from_parts(39_473_000, 0) - .saturating_add(Weight::from_parts(0, 25713)) + // Estimated: `11133` + // Minimum execution time: 38_257_000 picoseconds. + Weight::from_parts(39_042_000, 0) + .saturating_add(Weight::from_parts(0, 11133)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/xcm/pallet-xcm/src/benchmarking.rs b/xcm/pallet-xcm/src/benchmarking.rs index bb0fe930199a..8702f83e09cf 100644 --- a/xcm/pallet-xcm/src/benchmarking.rs +++ b/xcm/pallet-xcm/src/benchmarking.rs @@ -115,6 +115,8 @@ benchmarks! { let _ = Pallet::::request_version_notify(loc); }: _(RawOrigin::Root, Box::new(versioned_loc)) + force_suspension {}: _(RawOrigin::Root, true) + migrate_supported_version { let old_version = XCM_VERSION - 1; let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 47a9d7d75d0a..c76032d01b02 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -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, }; @@ -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; @@ -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) } @@ -609,6 +615,10 @@ pub mod pallet { OptionQuery, >; + /// Global suspension state of the XCM executor. + #[pallet::storage] + pub(super) type XcmExecutionSuspended = StorageValue<_, bool, ValueQuery>; + #[pallet::genesis_config] pub struct GenesisConfig { /// The default version to encode outgoing XCM messages with. @@ -905,7 +915,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)] @@ -929,7 +939,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())] @@ -944,7 +954,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())] @@ -967,7 +977,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)] @@ -1089,6 +1099,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, suspended: bool) -> DispatchResult { + ensure_root(origin)?; + XcmExecutionSuspended::::set(suspended); + Ok(()) + } } } @@ -2035,6 +2057,17 @@ impl OnResponse for Pallet { } } +impl CheckSuspension for Pallet { + fn is_suspended( + _origin: &MultiLocation, + _instructions: &mut [Instruction], + _max_weight: Weight, + _weight_credit: &mut Weight, + ) -> bool { + XcmExecutionSuspended::::get() + } +} + /// Ensure that the origin `o` represents an XCM (`Transact`) origin. /// /// Returns `Ok` with the location of the XCM sender or an `Err` otherwise. diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 0f919b892179..5889eded20f4 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -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; @@ -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 - 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(self, f: F) -> Result - 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(self, cond: C, f: F) -> Result - where - Self: Sized, - C: Fn(&Self::Inst) -> bool, - F: FnMut(&mut Self::Inst) -> Result, 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(self, cond: C) -> Result - 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 {} diff --git a/xcm/src/v3/matcher.rs b/xcm/src/v3/matcher.rs deleted file mode 100644 index de390338e3f5..000000000000 --- a/xcm/src/v3/matcher.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2023 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 . - -//! XCM matcher API, used primarily for writing barrier conditions. - -use super::{Instruction, MultiLocation}; -use crate::{CreateMatcher, MatchXcm}; -use core::ops::ControlFlow; - -impl<'a, Call> CreateMatcher for &'a mut [Instruction] { - type Matcher = Matcher<'a, Call>; - - fn matcher(self) -> Self::Matcher { - let total_inst = self.len(); - - Matcher { xcm: self, current_idx: 0, total_inst } - } -} - -/// 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], - pub(crate) current_idx: usize, - pub(crate) total_inst: usize, -} - -impl<'a, Call> MatchXcm for Matcher<'a, Call> { - type Error = (); - type Inst = Instruction; - type Loc = MultiLocation; - - fn assert_remaining_insts(self, n: usize) -> Result - where - Self: Sized, - { - if self.total_inst - self.current_idx != n { - return Err(()) - } - - Ok(self) - } - - fn match_next_inst(mut self, mut f: F) -> Result - 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(()) - } - } - - fn match_next_inst_while(mut self, cond: C, mut f: F) -> Result - where - Self: Sized, - C: Fn(&Self::Inst) -> bool, - F: FnMut(&mut Self::Inst) -> Result, Self::Error>, - { - if self.current_idx >= self.total_inst { - return Err(()) - } - - 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 crate::v3::prelude::*; - use alloc::{vec, vec::Vec}; - - #[test] - fn match_next_inst_while_works() { - let mut xcm: Vec> = vec![ClearOrigin]; - - let _ = xcm - .matcher() - .match_next_inst_while(|_| true, |_| Ok(ControlFlow::Continue(()))) - .unwrap(); - } -} diff --git a/xcm/src/v3/mod.rs b/xcm/src/v3/mod.rs index 90b9c74df0cb..9a1a4a6ba82f 100644 --- a/xcm/src/v3/mod.rs +++ b/xcm/src/v3/mod.rs @@ -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, diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 02de36caeb6f..10a98da48e7c 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -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], 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> ShouldExecute for AllowTopLevelPaidExecutionFro instructions: &mut [Instruction], 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> 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> ShouldExecute for AllowTopLevelPaidExecutionFro *weight_limit = Limited(max_weight); Ok(()) }, - _ => Err(()), + _ => Err(ProcessMessageError::Overweight(max_weight)), })?; Ok(()) } @@ -167,7 +167,7 @@ impl< instructions: &mut [Instruction], 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(PhantomData<(Inner, SuspensionChecker)>); +impl ShouldExecute for RespectSuspension +where + Inner: ShouldExecute, + SuspensionChecker: CheckSuspension, +{ + fn should_execute( + origin: &MultiLocation, + instructions: &mut [Instruction], + 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> ShouldExecute for AllowUnpaidExecutionFrom { instructions: &mut [Instruction], _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> ShouldExecute for AllowExplicitUnpaidExecutionF instructions: &mut [Instruction], 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 ShouldExecute for AllowKnownQueryResponses], _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 ShouldExecute for AllowKnownQueryResponses Ok(()), - _ => Err(()), + _ => Err(ProcessMessageError::BadFormat), })?; Ok(()) } @@ -305,19 +329,19 @@ impl> ShouldExecute for AllowSubscriptionsFrom { instructions: &mut [Instruction], _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(()) } diff --git a/xcm/xcm-builder/src/lib.rs b/xcm/xcm-builder/src/lib.rs index 2379297010a1..32fcf1e36e14 100644 --- a/xcm/xcm-builder/src/lib.rs +++ b/xcm/xcm-builder/src/lib.rs @@ -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}; diff --git a/xcm/xcm-builder/src/matcher.rs b/xcm/xcm-builder/src/matcher.rs new file mode 100644 index 000000000000..038a45acf730 --- /dev/null +++ b/xcm/xcm-builder/src/matcher.rs @@ -0,0 +1,191 @@ +// Copyright 2023 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 . + +//! 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] { + 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 + 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(self, f: F) -> Result + 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(self, cond: C, f: F) -> Result + where + Self: Sized, + C: Fn(&Self::Inst) -> bool, + F: FnMut(&mut Self::Inst) -> Result, 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(self, cond: C) -> Result + 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], + pub(crate) current_idx: usize, + pub(crate) total_inst: usize, +} + +impl<'a, Call> MatchXcm for Matcher<'a, Call> { + type Error = ProcessMessageError; + type Inst = Instruction; + type Loc = MultiLocation; + + fn assert_remaining_insts(self, n: usize) -> Result + where + Self: Sized, + { + if self.total_inst - self.current_idx != n { + return Err(ProcessMessageError::BadFormat) + } + + Ok(self) + } + + fn match_next_inst(mut self, mut f: F) -> Result + 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(mut self, cond: C, mut f: F) -> Result + where + Self: Sized, + C: Fn(&Self::Inst) -> bool, + F: FnMut(&mut Self::Inst) -> Result, 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> = vec![ClearOrigin]; + + let _ = xcm + .matcher() + .match_next_inst_while(|_| true, |_| Ok(ControlFlow::Continue(()))) + .unwrap(); + } +} diff --git a/xcm/xcm-builder/src/tests/barriers.rs b/xcm/xcm-builder/src/tests/barriers.rs index a7889c7e212d..48236fde7b6b 100644 --- a/xcm/xcm-builder/src/tests/barriers.rs +++ b/xcm/xcm-builder/src/tests/barriers.rs @@ -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>, @@ -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>, @@ -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::>::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::>::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::>::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::>::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::>::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::>::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::>::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::>, 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::>, TestSuspender>::should_execute( + &Parent.into(), + message.inner_mut(), + Weight::from_parts(10, 10), + &mut Weight::zero(), + ); + assert_eq!(r, Ok(())); +} diff --git a/xcm/xcm-builder/src/tests/mock.rs b/xcm/xcm-builder/src/tests/mock.rs index fa85d09a443e..a98f63152ecf 100644 --- a/xcm/xcm-builder/src/tests/mock.rs +++ b/xcm/xcm-builder/src/tests/mock.rs @@ -14,7 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -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, )>> = RefCell::new(None); pub static SEND_PRICE: RefCell = RefCell::new(MultiAssets::new()); + pub static SUSPENDED: Cell = 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( + _origin: &MultiLocation, + _instructions: &mut [Instruction], + _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, @@ -629,7 +651,7 @@ impl Config for TestConfig { type IsReserve = TestIsReserve; type IsTeleporter = TestIsTeleporter; type UniversalLocation = ExecutorUniversalLocation; - type Barrier = TestBarrier; + type Barrier = RespectSuspension; type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = TestResponseHandler; diff --git a/xcm/xcm-builder/src/tests/mod.rs b/xcm/xcm-builder/src/tests/mod.rs index cc83d9d5ac98..92ef8067e0a7 100644 --- a/xcm/xcm-builder/src/tests/mod.rs +++ b/xcm/xcm-builder/src/tests/mod.rs @@ -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}; diff --git a/xcm/xcm-builder/tests/mock/mod.rs b/xcm/xcm-builder/tests/mock/mod.rs index a265bff1e352..7059f1eb0988 100644 --- a/xcm/xcm-builder/tests/mock/mod.rs +++ b/xcm/xcm-builder/tests/mock/mod.rs @@ -33,7 +33,7 @@ use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, - IsChildSystemParachain, IsConcrete, MintLocation, SignedAccountId32AsNative, + IsChildSystemParachain, IsConcrete, MintLocation, RespectSuspension, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; @@ -182,7 +182,7 @@ impl xcm_executor::Config for XcmConfig { type IsReserve = (); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; - type Barrier = Barrier; + type Barrier = RespectSuspension; type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = XcmPallet; diff --git a/xcm/xcm-executor/src/traits/mod.rs b/xcm/xcm-executor/src/traits/mod.rs index 94fe7e98a7db..6bb965196846 100644 --- a/xcm/xcm-executor/src/traits/mod.rs +++ b/xcm/xcm-executor/src/traits/mod.rs @@ -40,7 +40,7 @@ pub use token_matching::{ mod on_response; pub use on_response::{OnResponse, VersionChangeNotifier}; mod should_execute; -pub use should_execute::ShouldExecute; +pub use should_execute::{CheckSuspension, ShouldExecute}; mod transact_asset; pub use transact_asset::TransactAsset; mod weight; diff --git a/xcm/xcm-executor/src/traits/should_execute.rs b/xcm/xcm-executor/src/traits/should_execute.rs index 7db8fbe4a09e..a61dc5727b22 100644 --- a/xcm/xcm-executor/src/traits/should_execute.rs +++ b/xcm/xcm-executor/src/traits/should_execute.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use frame_support::traits::ProcessMessageError; use sp_std::result::Result; use xcm::latest::{Instruction, MultiLocation, Weight}; @@ -35,7 +36,7 @@ pub trait ShouldExecute { instructions: &mut [Instruction], max_weight: Weight, weight_credit: &mut Weight, - ) -> Result<(), ()>; + ) -> Result<(), ProcessMessageError>; } #[impl_trait_for_tuples::impl_for_tuples(30)] @@ -45,7 +46,7 @@ impl ShouldExecute for Tuple { instructions: &mut [Instruction], max_weight: Weight, weight_credit: &mut Weight, - ) -> Result<(), ()> { + ) -> Result<(), ProcessMessageError> { for_tuples!( #( match Tuple::should_execute(origin, instructions, max_weight, weight_credit) { Ok(()) => return Ok(()), @@ -60,6 +61,42 @@ impl ShouldExecute for Tuple { max_weight, weight_credit, ); - Err(()) + Err(ProcessMessageError::Unsupported) + } +} + +/// Trait to determine whether the execution engine is suspended from executing a given XCM. +/// +/// The trait method is given the same parameters as `ShouldExecute::should_execute`, so that the +/// implementer will have all the context necessary to determine whether or not to suspend the +/// XCM executor. +/// +/// Can be chained together in tuples to have multiple rounds of checks. If all of the tuple +/// elements returns false, then execution is not suspended. Otherwise, execution is suspended +/// if any of the tuple elements returns true. +pub trait CheckSuspension { + fn is_suspended( + origin: &MultiLocation, + instructions: &mut [Instruction], + max_weight: Weight, + weight_credit: &mut Weight, + ) -> bool; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl CheckSuspension for Tuple { + fn is_suspended( + origin: &MultiLocation, + instruction: &mut [Instruction], + max_weight: Weight, + weight_credit: &mut Weight, + ) -> bool { + for_tuples!( #( + if Tuple::is_suspended(origin, instruction, max_weight, weight_credit) { + return true + } + )* ); + + false } }