From 8b56b2990e87a3ab3397d32f0101b7e4eaba2706 Mon Sep 17 00:00:00 2001 From: Amar Singh Date: Thu, 31 Oct 2024 09:04:01 -0400 Subject: [PATCH] xcm-transactor on evm (#345) --- evm-template/Cargo.lock | 26 ++- evm-template/Cargo.toml | 1 + evm-template/runtime/Cargo.toml | 4 + evm-template/runtime/src/benchmark.rs | 1 + .../runtime/src/configs/xcm_config.rs | 116 +++++++++++- evm-template/runtime/src/lib.rs | 2 + evm-template/runtime/src/weights/mod.rs | 1 + .../src/weights/pallet_xcm_transactor.rs | 177 ++++++++++++++++++ evm-template/template-fuzzer/src/main.rs | 1 + 9 files changed, 327 insertions(+), 2 deletions(-) create mode 100644 evm-template/runtime/src/weights/pallet_xcm_transactor.rs diff --git a/evm-template/Cargo.lock b/evm-template/Cargo.lock index 3b00375..e0e3066 100644 --- a/evm-template/Cargo.lock +++ b/evm-template/Cargo.lock @@ -3041,6 +3041,7 @@ dependencies = [ "pallet-utility", "pallet-whitelist", "pallet-xcm", + "pallet-xcm-transactor", "pallet-xcm-weight-trader", "parachains-common", "parity-scale-codec", @@ -6704,7 +6705,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.77", @@ -8198,6 +8199,29 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "pallet-xcm-transactor" +version = "0.2.0" +source = "git+https://github.com/OpenZeppelin/moonbeam.git?branch=polkadot-stable2407-1#fab6e72fbaaeaa065ad983556d09d4c0e8755dfa" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "orml-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-primitives", +] + [[package]] name = "pallet-xcm-weight-trader" version = "0.1.0" diff --git a/evm-template/Cargo.toml b/evm-template/Cargo.toml index 87298d8..8c6d31a 100644 --- a/evm-template/Cargo.toml +++ b/evm-template/Cargo.toml @@ -168,6 +168,7 @@ orml-xtokens = { git = "https://github.com/OpenZeppelin/open-runtime-module-libr # Moonbeam pallet-asset-manager = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } pallet-erc20-xcm-bridge = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } +pallet-xcm-transactor = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } pallet-xcm-weight-trader = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } xcm-primitives = { git = "https://github.com/OpenZeppelin/moonbeam.git", branch = "polkadot-stable2407-1", default-features = false } diff --git a/evm-template/runtime/Cargo.toml b/evm-template/runtime/Cargo.toml index 19a4e7a..e23b5e6 100644 --- a/evm-template/runtime/Cargo.toml +++ b/evm-template/runtime/Cargo.toml @@ -103,6 +103,7 @@ orml-xtokens = { workspace = true } # Moonbeam pallet-asset-manager = { workspace = true } pallet-erc20-xcm-bridge = { workspace = true } +pallet-xcm-transactor = { workspace = true } pallet-xcm-weight-trader = { workspace = true } xcm-primitives = { workspace = true } @@ -167,6 +168,7 @@ std = [ "pallet-treasury/std", "pallet-utility/std", "pallet-whitelist/std", + "pallet-xcm-transactor/std", "pallet-xcm-weight-trader/std", "pallet-xcm/std", "parachain-info/std", @@ -224,6 +226,7 @@ runtime-benchmarks = [ "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-whitelist/runtime-benchmarks", + "pallet-xcm-transactor/runtime-benchmarks", "pallet-xcm-weight-trader/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", @@ -270,6 +273,7 @@ try-runtime = [ "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-whitelist/try-runtime", + "pallet-xcm-transactor/try-runtime", "pallet-xcm-weight-trader/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", diff --git a/evm-template/runtime/src/benchmark.rs b/evm-template/runtime/src/benchmark.rs index 77eba86..84cd58a 100644 --- a/evm-template/runtime/src/benchmark.rs +++ b/evm-template/runtime/src/benchmark.rs @@ -21,6 +21,7 @@ frame_benchmarking::define_benchmarks!( [pallet_conviction_voting, ConvictionVoting] [pallet_whitelist, Whitelist] [pallet_referenda, Referenda] + [pallet_xcm_transactor, XcmTransactor] ); use cumulus_primitives_core::{ChannelStatus, GetChannelInfo}; diff --git a/evm-template/runtime/src/configs/xcm_config.rs b/evm-template/runtime/src/configs/xcm_config.rs index b0866d0..090fc9d 100644 --- a/evm-template/runtime/src/configs/xcm_config.rs +++ b/evm-template/runtime/src/configs/xcm_config.rs @@ -13,6 +13,7 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_parachain_primitives::primitives::{self, Sibling}; use scale_info::TypeInfo; use sp_core::H160; +use sp_runtime::Vec; use xcm::latest::prelude::{Assets as XcmAssets, *}; use xcm_builder::{ AccountKey20Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, Case, @@ -27,7 +28,10 @@ use xcm_executor::{ traits::{ConvertLocation, FeeReason, JustTry, TransactAsset}, XcmExecutor, }; -use xcm_primitives::{AbsoluteAndRelativeReserve, AccountIdToLocation, AsAssetType}; +use xcm_primitives::{ + AbsoluteAndRelativeReserve, AccountIdToLocation, AsAssetType, UtilityAvailableCalls, + UtilityEncodeCall, XcmTransact, +}; use crate::{ configs::{ @@ -587,3 +591,113 @@ impl pallet_xcm_weight_trader::Config for Runtime { type WeightToFee = ::WeightToFee; type XcmFeesAccount = TreasuryAccount; } + +// For now we only allow to transact in the relay, although this might change in the future +// Transactors just defines the chains in which we allow transactions to be issued through +// xcm +#[derive(Clone, Eq, Debug, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo)] +pub enum Transactors { + Relay, +} + +// Default for benchmarking +#[cfg(feature = "runtime-benchmarks")] +impl Default for Transactors { + fn default() -> Self { + Transactors::Relay + } +} + +impl TryFrom for Transactors { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0u8 => Ok(Transactors::Relay), + _ => Err(()), + } + } +} + +impl UtilityEncodeCall for Transactors { + fn encode_call(self, call: UtilityAvailableCalls) -> Vec { + match self { + Transactors::Relay => pallet_xcm_transactor::Pallet::::encode_call( + pallet_xcm_transactor::Pallet(sp_std::marker::PhantomData::), + call, + ), + } + } +} + +impl XcmTransact for Transactors { + fn destination(self) -> Location { + match self { + Transactors::Relay => Location::parent(), + } + } +} + +parameter_types! { + pub MaxHrmpRelayFee: Asset = (Location::parent(), 1_000_000_000_000u128).into(); +} + +// implement your own business logic for who can manage and use xcm-transactor +pub type DerivativeAddressRegistrationOrigin = EnsureRoot; +pub type HrmpManipulatorOrigin = EnsureRoot; +pub type HrmpOpenOrigin = EnsureRoot; +pub type SovereignAccountDispatcherOrigin = EnsureRoot; + +impl pallet_xcm_transactor::Config for Runtime { + type AccountIdToLocation = AccountIdToLocation; + type AssetTransactor = AssetTransactors; + type Balance = Balance; + type BaseXcmWeight = BaseXcmWeight; + type CurrencyId = CurrencyId; + type CurrencyIdToLocation = CurrencyIdToLocation>; + type DerivativeAddressRegistrationOrigin = DerivativeAddressRegistrationOrigin; + type HrmpManipulatorOrigin = HrmpManipulatorOrigin; + type HrmpOpenOrigin = HrmpOpenOrigin; + type MaxHrmpFee = xcm_builder::Case; + type ReserveProvider = AbsoluteAndRelativeReserve; + type RuntimeEvent = RuntimeEvent; + type SelfLocation = SelfLocation; + type SovereignAccountDispatcherOrigin = SovereignAccountDispatcherOrigin; + type Transactor = Transactors; + type UniversalLocation = UniversalLocation; + type Weigher = XcmWeigher; + type WeightInfo = weights::pallet_xcm_transactor::WeightInfo; + type XcmSender = XcmRouter; +} + +#[cfg(feature = "runtime-benchmarks")] +mod testing { + use sp_runtime::traits::MaybeEquivalence; + use xcm_builder::WithLatestLocationConverter; + + use super::*; + + /// This From exists for benchmarking purposes. It has the potential side-effect of calling + /// AssetManager::set_asset_type_asset_id() and should NOT be used in any production code. + impl From for CurrencyId { + fn from(location: Location) -> CurrencyId { + use xcm_primitives::AssetTypeGetter; + + // If it does not exist, for benchmarking purposes, we create the association + let asset_id = if let Some(asset_id) = + AsAssetType::::convert_location(&location) + { + asset_id + } else { + let asset_type = AssetType::Xcm( + WithLatestLocationConverter::convert(&location).expect("convert to v3"), + ); + let asset_id: AssetId = asset_type.clone().into(); + AssetManager::set_asset_type_asset_id(asset_type, asset_id); + asset_id + }; + + CurrencyId::ForeignAsset(asset_id) + } + } +} diff --git a/evm-template/runtime/src/lib.rs b/evm-template/runtime/src/lib.rs index 4058eb9..89e4875 100644 --- a/evm-template/runtime/src/lib.rs +++ b/evm-template/runtime/src/lib.rs @@ -266,6 +266,8 @@ mod runtime { pub type XTokens = orml_xtokens; #[runtime::pallet_index(35)] pub type XcmWeightTrader = pallet_xcm_weight_trader; + #[runtime::pallet_index(36)] + pub type XcmTransactor = pallet_xcm_transactor; // EVM #[runtime::pallet_index(40)] diff --git a/evm-template/runtime/src/weights/mod.rs b/evm-template/runtime/src/weights/mod.rs index 44a6f49..8077b9b 100644 --- a/evm-template/runtime/src/weights/mod.rs +++ b/evm-template/runtime/src/weights/mod.rs @@ -40,6 +40,7 @@ pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_whitelist; pub mod pallet_xcm; +pub mod pallet_xcm_transactor; pub mod pallet_xcm_weight_trader; pub mod paritydb_weights; pub mod rocksdb_weights; diff --git a/evm-template/runtime/src/weights/pallet_xcm_transactor.rs b/evm-template/runtime/src/weights/pallet_xcm_transactor.rs new file mode 100644 index 0000000..b8b0a89 --- /dev/null +++ b/evm-template/runtime/src/weights/pallet_xcm_transactor.rs @@ -0,0 +1,177 @@ +//! Autogenerated weights for `pallet_whitelist` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `ip-172-31-15-118`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/parachain-template-node +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=benchmarking/results/results-pallet_whitelist.json +// --pallet=pallet_whitelist +// --chain=dev +// --output=benchmarking/new-benchmarks/pallet_whitelist.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for `pallet_xcm_transactor`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_transactor::WeightInfo for WeightInfo { + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `114` + // Estimated: `3579` + // Minimum execution time: 9_597_000 picoseconds. + Weight::from_parts(9_924_000, 3579) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::IndexToAccount` (r:0 w:1) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_707_000 picoseconds. + Weight::from_parts(5_973_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_118_000 picoseconds. + Weight::from_parts(7_356_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:0 w:1) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_transact_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_362_000 picoseconds. + Weight::from_parts(6_609_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:0 w:1) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn set_fee_per_second() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_443_000 picoseconds. + Weight::from_parts(6_670_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::IndexToAccount` (r:1 w:0) + /// Proof: `XcmTransactor::IndexToAccount` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_derivative() -> Weight { + // Proof Size summary in bytes: + // Measured: `489` + // Estimated: `3954` + // Minimum execution time: 30_458_000 picoseconds. + Weight::from_parts(31_176_000, 3954) + .saturating_add(T::DbWeight::get().reads(7_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetTypeId` (r:1 w:0) + /// Proof: `AssetManager::AssetTypeId` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Assets::Asset` (r:1 w:0) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(174), added: 2649, mode: `MaxEncodedLen`) + fn transact_through_sovereign() -> Weight { + // Proof Size summary in bytes: + // Measured: `423` + // Estimated: `3888` + // Minimum execution time: 22_713_000 picoseconds. + Weight::from_parts(23_258_000, 3888) + .saturating_add(T::DbWeight::get().reads(5_u64)) + } + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transact_through_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `467` + // Estimated: `3932` + // Minimum execution time: 38_097_000 picoseconds. + Weight::from_parts(38_892_000, 3932) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `XcmTransactor::RelayIndices` (r:1 w:0) + /// Proof: `XcmTransactor::RelayIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AssetManager::AssetIdType` (r:1 w:0) + /// Proof: `AssetManager::AssetIdType` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::TransactInfoWithWeightLimit` (r:1 w:0) + /// Proof: `XcmTransactor::TransactInfoWithWeightLimit` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmTransactor::DestinationAssetFeePerSecond` (r:1 w:0) + /// Proof: `XcmTransactor::DestinationAssetFeePerSecond` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn hrmp_manage() -> Weight { + // Proof Size summary in bytes: + // Measured: `471` + // Estimated: `3936` + // Minimum execution time: 40_918_000 picoseconds. + Weight::from_parts(42_238_000, 3936) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} + diff --git a/evm-template/template-fuzzer/src/main.rs b/evm-template/template-fuzzer/src/main.rs index 8c24481..d4d2537 100644 --- a/evm-template/template-fuzzer/src/main.rs +++ b/evm-template/template-fuzzer/src/main.rs @@ -67,6 +67,7 @@ fn generate_genesis(accounts: &[AccountId]) -> Storage { }, evm: Default::default(), ethereum: Default::default(), + ..Default::default() } .build_storage() .unwrap()