diff --git a/Cargo.lock b/Cargo.lock
index 41d2040ba5..dedb95240f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8045,17 +8045,21 @@ name = "pallet-xvm"
version = "0.2.2"
dependencies = [
"astar-primitives",
+ "fp-evm",
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
+ "pallet-balances",
"pallet-contracts",
- "pallet-ethereum-checked",
"pallet-evm",
+ "pallet-insecure-randomness-collective-flip",
+ "pallet-timestamp",
"parity-scale-codec",
"scale-info",
"serde",
"sp-core",
+ "sp-io",
"sp-runtime",
"sp-std",
]
diff --git a/pallets/ethereum-checked/src/lib.rs b/pallets/ethereum-checked/src/lib.rs
index 7ac4f0320b..c627f141b8 100644
--- a/pallets/ethereum-checked/src/lib.rs
+++ b/pallets/ethereum-checked/src/lib.rs
@@ -20,7 +20,7 @@
//!
//! ## Overview
//!
-//! A `pallet-ethererum` like pallet that execute transactions from checked source,
+//! A `pallet-ethereum like pallet that execute transactions from checked source,
//! like XCM remote call, cross-VM call, etc. Only `Call` transactions are supported
//! (no `Create`).
//!
diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml
index 8d5213d225..6121f5657a 100644
--- a/pallets/xvm/Cargo.toml
+++ b/pallets/xvm/Cargo.toml
@@ -30,9 +30,13 @@ pallet-contracts = { workspace = true }
# Astar
astar-primitives = { workspace = true }
-pallet-ethereum-checked = { workspace = true }
[dev-dependencies]
+sp-io = { workspace = true }
+fp-evm = { workspace = true }
+pallet-timestamp = { workspace = true, features = ["std"] }
+pallet-balances = { workspace = true, features = ["std"] }
+pallet-insecure-randomness-collective-flip = { workspace = true, features = ["std"] }
[features]
default = ["std"]
@@ -43,22 +47,20 @@ std = [
"frame-system/std",
"pallet-contracts/std",
"pallet-evm/std",
+ "pallet-insecure-randomness-collective-flip/std",
"scale-info/std",
"serde",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"astar-primitives/std",
- "pallet-ethereum-checked/std",
]
runtime-benchmarks = [
"frame-benchmarking",
- "pallet-ethereum-checked/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"pallet-contracts/try-runtime",
"pallet-evm/try-runtime",
- "pallet-ethereum-checked/try-runtime",
]
diff --git a/pallets/xvm/src/benchmarking.rs b/pallets/xvm/src/benchmarking.rs
new file mode 100644
index 0000000000..e013422135
--- /dev/null
+++ b/pallets/xvm/src/benchmarking.rs
@@ -0,0 +1,78 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar 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.
+
+// Astar 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 Astar. If not, see .
+
+use super::*;
+
+use frame_benchmarking::v2::*;
+use parity_scale_codec::Encode;
+use sp_core::H160;
+
+#[benchmarks]
+mod benchmarks {
+ use super::*;
+
+ #[benchmark]
+ fn evm_call_without_execution() {
+ let context = Context {
+ source_vm_id: VmId::Wasm,
+ weight_limit: Weight::from_parts(1_000_000, 1_000_000),
+ };
+ let vm_id = VmId::Evm;
+ let source = whitelisted_caller();
+ let target = H160::repeat_byte(1).encode();
+ let input = vec![1, 2, 3];
+
+ #[block]
+ {
+ Pallet::::call_without_execution(context, vm_id, source, target, input).unwrap();
+ }
+ }
+
+ #[benchmark]
+ fn wasm_call_without_execution() {
+ let context = Context {
+ source_vm_id: VmId::Evm,
+ weight_limit: Weight::from_parts(1_000_000, 1_000_000),
+ };
+ let vm_id = VmId::Wasm;
+ let source = whitelisted_caller();
+ let target = whitelisted_caller::().encode();
+ let input = vec![1, 2, 3];
+
+ #[block]
+ {
+ Pallet::::call_without_execution(context, vm_id, source, target, input).unwrap();
+ }
+ }
+
+ impl_benchmark_test_suite!(
+ Pallet,
+ crate::benchmarking::tests::new_test_ext(),
+ crate::mock::TestRuntime,
+ );
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::mock;
+ use sp_io::TestExternalities;
+
+ pub fn new_test_ext() -> TestExternalities {
+ mock::ExtBuilder::default().build()
+ }
+}
diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs
index 789d5b4821..e5927c2647 100644
--- a/pallets/xvm/src/lib.rs
+++ b/pallets/xvm/src/lib.rs
@@ -42,9 +42,15 @@ use astar_primitives::{
ethereum_checked::{
AccountMapping, CheckedEthereumTransact, CheckedEthereumTx, MAX_ETHEREUM_TX_INPUT_SIZE,
},
- xvm::{CallError, CallErrorWithWeight, CallInfo, Context, VmId, XvmCall, XvmCallResult},
+ xvm::{CallError, CallErrorWithWeight, CallInfo, CallResult, Context, VmId, XvmCall},
};
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;
+
+#[cfg(test)]
+mod mock;
+
pub use pallet::*;
#[frame_support::pallet]
@@ -55,12 +61,11 @@ pub mod pallet {
pub struct Pallet(PhantomData);
#[pallet::config]
- pub trait Config:
- frame_system::Config
- + pallet_evm::Config
- + pallet_ethereum_checked::Config
- + pallet_contracts::Config
- {
+ pub trait Config: frame_system::Config + pallet_contracts::Config {
+ /// Mapping from `Account` to `H160`.
+ type AccountMapping: AccountMapping;
+ /// Mapping from Ethereum gas to Substrate weight.
+ type GasWeightMapping: GasWeightMapping;
/// `CheckedEthereumTransact` implementation.
type EthereumTransact: CheckedEthereumTransact;
}
@@ -73,7 +78,7 @@ impl XvmCall for Pallet {
source: T::AccountId,
target: Vec,
input: Vec,
- ) -> XvmCallResult {
+ ) -> CallResult {
Pallet::::do_call(context, vm_id, source, target, input, false)
}
}
@@ -89,7 +94,7 @@ impl Pallet {
target: Vec,
input: Vec,
skip_execution: bool,
- ) -> XvmCallResult {
+ ) -> CallResult {
ensure!(
context.source_vm_id != vm_id,
CallErrorWithWeight {
@@ -98,7 +103,7 @@ impl Pallet {
}
);
- match context.source_vm_id {
+ match vm_id {
VmId::Evm => Pallet::::evm_call(context, source, target, input, skip_execution),
VmId::Wasm => Pallet::::wasm_call(context, source, target, input, skip_execution),
}
@@ -110,7 +115,7 @@ impl Pallet {
target: Vec,
input: Vec,
skip_execution: bool,
- ) -> XvmCallResult {
+ ) -> CallResult {
log::trace!(
target: "xvm::evm_call",
"Calling EVM: {:?} {:?}, {:?}, {:?}",
@@ -174,7 +179,7 @@ impl Pallet {
target: Vec,
input: Vec,
skip_execution: bool,
- ) -> XvmCallResult {
+ ) -> CallResult {
log::trace!(
target: "xvm::wasm_call",
"Calling WASM: {:?} {:?}, {:?}, {:?}",
@@ -226,13 +231,13 @@ impl Pallet {
}
#[cfg(feature = "runtime-benchmarks")]
- pub fn xvm_call_without_execution(
+ pub fn call_without_execution(
context: Context,
vm_id: VmId,
source: T::AccountId,
target: Vec,
input: Vec,
- ) -> XvmCallResult {
+ ) -> CallResult {
Self::do_call(context, vm_id, source, target, input, true)
}
}
diff --git a/pallets/xvm/src/mock.rs b/pallets/xvm/src/mock.rs
new file mode 100644
index 0000000000..2c06bc4d63
--- /dev/null
+++ b/pallets/xvm/src/mock.rs
@@ -0,0 +1,207 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar 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.
+
+// Astar 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 Astar. If not, see .
+
+#![cfg(test)]
+
+use super::*;
+use crate as pallet_xvm;
+
+use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed};
+use frame_support::{
+ construct_runtime,
+ dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo},
+ parameter_types,
+ sp_io::TestExternalities,
+ traits::{ConstBool, ConstU128, ConstU64, Nothing},
+ weights::Weight,
+};
+use sp_core::{H160, H256};
+use sp_runtime::{
+ testing::Header,
+ traits::{BlakeTwo256, IdentityLookup},
+ AccountId32,
+};
+
+parameter_types! {
+ pub BlockWeights: frame_system::limits::BlockWeights =
+ frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, 0));
+}
+
+impl frame_system::Config for TestRuntime {
+ type BaseCallFilter = frame_support::traits::Everything;
+ type BlockWeights = ();
+ type BlockLength = ();
+ type RuntimeOrigin = RuntimeOrigin;
+ type Index = u64;
+ type RuntimeCall = RuntimeCall;
+ type BlockNumber = BlockNumber;
+ type Hash = H256;
+ type Hashing = BlakeTwo256;
+ type AccountId = AccountId;
+ type Lookup = IdentityLookup;
+ type Header = Header;
+ type RuntimeEvent = RuntimeEvent;
+ type BlockHashCount = ConstU64<250>;
+ type DbWeight = ();
+ type Version = ();
+ type PalletInfo = PalletInfo;
+ type AccountData = pallet_balances::AccountData;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
+ type SystemWeightInfo = ();
+ type SS58Prefix = ();
+ type OnSetCode = ();
+ type MaxConsumers = frame_support::traits::ConstU32<16>;
+}
+
+impl pallet_balances::Config for TestRuntime {
+ type MaxLocks = ConstU32<4>;
+ type MaxReserves = ();
+ type ReserveIdentifier = [u8; 8];
+ type Balance = Balance;
+ type RuntimeEvent = RuntimeEvent;
+ type DustRemoval = ();
+ type ExistentialDeposit = ConstU128<2>;
+ type AccountStore = System;
+ type WeightInfo = ();
+}
+
+impl pallet_timestamp::Config for TestRuntime {
+ type Moment = u64;
+ type OnTimestampSet = ();
+ type MinimumPeriod = ConstU64<3>;
+ type WeightInfo = ();
+}
+
+impl pallet_insecure_randomness_collective_flip::Config for TestRuntime {}
+
+parameter_types! {
+ pub const DepositPerItem: Balance = 1_000;
+ pub const DepositPerByte: Balance = 1_000;
+ pub DeletionWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX);
+ pub Schedule: pallet_contracts::Schedule = Default::default();
+}
+
+impl pallet_contracts::Config for TestRuntime {
+ type Time = Timestamp;
+ type Randomness = RandomnessCollectiveFlip;
+ type Currency = Balances;
+ type RuntimeEvent = RuntimeEvent;
+ type RuntimeCall = RuntimeCall;
+ type CallFilter = Nothing;
+ type DepositPerItem = DepositPerItem;
+ type DepositPerByte = DepositPerByte;
+ type CallStack = [pallet_contracts::Frame; 5];
+ type WeightPrice = ();
+ type WeightInfo = pallet_contracts::weights::SubstrateWeight;
+ type ChainExtension = ();
+ type DeletionQueueDepth = ConstU32<128>;
+ type DeletionWeightLimit = DeletionWeightLimit;
+ type Schedule = Schedule;
+ type AddressGenerator = pallet_contracts::DefaultAddressGenerator;
+ type MaxCodeLen = ConstU32<{ 123 * 1024 }>;
+ type MaxStorageKeyLen = ConstU32<128>;
+ type UnsafeUnstableInterface = ConstBool;
+ type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
+}
+
+pub struct HashedAccountMapping;
+impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping {
+ fn into_h160(account_id: AccountId) -> H160 {
+ let data = (b"evm:", account_id);
+ return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]);
+ }
+}
+
+pub struct MockEthereumTransact;
+impl CheckedEthereumTransact for MockEthereumTransact {
+ fn xvm_transact(
+ _source: H160,
+ _checked_tx: CheckedEthereumTx,
+ ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> {
+ Ok((
+ PostDispatchInfo {
+ actual_weight: Default::default(),
+ pays_fee: Default::default(),
+ },
+ EvmCallInfo {
+ exit_reason: ExitReason::Succeed(ExitSucceed::Returned),
+ value: Default::default(),
+ used_gas: Default::default(),
+ logs: Default::default(),
+ },
+ ))
+ }
+}
+
+pub struct MockGasWeightMapping;
+impl GasWeightMapping for MockGasWeightMapping {
+ fn gas_to_weight(gas: u64, _without_base_weight: bool) -> Weight {
+ Weight::from_parts(gas, 0)
+ }
+ fn weight_to_gas(weight: Weight) -> u64 {
+ weight.ref_time()
+ }
+}
+
+impl pallet_xvm::Config for TestRuntime {
+ type GasWeightMapping = MockGasWeightMapping;
+ type AccountMapping = HashedAccountMapping;
+ type EthereumTransact = MockEthereumTransact;
+}
+
+pub(crate) type AccountId = AccountId32;
+pub(crate) type BlockNumber = u64;
+pub(crate) type Balance = u128;
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
+type Block = frame_system::mocking::MockBlock;
+
+construct_runtime!(
+ pub struct TestRuntime
+ where
+ Block = Block,
+ NodeBlock = Block,
+ UncheckedExtrinsic = UncheckedExtrinsic,
+ {
+ System: frame_system,
+ Timestamp: pallet_timestamp,
+ Balances: pallet_balances,
+ RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip,
+ Contracts: pallet_contracts,
+ Xvm: pallet_xvm,
+ }
+);
+
+#[derive(Default)]
+pub struct ExtBuilder;
+
+impl ExtBuilder {
+ #[allow(dead_code)]
+ pub fn build(self) -> TestExternalities {
+ let t = frame_system::GenesisConfig::default()
+ .build_storage::()
+ .unwrap();
+
+ let mut ext = TestExternalities::from(t);
+ ext.execute_with(|| {
+ System::set_block_number(1);
+ });
+ ext
+ }
+}
diff --git a/precompiles/xvm/src/mock.rs b/precompiles/xvm/src/mock.rs
index 4c9fe078f7..4e591f4268 100644
--- a/precompiles/xvm/src/mock.rs
+++ b/precompiles/xvm/src/mock.rs
@@ -37,7 +37,7 @@ use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
};
-use astar_primitives::xvm::{CallError::*, CallErrorWithWeight, CallInfo, XvmCallResult};
+use astar_primitives::xvm::{CallError::*, CallErrorWithWeight, CallInfo, CallResult};
pub type AccountId = TestAccount;
pub type Balance = u128;
@@ -237,7 +237,7 @@ impl XvmCall for MockXvmWithArgsCheck {
_source: AccountId,
target: Vec,
input: Vec,
- ) -> XvmCallResult {
+ ) -> CallResult {
ensure!(
vm_id != VmId::Evm,
CallErrorWithWeight {
diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs
index 168e1c1fe9..50d4d472a0 100644
--- a/primitives/src/xvm.rs
+++ b/primitives/src/xvm.rs
@@ -78,7 +78,7 @@ pub struct CallErrorWithWeight {
}
/// XVM call result.
-pub type XvmCallResult = Result;
+pub type CallResult = Result;
/// XVM context.
///
@@ -106,5 +106,5 @@ pub trait XvmCall {
source: AccountId,
target: Vec,
input: Vec,
- ) -> XvmCallResult;
+ ) -> CallResult;
}
diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs
index 0e4ba1ce17..99c166aee8 100644
--- a/runtime/local/src/lib.rs
+++ b/runtime/local/src/lib.rs
@@ -471,6 +471,8 @@ parameter_types! {
}
impl pallet_xvm::Config for Runtime {
+ type GasWeightMapping = pallet_evm::FixedGasWeightMapping;
+ type AccountMapping = HashedAccountMapping;
type EthereumTransact = EthereumChecked;
}
diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml
index a1cb4ab9a0..bfdcbf913d 100644
--- a/runtime/shibuya/Cargo.toml
+++ b/runtime/shibuya/Cargo.toml
@@ -255,6 +255,7 @@ runtime-benchmarks = [
"pallet-preimage/runtime-benchmarks",
"pallet-collator-selection/runtime-benchmarks",
"pallet-ethereum-checked/runtime-benchmarks",
+ "pallet-xvm/runtime-benchmarks",
"polkadot-runtime/runtime-benchmarks",
"orml-xtokens/runtime-benchmarks",
"astar-primitives/runtime-benchmarks",
diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs
index 16ae014b08..d5ae642d1a 100644
--- a/runtime/shibuya/src/lib.rs
+++ b/runtime/shibuya/src/lib.rs
@@ -784,6 +784,8 @@ impl pallet_ethereum_checked::Config for Runtime {
}
impl pallet_xvm::Config for Runtime {
+ type GasWeightMapping = pallet_evm::FixedGasWeightMapping;
+ type AccountMapping = HashedAccountMapping;
type EthereumTransact = EthereumChecked;
}
@@ -1423,6 +1425,7 @@ mod benches {
[pallet_collator_selection, CollatorSelection]
[pallet_xcm, PolkadotXcm]
[pallet_ethereum_checked, EthereumChecked]
+ [pallet_xvm, Xvm]
);
}