From f0b2bf3c20a7fae381685c7f6bb3c36fbce65722 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 27 Sep 2021 00:38:46 -0400 Subject: [PATCH] XCM Benchmarks for Asset Transactor w/ Fungible Asset (#3818) * benchmarks for fungibles * add benchmark to westend * fix hex * clean up a bit * update code doc * fix warnings * cargo run --quiet --release --features runtime-benchmarks -- benchmark --chain=westend-dev --pallet=pallet_xcm_benchmarks::fungible --extrinsic=* --steps=10 --repeat=10 --template=./xcm/pallet-xcm-benchmarks/template.hbs --output=./ --execution=wasm --wasm-execution=compiled * use skip * fix spelling * Update Cargo.lock * add scale-info * Update Cargo.lock * update bench * cargo run --quiet --release --features=runtime-benchmarks -- benchmark --chain=westend-dev --steps=50 --repeat=20 --pallet=pallet_xcm_benchmarks::fungible --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --template=./xcm/pallet-xcm-benchmarks/template.hbs --output=./runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs * weights compile * update westend to use weights * fmt * spelling fixes * Delete pallet_xcm_benchmarks::fungible.rs * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix code review * update weight * fix report_error * fix spell check Co-authored-by: Parity Bot Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 41 ++++ Cargo.toml | 1 + .../src/weights/runtime_common_crowdloan.rs | 2 +- .../weights/runtime_common_paras_registrar.rs | 2 +- runtime/westend/Cargo.toml | 4 +- runtime/westend/src/lib.rs | 68 +++++- runtime/westend/src/weights/mod.rs | 1 + runtime/westend/src/weights/xcm/mod.rs | 193 +++++++++++++++ .../xcm/pallet_xcm_benchmarks_fungible.rs | 95 ++++++++ .../xcm/pallet_xcm_benchmarks_generic.rs | 73 ++++++ xcm/Cargo.toml | 1 + xcm/pallet-xcm-benchmarks/Cargo.toml | 45 ++++ .../src/fungible/benchmarking.rs | 219 ++++++++++++++++++ .../src/fungible/mock.rs | 180 ++++++++++++++ xcm/pallet-xcm-benchmarks/src/fungible/mod.rs | 47 ++++ xcm/pallet-xcm-benchmarks/src/lib.rs | 108 +++++++++ xcm/pallet-xcm-benchmarks/src/mock.rs | 64 +++++ xcm/pallet-xcm-benchmarks/template.hbs | 66 ++++++ xcm/xcm-builder/src/lib.rs | 4 +- xcm/xcm-builder/src/weight.rs | 2 +- xcm/xcm-executor/Cargo.toml | 4 + xcm/xcm-executor/src/assets.rs | 2 +- 22 files changed, 1206 insertions(+), 16 deletions(-) create mode 100644 runtime/westend/src/weights/xcm/mod.rs create mode 100644 runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs create mode 100644 runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs create mode 100644 xcm/pallet-xcm-benchmarks/Cargo.toml create mode 100644 xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs create mode 100644 xcm/pallet-xcm-benchmarks/src/fungible/mock.rs create mode 100644 xcm/pallet-xcm-benchmarks/src/fungible/mod.rs create mode 100644 xcm/pallet-xcm-benchmarks/src/lib.rs create mode 100644 xcm/pallet-xcm-benchmarks/src/mock.rs create mode 100644 xcm/pallet-xcm-benchmarks/template.hbs diff --git a/Cargo.lock b/Cargo.lock index 41bf2524834f..4cd57cec08b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4605,6 +4605,20 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13370dae44474229701bb69b90b4f4dca6404cb0357a2d50d635f1171dc3aa7b" +[[package]] +name = "pallet-assets" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#c000780dba99a611fadbf83873073e024be1be0b" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" @@ -5429,6 +5443,31 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "pallet-xcm-benchmarks" +version = "0.9.8" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-assets", + "pallet-balances", + "pallet-xcm", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-common", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-tracing", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "parity-db" version = "0.3.1" @@ -11607,6 +11646,7 @@ dependencies = [ "pallet-utility", "pallet-vesting", "pallet-xcm", + "pallet-xcm-benchmarks", "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", @@ -11776,6 +11816,7 @@ dependencies = [ name = "xcm-executor" version = "0.9.9" dependencies = [ + "frame-benchmarking", "frame-support", "impl-trait-for-tuples", "log", diff --git a/Cargo.toml b/Cargo.toml index 5ea0f98eef6d..1a8407e53a91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "xcm/xcm-simulator", "xcm/xcm-simulator/example", "xcm/pallet-xcm", + "xcm/pallet-xcm-benchmarks", "xcm/procedural", "node/client", "node/collation-generation", diff --git a/runtime/polkadot/src/weights/runtime_common_crowdloan.rs b/runtime/polkadot/src/weights/runtime_common_crowdloan.rs index e69442c8a884..7929c8c16754 100644 --- a/runtime/polkadot/src/weights/runtime_common_crowdloan.rs +++ b/runtime/polkadot/src/weights/runtime_common_crowdloan.rs @@ -41,7 +41,7 @@ use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for runtime_common::crowdloan. +/// Weight functions for `runtime_common::crowdloan`. pub struct WeightInfo(PhantomData); impl runtime_common::crowdloan::WeightInfo for WeightInfo { // Storage: Crowdloan Funds (r:1 w:1) diff --git a/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs b/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs index 8dfc9409741c..84d3a89e92d0 100644 --- a/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs +++ b/runtime/polkadot/src/weights/runtime_common_paras_registrar.rs @@ -41,7 +41,7 @@ use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; -/// Weight functions for runtime_common::paras_registrar. +/// Weight functions for `runtime_common::paras_registrar`. pub struct WeightInfo(PhantomData); impl runtime_common::paras_registrar::WeightInfo for WeightInfo { // Storage: Registrar NextFreeParaId (r:1 w:1) diff --git a/runtime/westend/Cargo.toml b/runtime/westend/Cargo.toml index eecc6a56c5bd..3b41179ad350 100644 --- a/runtime/westend/Cargo.toml +++ b/runtime/westend/Cargo.toml @@ -40,6 +40,7 @@ frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate" pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-bags-list = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-collective = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-democracy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -69,7 +70,7 @@ pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "m pallet-utility = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-vesting = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -pallet-bags-list = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-xcm-benchmarks = { path = "../../xcm/pallet-xcm-benchmarks", default-features = false, optional = true } frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } frame-try-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } @@ -202,6 +203,7 @@ runtime-benchmarks = [ "frame-system-benchmarking", "hex-literal", "xcm-builder/runtime-benchmarks", + "pallet-xcm-benchmarks", "frame-election-provider-support/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", ] diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 196a28d57819..e237a473c2ac 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -49,9 +49,9 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete, - LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, - TakeWeightCredit, UsingComponents, + CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, LocationInverter, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, WeightInfoBounds, }; use xcm_executor::XcmExecutor; @@ -951,10 +951,6 @@ type LocalOriginConverter = ( ChildSystemParachainAsSuperuser, ); -parameter_types! { - pub const BaseXcmWeight: Weight = 1_000_000_000; -} - /// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our /// individual routers. pub type XcmRouter = ( @@ -963,8 +959,9 @@ pub type XcmRouter = ( ); parameter_types! { + pub const Westmint: MultiLocation = Parachain(1000).into(); pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) = - (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Parachain(1000).into()); + (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Westmint::get()); pub const MaxInstructions: u32 = 100; } pub type TrustedTeleporters = (xcm_builder::Case,); @@ -989,7 +986,7 @@ impl xcm_executor::Config for XcmConfig { type IsTeleporter = TrustedTeleporters; type LocationInverter = LocationInverter; type Barrier = Barrier; - type Weigher = FixedWeightBounds; + type Weigher = WeightInfoBounds, Call, MaxInstructions>; type Trader = UsingComponents>; type ResponseHandler = XcmPallet; type AssetTrap = XcmPallet; @@ -1015,7 +1012,7 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; + type Weigher = WeightInfoBounds, Call, MaxInstructions>; type LocationInverter = LocationInverter; type Origin = Origin; type Call = Call; @@ -1468,6 +1465,8 @@ sp_api::impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use frame_system_benchmarking::Pallet as SystemBench; + type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; + let mut list = Vec::::new(); // Polkadot @@ -1479,6 +1478,7 @@ sp_api::impl_runtime_apis! { list_benchmark!(list, extra, runtime_common::slots, Slots); list_benchmark!(list, extra, runtime_parachains::configuration, Configuration); list_benchmark!(list, extra, runtime_parachains::paras, Paras); + // Substrate list_benchmark!(list, extra, pallet_bags_list, BagsList); list_benchmark!(list, extra, pallet_balances, Balances); @@ -1497,6 +1497,10 @@ sp_api::impl_runtime_apis! { list_benchmark!(list, extra, pallet_utility, Utility); list_benchmark!(list, extra, pallet_vesting, Vesting); + // XCM Benchmarks + // NOTE: Make sure you point to the individual modules below. + list_benchmark!(list, extra, pallet_xcm_benchmarks::fungible, XcmBalances); + let storage_info = AllPalletsWithSystem::storage_info(); return (list, storage_info) @@ -1519,6 +1523,39 @@ sp_api::impl_runtime_apis! { impl pallet_offences_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {} + use xcm::latest::MultiAsset; + + impl pallet_xcm_benchmarks::Config for Runtime { + type XcmConfig = XcmConfig; + type AccountIdConverter = LocationConverter; + fn valid_destination() -> Result { + Ok(Westmint::get()) + } + } + + parameter_types! { + pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( + Westmint::get(), + MultiAsset { fun: Fungible(1 * UNITS), id: Concrete(WndLocation::get()) }, + )); + } + + impl pallet_xcm_benchmarks::fungible::Config for Runtime { + type TransactAsset = Balances; + + type CheckedAccount = CheckAccount; + type TrustedTeleporter = TrustedTeleporter; + + fn get_multi_asset() -> MultiAsset { + MultiAsset { + id: Concrete(WndLocation::get()), + fun: Fungible(1 * UNITS), + } + } + } + + type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), @@ -1532,6 +1569,12 @@ sp_api::impl_runtime_apis! { hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), // Treasury Account hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec().into(), + // Dmp DownwardMessageQueueHeads + hex_literal::hex!("63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5").to_vec().into(), + // Dmp DownwardMessageQueues + hex_literal::hex!("63f78c98723ddc9073523ef3beefda0ca95dac46c07a40d91506e7637ec4ba57").to_vec().into(), + // Configuration ActiveConfig + hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385").to_vec().into(), ]; let mut batches = Vec::::new(); @@ -1546,6 +1589,7 @@ sp_api::impl_runtime_apis! { add_benchmark!(params, batches, runtime_common::slots, Slots); add_benchmark!(params, batches, runtime_parachains::configuration, Configuration); add_benchmark!(params, batches, runtime_parachains::paras, Paras); + // Substrate add_benchmark!(params, batches, pallet_bags_list, BagsList); add_benchmark!(params, batches, pallet_balances, Balances); @@ -1564,6 +1608,10 @@ sp_api::impl_runtime_apis! { add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_vesting, Vesting); + // XCM Benchmarks + // NOTE: Make sure you point to the individual modules below. + add_benchmark!(params, batches, pallet_xcm_benchmarks::fungible, XcmBalances); + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) } diff --git a/runtime/westend/src/weights/mod.rs b/runtime/westend/src/weights/mod.rs index c7dba930ed49..afca6434f826 100644 --- a/runtime/westend/src/weights/mod.rs +++ b/runtime/westend/src/weights/mod.rs @@ -36,3 +36,4 @@ pub mod runtime_common_paras_registrar; pub mod runtime_common_slots; pub mod runtime_parachains_configuration; pub mod runtime_parachains_paras; +pub mod xcm; diff --git a/runtime/westend/src/weights/xcm/mod.rs b/runtime/westend/src/weights/xcm/mod.rs new file mode 100644 index 000000000000..1b0d7c1ef485 --- /dev/null +++ b/runtime/westend/src/weights/xcm/mod.rs @@ -0,0 +1,193 @@ +mod pallet_xcm_benchmarks_fungible; +mod pallet_xcm_benchmarks_generic; + +use crate::Runtime; +use frame_support::weights::Weight; +use sp_std::prelude::*; +use xcm::{latest::prelude::*, DoubleEncoded}; + +use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; +use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; + +/// Types of asset supported by the westend runtime. +pub enum AssetTypes { + /// An asset backed by `pallet-balances`. + Balances, + /// Unknown asset. + Unknown, +} + +impl From<&MultiAsset> for AssetTypes { + fn from(asset: &MultiAsset) -> Self { + match asset { + MultiAsset { id: Concrete(MultiLocation { parents: 0, interior: Here }), .. } => + AssetTypes::Balances, + _ => AssetTypes::Unknown, + } + } +} + +trait WeighMultiAssets { + fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight; +} + +// TODO wild case +impl WeighMultiAssets for MultiAssetFilter { + fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight { + match self { + Self::Definite(assets) => assets + .inner() + .into_iter() + .map(From::from) + .map(|t| match t { + AssetTypes::Balances => balances_weight, + AssetTypes::Unknown => Weight::MAX, + }) + .fold(0, |acc, x| acc.saturating_add(x)), + _ => Weight::MAX, + } + } +} + +impl WeighMultiAssets for MultiAssets { + fn weigh_multi_assets(&self, balances_weight: Weight) -> Weight { + self.inner() + .into_iter() + .map(|m| >::from(m)) + .map(|t| match t { + AssetTypes::Balances => balances_weight, + AssetTypes::Unknown => Weight::MAX, + }) + .fold(0, |acc, x| acc.saturating_add(x)) + } +} + +pub struct WestendXcmWeight(core::marker::PhantomData); +impl XcmWeightInfo for WestendXcmWeight { + fn withdraw_asset(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::withdraw_asset()) + } + fn reserve_asset_deposited(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmGeneric::::reserve_asset_deposited()) + } + fn receive_teleported_asset(assets: &MultiAssets) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::receive_teleported_asset()) + } + fn query_response(_query_id: &u64, _response: &Response, max_weight: &u64) -> Weight { + *max_weight + } + fn transfer_asset(assets: &MultiAssets, _dest: &MultiLocation) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::transfer_asset()) + } + fn transfer_reserve_asset( + assets: &MultiAssets, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::transfer_reserve_asset()) + } + fn transact( + _origin_type: &OriginKind, + _require_weight_at_most: &u64, + _call: &DoubleEncoded, + ) -> Weight { + XcmGeneric::::transact() + } + fn hrmp_new_channel_open_request( + _sender: &u32, + _max_message_size: &u32, + _max_capacity: &u32, + ) -> Weight { + XcmGeneric::::hrmp_new_channel_open_request() + } + fn hrmp_channel_accepted(_recipient: &u32) -> Weight { + XcmGeneric::::hrmp_channel_accepted() + } + fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> Weight { + XcmGeneric::::hrmp_channel_closing() + } + fn clear_origin() -> Weight { + XcmGeneric::::clear_origin() + } + fn descend_origin(who: &InteriorMultiLocation) -> Weight { + XcmGeneric::::descend_origin(who) + } + fn report_error( + _query_id: &QueryId, + _dest: &MultiLocation, + _max_response_weight: &u64, + ) -> Weight { + XcmGeneric::::report_error() + } + fn relayed_from(_who: &Junctions, _message: &Box>) -> Weight { + XcmGeneric::::relayed_from() + } + + fn deposit_asset( + assets: &MultiAssetFilter, + _max_assets: &u32, // TODO use max assets? + _dest: &MultiLocation, + ) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::deposit_asset()) + } + fn deposit_reserve_asset( + assets: &MultiAssetFilter, + _max_assets: &u32, // TODO use max assets? + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::deposit_reserve_asset()) + } + fn exchange_asset(_give: &MultiAssetFilter, _receive: &MultiAssets) -> Weight { + Weight::MAX // todo fix + } + fn initiate_reserve_withdraw( + assets: &MultiAssetFilter, + _reserve: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmGeneric::::initiate_reserve_withdraw()) + } + fn initiate_teleport( + assets: &MultiAssetFilter, + _dest: &MultiLocation, + _xcm: &Xcm<()>, + ) -> Weight { + assets.weigh_multi_assets(XcmBalancesWeight::::initiate_teleport()) + } + fn query_holding( + _query_id: &u64, + _dest: &MultiLocation, + _assets: &MultiAssetFilter, + _max_response_weight: &u64, + ) -> Weight { + XcmGeneric::::query_holding() + } + fn buy_execution(_fees: &MultiAsset, _weight_limit: &WeightLimit) -> Weight { + XcmGeneric::::buy_execution() + } + fn refund_surplus() -> Weight { + XcmGeneric::::refund_surplus() + } + fn set_error_handler(_xcm: &Xcm) -> Weight { + XcmGeneric::::set_error_handler() + } + fn set_appendix(_xcm: &Xcm) -> Weight { + XcmGeneric::::set_appendix() + } + fn clear_error() -> Weight { + XcmGeneric::::clear_error() + } + fn claim_asset(assets: &MultiAssets, _ticket: &MultiLocation) -> Weight { + XcmGeneric::::claim_asset(assets) + } + fn trap(code: &u64) -> Weight { + XcmGeneric::::trap(code) + } + fn subscribe_version(_query_id: &QueryId, _max_response_weight: &u64) -> Weight { + XcmGeneric::::subscribe_version() + } + fn unsubscribe_version() -> Weight { + XcmGeneric::::unsubscribe_version() + } +} diff --git a/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs new file mode 100644 index 000000000000..869c1bca408f --- /dev/null +++ b/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -0,0 +1,95 @@ +// Copyright 2017-2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-09-17, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 128 + +// Executed Command: +// target/release/polkadot +// benchmark +// --chain=westend-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_xcm_benchmarks::fungible +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --header=./file_header.txt +// --template=./xcm/pallet-xcm-benchmarks/template.hbs +// --output=./runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm_benchmarks::fungible`. +pub struct WeightInfo(PhantomData); +impl WeightInfo { + // Storage: System Account (r:1 w:1) + pub(crate) fn withdraw_asset() -> Weight { + (39_691_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:2 w:2) + pub(crate) fn transfer_asset() -> Weight { + (62_616_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + // Storage: System Account (r:2 w:2) + // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + pub(crate) fn transfer_reserve_asset() -> Weight { + (86_642_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + // Storage: Benchmark Override (r:0 w:0) + pub(crate) fn receive_teleported_asset() -> Weight { + (2_000_000_000_000 as Weight) + } + // Storage: System Account (r:1 w:1) + pub(crate) fn deposit_asset() -> Weight { + (49_745_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: System Account (r:1 w:1) + // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + pub(crate) fn deposit_reserve_asset() -> Weight { + (75_318_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: System Account (r:1 w:1) + // Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) + // Storage: Dmp DownwardMessageQueues (r:1 w:1) + pub(crate) fn initiate_teleport() -> Weight { + (75_467_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } +} diff --git a/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs new file mode 100644 index 000000000000..5c8626f0b22a --- /dev/null +++ b/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -0,0 +1,73 @@ +// this whole file is temp, and will be replaced in the future TODO + +use frame_support::dispatch::Weight; + +pub struct WeightInfo(sp_std::marker::PhantomData); +impl WeightInfo { + pub fn query_holding() -> Weight { + 1_000_000_000 + } + pub fn buy_execution() -> Weight { + 1_000_000_000 + } + pub fn transact() -> Weight { + 1_000_000_000 + } + pub fn reserve_asset_deposited() -> Weight { + 1_000_000_000 + } + pub fn hrmp_new_channel_open_request() -> Weight { + 1_000_000_000 + } + pub fn hrmp_channel_accepted() -> Weight { + 1_000_000_000 + } + pub fn hrmp_channel_closing() -> Weight { + 1_000_000_000 + } + pub fn relayed_from() -> Weight { + 1_000_000_000 + } + pub fn refund_surplus() -> Weight { + 1_000_000_000 + } + pub fn set_error_handler() -> Weight { + 1_000_000_000 + } + pub fn set_appendix() -> Weight { + 1_000_000_000 + } + pub fn clear_error() -> Weight { + 1_000_000_000 + } + pub fn claim_asset(_assets: &crate::MultiAssets) -> Weight { + 1_000_000_000 + } + pub fn trap(_code: &u64) -> Weight { + 1_000_000_000 + } + + pub fn subscribe_version() -> Weight { + 1_000_000_000 + } + + pub fn unsubscribe_version() -> Weight { + 1_000_000_000 + } + + pub fn clear_origin() -> Weight { + 1_000_000_000 + } + + pub fn descend_origin(_who: &crate::InteriorMultiLocation) -> Weight { + 1_000_000_000 + } + + pub fn initiate_reserve_withdraw() -> Weight { + 1_000_000_000 + } + + pub fn report_error() -> Weight { + 1_000_000_000 + } +} diff --git a/xcm/Cargo.toml b/xcm/Cargo.toml index 8d60407ea8cc..972d28bd1863 100644 --- a/xcm/Cargo.toml +++ b/xcm/Cargo.toml @@ -16,6 +16,7 @@ xcm-procedural = { path = "procedural" } [features] default = ["std"] wasm-api = [] +runtime-benchmarks = [] std = [ "parity-scale-codec/std", "scale-info/std", diff --git a/xcm/pallet-xcm-benchmarks/Cargo.toml b/xcm/pallet-xcm-benchmarks/Cargo.toml new file mode 100644 index 000000000000..f310bd0510a4 --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "pallet-xcm-benchmarks" +authors = ["Parity Technologies "] +edition = "2018" +version = "0.9.8" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +frame-support = { version = "4.0.0-dev", default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" } +frame-system = { version = "4.0.0-dev", default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" } +sp-runtime = { version = "4.0.0-dev", default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" } +sp-std = { version = "4.0.0-dev", default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" } +xcm-executor = { path = "../xcm-executor", default-features = false, features = ["runtime-benchmarks"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, branch = "master", git = "https://github.com/paritytech/substrate" } +xcm = { path = "..", default-features = false, features = ["runtime-benchmarks"] } +log = "0.4.0" + +[dev-dependencies] +pallet-balances = { version = "4.0.0-dev", branch = "master", git = "https://github.com/paritytech/substrate" } +pallet-assets = { version = "4.0.0-dev", branch = "master", git = "https://github.com/paritytech/substrate" } +sp-core = { version = "4.0.0-dev", branch = "master", git = "https://github.com/paritytech/substrate" } +sp-io = { version = "4.0.0-dev", branch = "master", git = "https://github.com/paritytech/substrate" } +sp-tracing = { version = "4.0.0-dev", branch = "master", git = "https://github.com/paritytech/substrate" } +xcm-builder = { path = "../xcm-builder" } +xcm = { path = ".." } +# temp +pallet-xcm = { path = "../pallet-xcm" } +polkadot-runtime-common = { path = "../../runtime/common" } +# westend-runtime = { path = "../../runtime/westend", features = ["runtime-benchmarks"] } +polkadot-primitives = { path = "../../primitives" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std" +] diff --git a/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs new file mode 100644 index 000000000000..b93184e0455d --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -0,0 +1,219 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +use super::*; +use crate::{account_and_location, new_executor, worst_case_holding, AssetTransactorOf, XcmCallOf}; +use frame_benchmarking::{ + benchmarks_instance_pallet, impl_benchmark_test_suite, BenchmarkError, BenchmarkResult, +}; +use frame_support::{pallet_prelude::Get, traits::fungible::Inspect}; +use sp_runtime::traits::Zero; +use sp_std::{convert::TryInto, prelude::*, vec}; +use xcm::latest::prelude::*; +use xcm_executor::traits::{Convert, TransactAsset}; + +benchmarks_instance_pallet! { + where_clause { where + < + < + T::TransactAsset + as + Inspect + >::Balance + as + TryInto + >::Error: sp_std::fmt::Debug, + } + + withdraw_asset { + let (sender_account, sender_location) = account_and_location::(1); + let worst_case_holding = worst_case_holding(); + let asset = T::get_multi_asset(); + + >::deposit_asset(&asset, &sender_location).unwrap(); + // check the assets of origin. + assert!(!T::TransactAsset::balance(&sender_account).is_zero()); + + let mut executor = new_executor::(sender_location); + executor.holding = worst_case_holding; + let instruction = Instruction::>::WithdrawAsset(vec![asset.clone()].into()); + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm)?; + } verify { + // check one of the assets of origin. + assert!(T::TransactAsset::balance(&sender_account).is_zero()); + assert!(executor.holding.ensure_contains(&vec![asset].into()).is_ok()); + } + + transfer_asset { + let (sender_account, sender_location) = account_and_location::(1); + let asset = T::get_multi_asset(); + let assets: MultiAssets = vec![ asset.clone() ].into(); + // this xcm doesn't use holding + + let dest_location = T::valid_destination()?; + let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap(); + + >::deposit_asset(&asset, &sender_location).unwrap(); + assert!(T::TransactAsset::balance(&dest_account).is_zero()); + + let mut executor = new_executor::(sender_location); + let instruction = Instruction::TransferAsset { assets, beneficiary: dest_location }; + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm)?; + } verify { + assert!(T::TransactAsset::balance(&sender_account).is_zero()); + assert!(!T::TransactAsset::balance(&dest_account).is_zero()); + } + + transfer_reserve_asset { + let (sender_account, sender_location) = account_and_location::(1); + let dest_location = T::valid_destination()?; + let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap(); + + let asset = T::get_multi_asset(); + >::deposit_asset(&asset, &sender_location).unwrap(); + let assets: MultiAssets = vec![ asset ].into(); + assert!(T::TransactAsset::balance(&dest_account).is_zero()); + + let mut executor = new_executor::(sender_location); + let instruction = Instruction::TransferReserveAsset { + assets, + dest: dest_location, + xcm: Xcm::new() + }; + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm)?; + } verify { + assert!(T::TransactAsset::balance(&sender_account).is_zero()); + assert!(!T::TransactAsset::balance(&dest_account).is_zero()); + // TODO: Check sender queue is not empty. + } + + receive_teleported_asset { + // If there is no trusted teleporter, then we skip this benchmark. + let (trusted_teleporter, teleportable_asset) = T::TrustedTeleporter::get().ok_or( + BenchmarkError::Override( + BenchmarkResult::from_weight(T::BlockWeights::get().max_block) + ) + )?; + + let assets: MultiAssets = vec![ teleportable_asset ].into(); + + let mut executor = new_executor::(trusted_teleporter); + let instruction = Instruction::ReceiveTeleportedAsset(assets.clone()); + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm).map_err(|_| { + BenchmarkError::Override( + BenchmarkResult::from_weight(T::BlockWeights::get().max_block) + ) + })?; + } verify { + assert!(executor.holding.ensure_contains(&assets).is_ok()); + } + + deposit_asset { + let asset = T::get_multi_asset(); + let mut holding = worst_case_holding(); + + // Add our asset to the holding. + holding.subsume(asset.clone()); + + // our dest must have no balance initially. + let dest_location = T::valid_destination()?; + let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap(); + assert!(T::TransactAsset::balance(&dest_account).is_zero()); + + let mut executor = new_executor::(Default::default()); + executor.holding = holding; + let instruction = Instruction::>::DepositAsset { + assets: asset.into(), + max_assets: 1, + beneficiary: dest_location, + }; + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm)?; + } verify { + // dest should have received some asset. + assert!(!T::TransactAsset::balance(&dest_account).is_zero()) + } + + deposit_reserve_asset { + let asset = T::get_multi_asset(); + let mut holding = worst_case_holding(); + + // Add our asset to the holding. + holding.subsume(asset.clone()); + + // our dest must have no balance initially. + let dest_location = T::valid_destination()?; + let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap(); + assert!(T::TransactAsset::balance(&dest_account).is_zero()); + + let mut executor = new_executor::(Default::default()); + executor.holding = holding; + let instruction = Instruction::>::DepositReserveAsset { + assets: asset.into(), + max_assets: 1, + dest: dest_location, + xcm: Xcm::new(), + }; + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm)?; + } verify { + // dest should have received some asset. + assert!(!T::TransactAsset::balance(&dest_account).is_zero()) + } + + initiate_teleport { + let asset = T::get_multi_asset(); + let mut holding = worst_case_holding(); + + // Add our asset to the holding. + holding.subsume(asset.clone()); + + // Checked account starts at zero + assert!(T::CheckedAccount::get().map_or(true, |c| T::TransactAsset::balance(&c).is_zero())); + + let mut executor = new_executor::(Default::default()); + executor.holding = holding; + let instruction = Instruction::>::InitiateTeleport { + assets: asset.into(), + dest: T::valid_destination()?, + xcm: Xcm::new(), + }; + let xcm = Xcm(vec![instruction]); + }: { + executor.execute(xcm)?; + } verify { + if let Some(checked_account) = T::CheckedAccount::get() { + // teleport checked account should have received some asset. + assert!(!T::TransactAsset::balance(&checked_account).is_zero()); + } + } +} + +impl_benchmark_test_suite!( + Pallet, + crate::fungible::mock::new_test_ext(), + crate::fungible::mock::Test +); diff --git a/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs new file mode 100644 index 000000000000..8666dc6caa4d --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -0,0 +1,180 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +//! A mock runtime for XCM benchmarking. + +use crate::{fungible as xcm_balances_benchmark, mock::*}; +use frame_support::{parameter_types, traits::Everything}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; +use xcm::latest::prelude::*; +use xcm_builder::AllowUnpaidExecutionFrom; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// For testing the pallet, we construct a mock runtime. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + XcmBalancesBenchmark: xcm_balances_benchmark::{Pallet}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1024); +} +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = Call; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 7; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = u64; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +parameter_types! { + pub const AssetDeposit: u64 = 100 * ExistentialDeposit::get(); + pub const ApprovalDeposit: u64 = 1 * ExistentialDeposit::get(); + pub const StringLimit: u32 = 50; + pub const MetadataDepositBase: u64 = 10 * ExistentialDeposit::get(); + pub const MetadataDepositPerByte: u64 = 1 * ExistentialDeposit::get(); +} + +pub struct MatchAnyFungible; +impl xcm_executor::traits::MatchesFungible for MatchAnyFungible { + fn matches_fungible(m: &MultiAsset) -> Option { + use sp_runtime::traits::SaturatedConversion; + match m { + MultiAsset { fun: Fungible(amount), .. } => Some((*amount).saturated_into::()), + _ => None, + } + } +} + +// Use balances as the asset transactor. +pub type AssetTransactor = xcm_builder::CurrencyAdapter< + Balances, + MatchAnyFungible, + AccountIdConverter, + u64, + CheckedAccount, +>; + +parameter_types! { + /// Maximum number of instructions in a single XCM fragment. A sanity check against weight + /// calculations getting too crazy. + pub const MaxInstructions: u32 = 100; +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type Call = Call; + type XcmSender = DevNull; + type AssetTransactor = AssetTransactor; + type OriginConverter = (); + type IsReserve = (); + type IsTeleporter = (); + type LocationInverter = xcm_builder::LocationInverter; + type Barrier = AllowUnpaidExecutionFrom; + type Weigher = xcm_builder::FixedWeightBounds; + type Trader = xcm_builder::FixedRateOfFungible; + type ResponseHandler = DevNull; + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); +} + +impl crate::Config for Test { + type XcmConfig = XcmConfig; + type AccountIdConverter = AccountIdConverter; + fn valid_destination() -> Result { + let valid_destination: MultiLocation = + X1(AccountId32 { network: NetworkId::Any, id: [0u8; 32] }).into(); + + Ok(valid_destination) + } +} + +parameter_types! { + pub const CheckedAccount: Option = Some(100); + pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some(( + X1(OnlyChild).into(), + MultiAsset { id: Concrete(Here.into()), fun: Fungible(100) }, + )); +} + +impl xcm_balances_benchmark::Config for Test { + type TransactAsset = Balances; + type CheckedAccount = CheckedAccount; + type TrustedTeleporter = TrustedTeleporter; + + fn get_multi_asset() -> MultiAsset { + let amount = + >::minimum_balance() as u128; + MultiAsset { id: Concrete(Here.into()), fun: Fungible(amount) } + } +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = GenesisConfig { ..Default::default() }.build_storage().unwrap(); + sp_tracing::try_init_simple(); + t.into() +} diff --git a/xcm/pallet-xcm-benchmarks/src/fungible/mod.rs b/xcm/pallet-xcm-benchmarks/src/fungible/mod.rs new file mode 100644 index 000000000000..e5062c310494 --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/src/fungible/mod.rs @@ -0,0 +1,47 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +// Benchmarking for the `AssetTransactor` trait via `Fungible`. + +pub use pallet::*; + +pub mod benchmarking; +#[cfg(test)] +mod mock; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::Get; + #[pallet::config] + pub trait Config: frame_system::Config + crate::Config { + /// The type of `fungible` that is being used under the hood. + /// + /// This is useful for testing and checking. + type TransactAsset: frame_support::traits::fungible::Mutate; + + /// The account used to check assets being teleported. + type CheckedAccount: Get>; + + /// A trusted location which we allow teleports from, and the asset we allow to teleport. + type TrustedTeleporter: Get>; + + /// Give me a fungible asset that your asset transactor is going to accept. + fn get_multi_asset() -> xcm::latest::MultiAsset; + } + + #[pallet::pallet] + pub struct Pallet(_); +} diff --git a/xcm/pallet-xcm-benchmarks/src/lib.rs b/xcm/pallet-xcm-benchmarks/src/lib.rs new file mode 100644 index 000000000000..cfbb3a478f67 --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -0,0 +1,108 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +//! Pallet that serves no other purpose than benchmarking raw messages [`Xcm`]. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Encode; +use frame_benchmarking::account; +use sp_std::prelude::*; +use xcm::latest::prelude::*; +use xcm_executor::{traits::Convert, Assets}; + +pub mod fungible; + +#[cfg(test)] +mod mock; + +/// A base trait for all individual pallets +pub trait Config: frame_system::Config { + /// The XCM configurations. + /// + /// These might affect the execution of XCM messages, such as defining how the + /// `TransactAsset` is implemented. + type XcmConfig: xcm_executor::Config; + + /// A converter between a multi-location to a sovereign account. + type AccountIdConverter: Convert; + + /// Does any necessary setup to create a valid destination for XCM messages. + /// Returns that destination's multi-location to be used in benchmarks. + fn valid_destination() -> Result; +} + +const SEED: u32 = 0; + +/// The XCM executor to use for doing stuff. +pub type ExecutorOf = xcm_executor::XcmExecutor<::XcmConfig>; +/// The overarching call type. +pub type OverArchingCallOf = ::Call; +/// The asset transactor of our executor +pub type AssetTransactorOf = <::XcmConfig as xcm_executor::Config>::AssetTransactor; +/// The call type of executor's config. Should eventually resolve to the same overarching call type. +pub type XcmCallOf = <::XcmConfig as xcm_executor::Config>::Call; + +/// The worst case number of assets in the holding. +const HOLDING_FUNGIBLES: u32 = 99; +const HOLDING_NON_FUNGIBLES: u32 = 99; + +pub fn worst_case_holding() -> Assets { + let fungibles_amount: u128 = 100; // TODO probably update + (0..HOLDING_FUNGIBLES) + .map(|i| { + MultiAsset { + id: Concrete(GeneralIndex(i as u128).into()), + fun: Fungible(fungibles_amount * i as u128), + } + .into() + }) + .chain(core::iter::once(MultiAsset { id: Concrete(Here.into()), fun: Fungible(u128::MAX) })) + .chain((0..HOLDING_NON_FUNGIBLES).map(|i| MultiAsset { + id: Concrete(GeneralIndex(i as u128).into()), + fun: NonFungible(asset_instance_from(i)), + })) + .collect::>() + .into() +} + +pub fn asset_instance_from(x: u32) -> AssetInstance { + let bytes = x.encode(); + let mut instance = [0u8; 4]; + instance.copy_from_slice(&bytes); + AssetInstance::Array4(instance) +} + +pub fn new_executor(origin: MultiLocation) -> ExecutorOf { + ExecutorOf::::new(origin) +} + +/// Build a multi-location from an account id. +fn account_id_junction(index: u32) -> Junction { + let account: T::AccountId = account("account", index, SEED); + let mut encoded = account.encode(); + encoded.resize(32, 0u8); + let mut id = [0u8; 32]; + id.copy_from_slice(&encoded); + Junction::AccountId32 { network: NetworkId::Any, id } +} + +pub fn account_and_location(index: u32) -> (T::AccountId, MultiLocation) { + let location: MultiLocation = account_id_junction::(index).into(); + let account = T::AccountIdConverter::convert(location.clone()).unwrap(); + + (account, location) +} diff --git a/xcm/pallet-xcm-benchmarks/src/mock.rs b/xcm/pallet-xcm-benchmarks/src/mock.rs new file mode 100644 index 000000000000..2b1cb31f1580 --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/src/mock.rs @@ -0,0 +1,64 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +use crate::*; +use frame_support::{parameter_types, weights::Weight}; +use xcm_executor::traits::FilterAssetLocation; + +// An xcm sender/receiver akin to > /dev/null +pub struct DevNull; +impl xcm::opaque::latest::SendXcm for DevNull { + fn send_xcm(_: MultiLocation, _: Xcm<()>) -> SendResult { + Ok(()) + } +} + +impl xcm_executor::traits::OnResponse for DevNull { + fn expecting_response(_: &MultiLocation, _: u64) -> bool { + false + } + fn on_response(_: &MultiLocation, _: u64, _: Response, _: Weight) -> Weight { + 0 + } +} + +pub struct AccountIdConverter; +impl xcm_executor::traits::Convert for AccountIdConverter { + fn convert(ml: MultiLocation) -> Result { + match ml { + MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { id, .. }) } => + Ok(::decode(&mut &*id.to_vec()).unwrap()), + _ => Err(ml), + } + } + + fn reverse(acc: u64) -> Result { + Err(acc) + } +} + +parameter_types! { + pub Ancestry: MultiLocation = Junction::Parachain(101).into(); + pub UnitWeightCost: Weight = 10; + pub WeightPrice: (AssetId, u128) = (Concrete(Here.into()), 1_000_000); +} + +pub struct AllAssetLocationsPass; +impl FilterAssetLocation for AllAssetLocationsPass { + fn filter_asset_location(_: &MultiAsset, _: &MultiLocation) -> bool { + true + } +} diff --git a/xcm/pallet-xcm-benchmarks/template.hbs b/xcm/pallet-xcm-benchmarks/template.hbs new file mode 100644 index 000000000000..357fa7456aa0 --- /dev/null +++ b/xcm/pallet-xcm-benchmarks/template.hbs @@ -0,0 +1,66 @@ +// Copyright 2017-2021 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 . + +//! Autogenerated weights for `{{pallet}}` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: {{cmd.repeat}}, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} + +// Executed Command: +{{#each args as |arg|~}} +// {{arg}} +{{/each}} + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weights for `{{pallet}}`. +pub struct WeightInfo(PhantomData); +impl WeightInfo { + {{~#each benchmarks as |benchmark|}} + {{~#each benchmark.comments as |comment|}} + // {{comment}} + {{~/each}} + pub(crate) fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + ({{underscore benchmark.base_weight}} as Weight) + {{~#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) + {{~/each}} + {{~#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) + {{~/if}} + {{~#each benchmark.component_reads as |cr|}} + .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) + {{~/each}} + {{~#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) + {{~/if}} + {{~#each benchmark.component_writes as |cw|}} + .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) + {{~/each}} + } + {{~/each}} +} diff --git a/xcm/xcm-builder/src/lib.rs b/xcm/xcm-builder/src/lib.rs index e2caff56bf36..72bb8b61c0ff 100644 --- a/xcm/xcm-builder/src/lib.rs +++ b/xcm/xcm-builder/src/lib.rs @@ -57,7 +57,9 @@ pub use fungibles_adapter::{ mod weight; #[allow(deprecated)] pub use weight::FixedRateOfConcreteFungible; -pub use weight::{FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents}; +pub use weight::{ + FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds, +}; mod matches_fungible; pub use matches_fungible::{IsAbstract, IsConcrete}; diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 3ec684f85852..1e84a42e2ada 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -64,7 +64,7 @@ impl, C: Decode + GetDispatchInfo, M> FixedWeightBounds } } -struct WeightInfoBounds(PhantomData<(W, C, M)>); +pub struct WeightInfoBounds(PhantomData<(W, C, M)>); impl WeightBounds for WeightInfoBounds where W: XcmWeightInfo, diff --git a/xcm/xcm-executor/Cargo.toml b/xcm/xcm-executor/Cargo.toml index b3e6b6eb9045..d4668d0165d6 100644 --- a/xcm/xcm-executor/Cargo.toml +++ b/xcm/xcm-executor/Cargo.toml @@ -16,9 +16,13 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } log = { version = "0.4.14", default-features = false } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false, optional = true } [features] default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking", +] std = [ "parity-scale-codec/std", "xcm/std", diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index c7049a3a6412..93a29d7af880 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -211,7 +211,7 @@ impl Assets { /// Returns an error unless all `assets` are contained in `self`. In the case of an error, the first asset in /// `assets` which is not wholly in `self` is returned. - fn ensure_contains(&self, assets: &MultiAssets) -> Result<(), TakeError> { + pub fn ensure_contains(&self, assets: &MultiAssets) -> Result<(), TakeError> { for asset in assets.inner().iter() { match asset { MultiAsset { fun: Fungible(ref amount), ref id } => {