diff --git a/Cargo.lock b/Cargo.lock index ec8b159f..718bfc71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12250,12 +12250,29 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", + "trappist-runtime-benchmarks", "xcm", "xcm-builder", "xcm-executor", "xcm-primitives", ] +[[package]] +name = "trappist-runtime-benchmarks" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", + "xcm", + "xcm-executor", +] + [[package]] name = "trappist-service" version = "1.0.0" diff --git a/pallets/asset-registry/src/lib.rs b/pallets/asset-registry/src/lib.rs index d5b89ded..7cc3ba78 100644 --- a/pallets/asset-registry/src/lib.rs +++ b/pallets/asset-registry/src/lib.rs @@ -137,7 +137,7 @@ pub mod pallet { AssetIdMultiLocation::::get(asset_id) } - fn get_asset_id(asset_type: MultiLocation) -> Option> { + fn get_asset_id(asset_type: &MultiLocation) -> Option> { AssetMultiLocationId::::get(asset_type) } } diff --git a/pallets/benchmarks/Cargo.toml b/pallets/benchmarks/Cargo.toml new file mode 100644 index 00000000..09defed2 --- /dev/null +++ b/pallets/benchmarks/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "trappist-runtime-benchmarks" +version = "0.1.0" +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", ] } +scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.37" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.37" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } + +xcm = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.37" } +xcm-executor = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.37" } + +[dev-dependencies] +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", + "xcm-executor/std" +] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] \ No newline at end of file diff --git a/pallets/benchmarks/src/benchmarking.rs b/pallets/benchmarks/src/benchmarking.rs new file mode 100644 index 00000000..5da6afb4 --- /dev/null +++ b/pallets/benchmarks/src/benchmarking.rs @@ -0,0 +1,33 @@ +use frame_benchmarking::benchmarks; +use sp_runtime::SaturatedConversion; +use xcm::prelude::AssetId as XcmAssetId; + +use crate::*; + +benchmarks! { + drop_assets_fungible { + let origin = MultiLocation::default(); + let asset_id = 1; + let location = Parachain(asset_id).into(); + T::register_asset(asset_id.into(), location.clone()); + let asset = MultiAsset { id: XcmAssetId::Concrete(location), fun: Fungibility::Fungible(100) }; + } : { + T::DropAssets::drop_assets(&origin, asset.into()); + } + + drop_assets_native { + let origin = MultiLocation::default(); + let location = MultiLocation { parents: 0, interior: Here }; + let amount = T::ExistentialDeposit::get().saturated_into(); + let asset = MultiAsset { id: XcmAssetId::Concrete(location), fun: Fungibility::Fungible(amount) }; + } : { + T::DropAssets::drop_assets(&origin, asset.into()); + } + + drop_assets_default { + let origin = MultiLocation::default(); + let asset = MultiAsset { id: XcmAssetId::Abstract(Default::default()), fun: Fungibility::Fungible(0) }; + } : { + T::DropAssets::drop_assets(&origin, asset.into()); + } +} diff --git a/pallets/benchmarks/src/lib.rs b/pallets/benchmarks/src/lib.rs new file mode 100644 index 00000000..34427034 --- /dev/null +++ b/pallets/benchmarks/src/lib.rs @@ -0,0 +1,43 @@ +//! Pallet for benchmarking. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use frame_support::{pallet_prelude::*, traits::tokens::AssetId}; +use sp_runtime::traits::AtLeast32BitUnsigned; +use xcm::prelude::*; +use xcm_executor::traits::DropAssets; + +pub use pallet::*; +pub use weights::*; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; +pub mod weights; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Identifier for the class of asset. + type AssetId: AssetId + From; + + /// The balance of an account. + type Balance: Parameter + Member + AtLeast32BitUnsigned + Codec + TypeInfo; + + /// The minimum amount required to keep an account open. + #[pallet::constant] + type ExistentialDeposit: Get; + + /// Handler for when some non-empty `Assets` value should be dropped. + type DropAssets: DropAssets; + + /// Handler to register an asset. + fn register_asset(asset_id: Self::AssetId, location: MultiLocation); + } + + #[pallet::pallet] + pub struct Pallet(_); +} diff --git a/pallets/benchmarks/src/weights.rs b/pallets/benchmarks/src/weights.rs new file mode 100644 index 00000000..411eef76 --- /dev/null +++ b/pallets/benchmarks/src/weights.rs @@ -0,0 +1,7 @@ +use frame_support::weights::Weight; + +pub trait WeightInfo { + fn drop_assets_fungible() -> Weight; + fn drop_assets_native() -> Weight; + fn drop_assets_default() -> Weight; +} diff --git a/primitives/xcm/src/lib.rs b/primitives/xcm/src/lib.rs index fc625775..88a11361 100644 --- a/primitives/xcm/src/lib.rs +++ b/primitives/xcm/src/lib.rs @@ -1,10 +1,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ - sp_runtime::SaturatedConversion, + sp_runtime::{SaturatedConversion, Saturating}, traits::{fungibles::Inspect, Currency}, }; -use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; +use sp_std::{borrow::Borrow, marker::PhantomData}; use xcm::latest::{ AssetId::Concrete, Fungibility::Fungible, Junctions::Here, MultiAsset, MultiLocation, }; @@ -23,7 +23,7 @@ where AssetIdInfoGetter: AssetMultiLocationGetter, { fn convert_ref(asset_multi_location: impl Borrow) -> Result { - AssetIdInfoGetter::get_asset_id(asset_multi_location.borrow().clone()).ok_or(()) + AssetIdInfoGetter::get_asset_id(asset_multi_location.borrow()).ok_or(()) } fn reverse_ref(asset_id: impl Borrow) -> Result { @@ -33,7 +33,7 @@ where pub trait AssetMultiLocationGetter { fn get_asset_multi_location(asset_id: AssetId) -> Option; - fn get_asset_id(asset_multi_location: MultiLocation) -> Option; + fn get_asset_id(asset_multi_location: &MultiLocation) -> Option; } pub struct ConvertedRegisteredAssetId( @@ -59,15 +59,34 @@ impl< } } +pub trait DropAssetsWeigher { + fn fungible() -> u64; + fn native() -> u64; + fn default() -> u64; +} + pub struct TrappistDropAssets< AssetId, AssetIdInfoGetter, AssetsPallet, BalancesPallet, XcmPallet, - AccoundId, ->(PhantomData<(AssetId, AssetIdInfoGetter, AssetsPallet, BalancesPallet, XcmPallet, AccoundId)>); -impl DropAssets + AccountId, + Weigher, +>( + PhantomData<( + AssetId, + AssetIdInfoGetter, + AssetsPallet, + BalancesPallet, + XcmPallet, + AccountId, + Weigher, + )>, +); + +impl + DropAssets for TrappistDropAssets< AssetId, AssetIdInfoGetter, @@ -75,52 +94,52 @@ impl where - AssetId: Clone, AssetIdInfoGetter: AssetMultiLocationGetter, AssetsPallet: Inspect, BalancesPallet: Currency, XcmPallet: DropAssets, + Weigher: DropAssetsWeigher, { // assets are whatever the Holding Register had when XCVM halts - fn drop_assets(origin: &MultiLocation, assets: Assets) -> u64 { - let multi_assets: Vec = assets.into(); - let mut trap: Vec = Vec::new(); + fn drop_assets(origin: &MultiLocation, mut assets: Assets) -> u64 { + const NATIVE_LOCATION: MultiLocation = MultiLocation { parents: 0, interior: Here }; - for asset in multi_assets { - if let MultiAsset { id: Concrete(location), fun: Fungible(amount) } = asset.clone() { - // is location a fungible on AssetRegistry? - if let Some(asset_id) = AssetIdInfoGetter::get_asset_id(location.clone()) { - let min_balance = AssetsPallet::minimum_balance(asset_id); + let mut weight = { + assets.non_fungible.clear(); + Weigher::default() + }; - // only trap if amount ≥ min_balance - // do nothing otherwise (asset is lost) - if min_balance <= amount.saturated_into::() { - trap.push(asset); - } + assets.fungible.retain(|id, &mut amount| { + if let Concrete(location) = id { + match AssetIdInfoGetter::get_asset_id(location) { + Some(asset_id) => { + weight.saturating_accrue(Weigher::fungible()); - // is location the native token? - } else if location == (MultiLocation { parents: 0, interior: Here }) { - let min_balance = BalancesPallet::minimum_balance(); + // only trap if amount ≥ min_balance + // do nothing otherwise (asset is lost) + amount.saturated_into::() >= + AssetsPallet::minimum_balance(asset_id) + }, + None => { + weight.saturating_accrue(Weigher::native()); - // only trap if amount ≥ min_balance - // do nothing otherwise (asset is lost) - if min_balance <= amount.saturated_into::() { - trap.push(asset); - } + // only trap if native token and amount ≥ min_balance + // do nothing otherwise (asset is lost) + *location == NATIVE_LOCATION && + amount.saturated_into::() >= + BalancesPallet::minimum_balance() + }, } + } else { + weight.saturating_accrue(Weigher::default()); + false } - } - - // TODO: put real weight of execution up until this point here - let mut weight = 0; - - if !trap.is_empty() { - // we have filtered out non-compliant assets - // insert valid assets into the asset trap implemented by XcmPallet - weight += XcmPallet::drop_assets(origin, trap.into()); - } + }); - weight + // we have filtered out non-compliant assets + // insert valid assets into the asset trap implemented by XcmPallet + weight.saturating_add(XcmPallet::drop_assets(origin, assets)) } } diff --git a/runtime/trappist/Cargo.toml b/runtime/trappist/Cargo.toml index 47ab5b42..796d1c1e 100644 --- a/runtime/trappist/Cargo.toml +++ b/runtime/trappist/Cargo.toml @@ -104,7 +104,8 @@ pallet-dex-rpc-runtime-api = { version = "0.0.1", git = "https://github.com/pari pallet-chess = { git = "https://github.com/SubstrateChess/pallet-chess.git", default-features = false, branch = "polkadot-v0.9.37" } # Trappist Pallets -pallet-asset-registry = { version = "0.0.1", default-features = false, path = "../../pallets/asset-registry" } +pallet-asset-registry = { default-features = false, path = "../../pallets/asset-registry" } +trappist-runtime-benchmarks = { default-features = false, path = "../../pallets/benchmarks" } [features] default = ["std"] @@ -183,6 +184,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-asset-registry/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "trappist-runtime-benchmarks/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-contracts/runtime-benchmarks", diff --git a/runtime/trappist/src/lib.rs b/runtime/trappist/src/lib.rs index 3e2be6ff..826efc49 100644 --- a/runtime/trappist/src/lib.rs +++ b/runtime/trappist/src/lib.rs @@ -17,31 +17,11 @@ #![cfg_attr(not(feature = "std"), no_std)] #![recursion_limit = "256"] -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -pub mod constants; -mod contracts; -pub mod impls; -pub mod xcm_config; +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, ConstU8, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Percent, Permill, -}; - -use sp_std::prelude::*; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use constants::{currency::*, fee::WeightToFee}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -60,25 +40,44 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, EnsureSigned, }; - +// Polkadot imports +use pallet_xcm::{EnsureXcm, IsMajorityOfBody}; pub use parachains_common as common; pub use parachains_common::{ impls::AssetsToBlockAuthor, opaque, AccountId, AssetId, AuraId, Balance, BlockNumber, Hash, Header, Index, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; +use polkadot_runtime_common::{prod_or_fast, BlockHashCount, SlowAdjustingFeeUpdate}; +use sp_api::impl_runtime_apis; +use sp_core::{crypto::KeyTypeId, ConstU8, OpaqueMetadata}; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, Percent, Permill, +}; +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; +use xcm::latest::prelude::BodyId; +use constants::{currency::*, fee::WeightToFee}; use impls::DealWithFees; - use xcm_config::{CollatorSelectionUpdateOrigin, RelayLocation}; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -// Polkadot imports -use pallet_xcm::{EnsureXcm, IsMajorityOfBody}; -use polkadot_runtime_common::{prod_or_fast, BlockHashCount, SlowAdjustingFeeUpdate}; -use xcm::latest::prelude::BodyId; +pub mod constants; +mod contracts; +pub mod impls; +mod weights; +pub mod xcm_config; pub const MICROUNIT: Balance = 1_000_000; @@ -689,15 +688,12 @@ construct_runtime!( } ); -#[cfg(feature = "runtime-benchmarks")] -#[macro_use] -extern crate frame_benchmarking; - #[cfg(feature = "runtime-benchmarks")] mod benches { define_benchmarks!( [frame_system, SystemBench::] [pallet_asset_registry, AssetRegistry] + [trappist_runtime_benchmarks, trappist_runtime_benchmarks::Pallet::] [pallet_balances, Balances] [pallet_session, SessionBench::] [pallet_timestamp, Timestamp] @@ -962,6 +958,21 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use xcm_primitives::TrappistDropAssets; + use xcm::prelude::MultiLocation; + use crate::weights::TrappistDropAssetsWeigher; + impl trappist_runtime_benchmarks::Config for Runtime { + type AssetId = AssetId; + type Balance = Balance; + type ExistentialDeposit = ConstU128; + type DropAssets = TrappistDropAssets; + + fn register_asset(asset_id: Self::AssetId, location: MultiLocation) { + pallet_asset_registry::AssetMultiLocationId::::insert(&location, asset_id); + pallet_asset_registry::AssetIdMultiLocation::::insert(asset_id, location); + } + } + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), diff --git a/runtime/trappist/src/weights/mod.rs b/runtime/trappist/src/weights/mod.rs new file mode 100644 index 00000000..878e0679 --- /dev/null +++ b/runtime/trappist/src/weights/mod.rs @@ -0,0 +1,21 @@ +use ::trappist_runtime_benchmarks::WeightInfo; +use xcm_primitives::DropAssetsWeigher; + +use crate::Runtime; + +mod trappist_runtime_benchmarks; + +pub struct TrappistDropAssetsWeigher(); +impl DropAssetsWeigher for TrappistDropAssetsWeigher { + fn fungible() -> u64 { + trappist_runtime_benchmarks::WeightInfo::::drop_assets_fungible().ref_time() + } + + fn native() -> u64 { + trappist_runtime_benchmarks::WeightInfo::::drop_assets_native().ref_time() + } + + fn default() -> u64 { + trappist_runtime_benchmarks::WeightInfo::::drop_assets_default().ref_time() + } +} diff --git a/runtime/trappist/src/weights/trappist_runtime_benchmarks.rs b/runtime/trappist/src/weights/trappist_runtime_benchmarks.rs new file mode 100644 index 00000000..c6b0661c --- /dev/null +++ b/runtime/trappist/src/weights/trappist_runtime_benchmarks.rs @@ -0,0 +1,53 @@ + +//! Autogenerated weights for `trappist_runtime_benchmarks` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-05-08, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `kalan-x1x`, CPU: `12th Gen Intel(R) Core(TM) i7-12800H` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/trappist-collator +// benchmark +// pallet +// --chain +// dev +// --pallet +// trappist_runtime_benchmarks +// --extrinsic +// * +// --steps +// 20 +// --repeat +// 10 +// --output +// runtime/trappist/src/weights/trappist_runtime_benchmarks.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for `trappist_runtime_benchmarks`. +pub struct WeightInfo(PhantomData); +impl trappist_runtime_benchmarks::WeightInfo for WeightInfo { + // Storage: AssetRegistry AssetMultiLocationId (r:1 w:0) + // Storage: Assets Asset (r:1 w:0) + fn drop_assets_fungible() -> Weight { + // Minimum execution time: 4_589 nanoseconds. + Weight::from_ref_time(4_898_000) + .saturating_add(T::DbWeight::get().reads(2)) + } + // Storage: AssetRegistry AssetMultiLocationId (r:1 w:0) + fn drop_assets_native() -> Weight { + // Minimum execution time: 2_157 nanoseconds. + Weight::from_ref_time(2_314_000) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn drop_assets_default() -> Weight { + // Minimum execution time: 130 nanoseconds. + Weight::from_ref_time(154_000) + } +} diff --git a/runtime/trappist/src/xcm_config.rs b/runtime/trappist/src/xcm_config.rs index 7033c600..ab8c30ef 100644 --- a/runtime/trappist/src/xcm_config.rs +++ b/runtime/trappist/src/xcm_config.rs @@ -13,7 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{constants::fee::default_fee_per_second, impls::ToAuthor}; +use crate::{ + constants::fee::default_fee_per_second, impls::ToAuthor, weights::TrappistDropAssetsWeigher, +}; use super::{ AccountId, AssetRegistry, Assets, Balance, Balances, ParachainInfo, ParachainSystem, @@ -262,8 +264,15 @@ impl xcm_executor::Config for XcmConfig { UsingComponents>, ); type ResponseHandler = PolkadotXcm; - type AssetTrap = - TrappistDropAssets; + type AssetTrap = TrappistDropAssets< + AssetId, + AssetRegistry, + Assets, + Balances, + PolkadotXcm, + AccountId, + TrappistDropAssetsWeigher, + >; type AssetClaims = PolkadotXcm; type SubscriptionService = PolkadotXcm; }