diff --git a/Cargo.lock b/Cargo.lock index 98c3112147..aacd4cbd09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6508,7 +6508,6 @@ dependencies = [ "pallet-balances", "pallet-chain-extension-assets", "pallet-chain-extension-unified-accounts", - "pallet-chain-extension-xvm", "pallet-collective", "pallet-collective-proxy", "pallet-contracts", @@ -6531,7 +6530,6 @@ dependencies = [ "pallet-evm-precompile-sr25519", "pallet-evm-precompile-substrate-ecdsa", "pallet-evm-precompile-unified-accounts", - "pallet-evm-precompile-xvm", "pallet-grandpa", "pallet-inflation", "pallet-insecure-randomness-collective-flip", @@ -6548,7 +6546,6 @@ dependencies = [ "pallet-unified-accounts", "pallet-utility", "pallet-vesting", - "pallet-xvm", "parity-scale-codec", "precompile-utils", "scale-info", @@ -8178,25 +8175,6 @@ dependencies = [ "unified-accounts-chain-extension-types", ] -[[package]] -name = "pallet-chain-extension-xvm" -version = "0.1.1" -dependencies = [ - "astar-primitives", - "frame-support", - "frame-system", - "log", - "num-traits", - "pallet-contracts", - "pallet-unified-accounts", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-runtime", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.9.0)", - "xvm-chain-extension-types", -] - [[package]] name = "pallet-child-bounties" version = "27.0.0" @@ -8851,32 +8829,6 @@ dependencies = [ "staging-xcm-executor", ] -[[package]] -name = "pallet-evm-precompile-xvm" -version = "0.1.1" -dependencies = [ - "astar-primitives", - "derive_more", - "fp-evm", - "frame-support", - "frame-system", - "hex", - "hex-literal", - "log", - "num_enum 0.5.11", - "pallet-balances", - "pallet-evm", - "pallet-timestamp", - "parity-scale-codec", - "precompile-utils", - "scale-info", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.9.0)", -] - [[package]] name = "pallet-fast-unstake" version = "27.0.0" @@ -9722,33 +9674,6 @@ dependencies = [ "staging-xcm-executor", ] -[[package]] -name = "pallet-xvm" -version = "0.2.2" -dependencies = [ - "astar-primitives", - "environmental", - "fp-evm", - "frame-benchmarking", - "frame-support", - "frame-system", - "hex", - "log", - "pallet-balances", - "pallet-contracts", - "pallet-contracts-uapi", - "pallet-evm", - "pallet-insecure-randomness-collective-flip", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.9.0)", -] - [[package]] name = "parachains-common" version = "7.0.0" @@ -14253,7 +14178,6 @@ dependencies = [ "pallet-balances", "pallet-chain-extension-assets", "pallet-chain-extension-unified-accounts", - "pallet-chain-extension-xvm", "pallet-collator-selection 3.3.2", "pallet-collective", "pallet-collective-proxy", @@ -14279,7 +14203,6 @@ dependencies = [ "pallet-evm-precompile-substrate-ecdsa", "pallet-evm-precompile-unified-accounts", "pallet-evm-precompile-xcm", - "pallet-evm-precompile-xvm", "pallet-identity", "pallet-inflation", "pallet-insecure-randomness-collective-flip", @@ -14302,7 +14225,6 @@ dependencies = [ "pallet-xc-asset-config", "pallet-xcm", "pallet-xcm-benchmarks", - "pallet-xvm", "parachains-common", "parity-scale-codec", "polkadot-parachain-primitives", @@ -17987,17 +17909,6 @@ dependencies = [ "substrate-build-script-utils", ] -[[package]] -name = "xvm-chain-extension-types" -version = "0.1.0" -dependencies = [ - "astar-primitives", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.9.0)", -] - [[package]] name = "yamux" version = "0.10.2" diff --git a/Cargo.toml b/Cargo.toml index b2c464e763..b00ca59d0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "precompiles/*", "primitives", "chain-extensions/pallet-assets", - "chain-extensions/xvm", "chain-extensions/unified-accounts", "chain-extensions/types/*", "vendor/evm-tracing", @@ -284,7 +283,6 @@ pallet-collator-selection = { path = "./pallets/collator-selection", default-fea pallet-dapp-staking-v3 = { path = "./pallets/dapp-staking-v3", default-features = false } pallet-dapp-staking-migration = { path = "./pallets/dapp-staking-migration", default-features = false } pallet-xc-asset-config = { path = "./pallets/xc-asset-config", default-features = false } -pallet-xvm = { path = "./pallets/xvm", default-features = false } pallet-ethereum-checked = { path = "./pallets/ethereum-checked", default-features = false } pallet-inflation = { path = "./pallets/inflation", default-features = false } pallet-dynamic-evm-base-fee = { path = "./pallets/dynamic-evm-base-fee", default-features = false } @@ -303,16 +301,13 @@ pallet-evm-precompile-assets-erc20 = { path = "./precompiles/assets-erc20", defa pallet-evm-precompile-sr25519 = { path = "./precompiles/sr25519", default-features = false } pallet-evm-precompile-substrate-ecdsa = { path = "./precompiles/substrate-ecdsa", default-features = false } pallet-evm-precompile-xcm = { path = "./precompiles/xcm", default-features = false } -pallet-evm-precompile-xvm = { path = "./precompiles/xvm", default-features = false } pallet-evm-precompile-dapp-staking-v3 = { path = "./precompiles/dapp-staking-v3", default-features = false } pallet-evm-precompile-unified-accounts = { path = "./precompiles/unified-accounts", default-features = false } pallet-evm-precompile-dispatch-lockdrop = { path = "./precompiles/dispatch-lockdrop", default-features = false } -pallet-chain-extension-xvm = { path = "./chain-extensions/xvm", default-features = false } pallet-chain-extension-assets = { path = "./chain-extensions/pallet-assets", default-features = false } pallet-chain-extension-unified-accounts = { path = "./chain-extensions/unified-accounts", default-features = false } -xvm-chain-extension-types = { path = "./chain-extensions/types/xvm", default-features = false } assets-chain-extension-types = { path = "./chain-extensions/types/assets", default-features = false } unified-accounts-chain-extension-types = { path = "./chain-extensions/types/unified-accounts", default-features = false } diff --git a/chain-extensions/types/xvm/Cargo.toml b/chain-extensions/types/xvm/Cargo.toml deleted file mode 100644 index e9888174c8..0000000000 --- a/chain-extensions/types/xvm/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "xvm-chain-extension-types" -version = "0.1.0" -license = "Apache-2.0" -description = "Types definitions for contracts using xvm chain-extension." -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -astar-primitives = { workspace = true } -parity-scale-codec = { workspace = true } -scale-info = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -[features] -default = ["std"] -std = [ - "parity-scale-codec/std", - "scale-info/std", - "sp-runtime/std", - "sp-std/std", - "astar-primitives/std", -] diff --git a/chain-extensions/types/xvm/src/lib.rs b/chain-extensions/types/xvm/src/lib.rs deleted file mode 100644 index 4b6b615059..0000000000 --- a/chain-extensions/types/xvm/src/lib.rs +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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_attr(not(feature = "std"), no_std)] - -use astar_primitives::{ - xvm::{FailureError, FailureReason, FailureRevert}, - Balance, -}; -use parity_scale_codec::{Decode, Encode}; -use sp_std::vec::Vec; - -#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, Debug)] -pub enum XvmExecutionResult { - /// Success - Ok, - /// Failure - Err(u32), -} - -impl From for XvmExecutionResult { - fn from(input: FailureReason) -> Self { - // `0` is reserved for `Ok` - let error_code = match input { - // Revert failure: 1 - 127 - FailureReason::Revert(FailureRevert::InvalidTarget) => 1, - FailureReason::Revert(FailureRevert::InputTooLarge) => 2, - FailureReason::Revert(FailureRevert::VmRevert(_)) => 3, - - // Error failure: 128 - 255 - FailureReason::Error(FailureError::InvalidVmId) => 128, - FailureReason::Error(FailureError::SameVmCallDenied) => 129, - FailureReason::Error(FailureError::ReentranceDenied) => 130, - FailureReason::Error(FailureError::VmError(_)) => 131, - FailureReason::Error(FailureError::OutOfGas) => 132, - }; - Self::Err(error_code) - } -} - -impl From for u32 { - fn from(input: XvmExecutionResult) -> Self { - match input { - XvmExecutionResult::Ok => 0, - XvmExecutionResult::Err(code) => code, - } - } -} - -#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)] -pub struct XvmCallArgs { - /// virtual machine identifier - pub vm_id: u8, - /// Call destination (e.g. address) - pub to: Vec, - /// Encoded call params - pub input: Vec, - /// Value to transfer - pub value: Balance, -} diff --git a/chain-extensions/xvm/Cargo.toml b/chain-extensions/xvm/Cargo.toml deleted file mode 100644 index 0c79a43bd7..0000000000 --- a/chain-extensions/xvm/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "pallet-chain-extension-xvm" -version = "0.1.1" -license = "Apache-2.0" -description = "Chain extension for XVM" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -frame-support = { workspace = true } -frame-system = { workspace = true } -log = { workspace = true } -num-traits = { workspace = true } -pallet-contracts = { workspace = true } -pallet-unified-accounts = { workspace = true } -parity-scale-codec = { workspace = true } -scale-info = { workspace = true } -sp-core = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -# Astar -astar-primitives = { workspace = true } -xvm-chain-extension-types = { workspace = true } - -[features] -default = ["std"] -std = [ - "parity-scale-codec/std", - "frame-support/std", - "frame-system/std", - "num-traits/std", - "pallet-contracts/std", - "pallet-unified-accounts/std", - "scale-info/std", - "sp-std/std", - "sp-core/std", - "sp-runtime/std", - # Astar - "astar-primitives/std", - "log/std", - "xvm-chain-extension-types/std", -] diff --git a/chain-extensions/xvm/src/lib.rs b/chain-extensions/xvm/src/lib.rs deleted file mode 100644 index d64ef179d6..0000000000 --- a/chain-extensions/xvm/src/lib.rs +++ /dev/null @@ -1,193 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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_attr(not(feature = "std"), no_std)] - -extern crate alloc; -use alloc::format; - -use astar_primitives::{ - evm::UnifiedAddressMapper, - xvm::{CallFailure, Context, FailureError, VmId, XvmCall}, -}; -use frame_support::weights::Weight; -use frame_system::RawOrigin; -use pallet_contracts::chain_extension::{ - ChainExtension, Environment, Ext, InitState, RetVal, ReturnFlags, -}; -use pallet_unified_accounts::WeightInfo; -use parity_scale_codec::Encode; -use sp_runtime::DispatchError; -use sp_std::marker::PhantomData; -use xvm_chain_extension_types::{XvmCallArgs, XvmExecutionResult}; - -enum XvmFuncId { - Call, -} - -impl TryFrom for XvmFuncId { - type Error = DispatchError; - - fn try_from(value: u16) -> Result { - match value { - 1 => Ok(XvmFuncId::Call), - _ => Err(DispatchError::Other( - "Unsupported func id in Xvm chain extension", - )), - } - } -} - -/// XVM chain extension. -pub struct XvmExtension(PhantomData<(T, XC, UA)>); - -impl Default for XvmExtension { - fn default() -> Self { - XvmExtension(PhantomData) - } -} - -impl ChainExtension for XvmExtension -where - T: pallet_contracts::Config + pallet_unified_accounts::Config, - XC: XvmCall, - UA: UnifiedAddressMapper, -{ - fn call(&mut self, env: Environment) -> Result - where - E: Ext, - { - let func_id = env.func_id().try_into()?; - let mut env = env.buf_in_buf_out(); - - match func_id { - XvmFuncId::Call => { - // We need to immediately charge for the worst case scenario. Gas equals Weight in pallet-contracts context. - let weight_limit = env.ext().gas_meter().gas_left(); - let charged_weight = env.charge_weight(weight_limit)?; - - let XvmCallArgs { - vm_id, - to, - input, - value, - } = env.read_as_unbounded(env.in_len())?; - - // Similar to EVM behavior, the `source` should be (limited to) the - // contract address. Otherwise contracts would be able to do arbitrary - // things on behalf of the caller via XVM. - let source = env.ext().address().clone(); - - // Claim the default evm address if needed. - let mut actual_weight = Weight::zero(); - if value > 0 { - // `UA::to_h160`. - actual_weight.saturating_accrue( - ::WeightInfo::to_h160(), - ); - - if actual_weight.any_gt(weight_limit) { - return out_of_gas_err(actual_weight); - } - - if UA::to_h160(&source).is_none() { - let weight_of_claim = ::WeightInfo::claim_default_evm_address(); - actual_weight.saturating_accrue(weight_of_claim); - if actual_weight.any_gt(weight_limit) { - return out_of_gas_err(actual_weight); - } - - let claim_result = - pallet_unified_accounts::Pallet::::claim_default_evm_address( - RawOrigin::Signed(source.clone()).into(), - ); - if claim_result.is_err() { - return Ok(RetVal::Diverging { - flags: ReturnFlags::REVERT, - data: format!("{:?}", claim_result.err()).into(), - }); - } - } - } - - let xvm_context = Context { - source_vm_id: VmId::Wasm, - // Weight limit left for XVM call. - weight_limit: weight_limit.saturating_sub(actual_weight), - }; - let vm_id = { - match TryInto::::try_into(vm_id) { - Ok(id) => id, - Err(err) => { - return Ok(RetVal::Diverging { - flags: ReturnFlags::REVERT, - data: format!("{:?}", err).into(), - }); - } - } - }; - let call_result = XC::call(xvm_context, vm_id, source, to, input, value, None); - - let used_weight = match call_result { - Ok(ref info) => info.used_weight, - Err(ref err) => err.used_weight, - }; - actual_weight.saturating_accrue(used_weight); - env.adjust_weight(charged_weight, actual_weight); - - match call_result { - Ok(info) => { - log::trace!( - target: "xvm-extension::xvm_call", - "info: {:?}", info - ); - - let buffer: sp_std::vec::Vec<_> = info.output.encode(); - env.write(&buffer, false, None)?; - Ok(RetVal::Converging(XvmExecutionResult::Ok.into())) - } - - Err(err) => { - log::trace!( - target: "xvm-extension::xvm_call", - "err: {:?}", err - ); - - // `Diverging` is used instead of `Err` to make sure the control - // doesn't return to the caller. - Ok(RetVal::Diverging { - flags: ReturnFlags::REVERT, - data: format!("{:?}", err).into(), - }) - } - } - } - } - } -} - -fn out_of_gas_err(actual_weight: Weight) -> Result { - Ok(RetVal::Diverging { - flags: ReturnFlags::REVERT, - data: format!( - "{:?}", - CallFailure::error(FailureError::OutOfGas, actual_weight) - ) - .into(), - }) -} diff --git a/pallets/ethereum-checked/src/lib.rs b/pallets/ethereum-checked/src/lib.rs index 2585278a12..e0c9b96d81 100644 --- a/pallets/ethereum-checked/src/lib.rs +++ b/pallets/ethereum-checked/src/lib.rs @@ -21,7 +21,7 @@ //! ## Overview //! //! A `pallet-ethereum like pallet that execute transactions from checked source, -//! like XCM remote call, cross-VM call, etc. Only `Call` transactions are supported +//! like XCM remote call. Only `Call` transactions are supported //! (no `Create`). //! //! The checked source guarantees that transactions are valid with prior checks, so these @@ -36,10 +36,6 @@ //! - `transact`: transact an Ethereum transaction. Similar to `pallet_ethereum::Transact`, //! but is only for XCM remote call. //! -//! ### Implementation -//! -//! - Implements `CheckedEthereumTransact` trait. -//! #![cfg_attr(not(feature = "std"), no_std)] @@ -64,10 +60,7 @@ use sp_runtime::traits::TrailingZeroInput; use sp_runtime::traits::UniqueSaturatedInto; use sp_std::{marker::PhantomData, result::Result}; -use astar_primitives::{ - ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx}, - evm::UnifiedAddressMapper, -}; +use astar_primitives::{ethereum_checked::CheckedEthereumTx, evm::UnifiedAddressMapper}; pub use pallet::*; @@ -116,8 +109,6 @@ impl, O>> + From>, Acco pub enum CheckedEthereumTxKind { /// The tx is from XCM remote call. Xcm, - /// The tx is from cross-VM call. - Xvm, } #[frame_support::pallet] @@ -132,9 +123,6 @@ pub mod pallet { /// Reserved Xcmp weight for block gas limit calculation. type ReservedXcmpWeight: Get; - /// Xcm transaction weight limit, for block gas limit calculation. - type XvmTxWeightLimit: Get; - /// Invalid tx error. type InvalidEvmTransactionError: From; @@ -270,7 +258,6 @@ impl Pallet { fn block_gas_limit(tx_kind: &CheckedEthereumTxKind) -> u64 { let weight_limit = match tx_kind { CheckedEthereumTxKind::Xcm => T::ReservedXcmpWeight::get(), - CheckedEthereumTxKind::Xvm => T::XvmTxWeightLimit::get(), }; T::GasWeightMapping::weight_to_gas(weight_limit) } @@ -292,12 +279,3 @@ impl Pallet { .map(|(post_info, _)| post_info) } } - -impl CheckedEthereumTransact for Pallet { - fn xvm_transact( - source: H160, - checked_tx: CheckedEthereumTx, - ) -> Result<(PostDispatchInfo, CallInfo), DispatchErrorWithPostInfo> { - Self::do_transact(source, checked_tx, CheckedEthereumTxKind::Xvm, false) - } -} diff --git a/pallets/ethereum-checked/src/mock.rs b/pallets/ethereum-checked/src/mock.rs index 23464c97c1..fc68a7231a 100644 --- a/pallets/ethereum-checked/src/mock.rs +++ b/pallets/ethereum-checked/src/mock.rs @@ -206,7 +206,6 @@ parameter_types! { impl pallet_ethereum_checked::Config for TestRuntime { type ReservedXcmpWeight = TxWeightLimit; - type XvmTxWeightLimit = TxWeightLimit; type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; type AddressMapper = MockAddressMapper; diff --git a/pallets/ethereum-checked/src/tests.rs b/pallets/ethereum-checked/src/tests.rs index 8193b41cba..4eaa356063 100644 --- a/pallets/ethereum-checked/src/tests.rs +++ b/pallets/ethereum-checked/src/tests.rs @@ -23,7 +23,6 @@ use mock::*; use astar_primitives::ethereum_checked::EthereumTxInput; use ethereum::{ReceiptV3 as Receipt, TransactionV2 as Transaction}; -pub use fp_rpc::TransactionStatus; use frame_support::{assert_noop, assert_ok}; use sp_runtime::DispatchError; @@ -73,18 +72,6 @@ fn transact_works() { _ => panic!("unexpected transaction type"), } assert_eq!(Nonce::::get(), U256::from(2)); - - let retrieve_tx = CheckedEthereumTx { - gas_limit: U256::from(1_000_000), - target: contract_address(), - value: U256::zero(), - // Calling `retrieve` - input: bounded_input("2e64cec1"), - maybe_access_list: None, - }; - let (_, call_info) = - EthereumChecked::xvm_transact(ALICE_H160, retrieve_tx).expect("failed to retrieve"); - assert_eq!(U256::from_big_endian(&(call_info.value)), 3.into()); }); } @@ -134,14 +121,6 @@ fn no_hash_collision() { RawOrigin::XcmEthereumTx(ALICE).into(), store_tx.clone() )); - assert_ok!(::xvm_transact( - BOB_H160, - store_tx.clone() - )); - assert_ok!(::xvm_transact( - CHARLIE_H160, - store_tx.clone() - )); } let mut tx_hashes = pallet_ethereum::Pending::::get() @@ -149,6 +128,6 @@ fn no_hash_collision() { .map(|(tx, _, _)| tx.hash()) .collect::>(); tx_hashes.dedup(); - assert_eq!(tx_hashes.len(), 15); + assert_eq!(tx_hashes.len(), 5); }); } diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml deleted file mode 100644 index 50b68addb6..0000000000 --- a/pallets/xvm/Cargo.toml +++ /dev/null @@ -1,83 +0,0 @@ -[package] -name = "pallet-xvm" -version = "0.2.2" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -environmental = { workspace = true } -log = { workspace = true } -serde = { workspace = true, optional = true } - -# Substrate -frame-support = { workspace = true } -frame-system = { workspace = true } -parity-scale-codec = { workspace = true } -scale-info = { workspace = true } -sp-core = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -# Benchmarks -frame-benchmarking = { workspace = true, optional = true } - -# EVM -fp-evm = { workspace = true } -pallet-evm = { workspace = true } - -# Substrate WASM VM support -pallet-contracts = { workspace = true } -pallet-contracts-uapi = { workspace = true } - -# Astar -astar-primitives = { workspace = true } - -[dev-dependencies] -hex = { workspace = true } -pallet-balances = { workspace = true, features = ["std"] } -pallet-insecure-randomness-collective-flip = { workspace = true, features = ["std"] } -pallet-timestamp = { workspace = true, features = ["std"] } -sp-io = { workspace = true } - -[features] -default = ["std"] -std = [ - "environmental/std", - "log/std", - "parity-scale-codec/std", - "fp-evm/std", - "frame-support/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", - "frame-benchmarking?/std", - "serde?/std", -] - -runtime-benchmarks = [ - "frame-benchmarking", - "astar-primitives/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-contracts/runtime-benchmarks", - "pallet-evm/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -try-runtime = [ - "frame-support/try-runtime", - "pallet-contracts/try-runtime", - "pallet-evm/try-runtime", - "astar-primitives/try-runtime", - "frame-system/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/pallets/xvm/src/benchmarking.rs b/pallets/xvm/src/benchmarking.rs deleted file mode 100644 index 5b7fe5f057..0000000000 --- a/pallets/xvm/src/benchmarking.rs +++ /dev/null @@ -1,88 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 frame_support::weights::Weight; -use parity_scale_codec::Encode; -use sp_core::H160; -use sp_runtime::MultiAddress; - -use astar_primitives::Balance; - -#[benchmarks( - where ::Currency: Inspect, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn evm_call_overheads() { - 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]; - let value = 1_000_000u128; - - #[block] - { - Pallet::::call_without_execution(context, vm_id, source, target, input, value, None) - .unwrap(); - } - } - - #[benchmark] - fn wasm_call_overheads() { - 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 = MultiAddress::::Id(whitelisted_caller()).encode(); - let input = vec![1, 2, 3]; - let value = 1_000_000u128; - - #[block] - { - Pallet::::call_without_execution(context, vm_id, source, target, input, value, None) - .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 deleted file mode 100644 index b9e21af88d..0000000000 --- a/pallets/xvm/src/lib.rs +++ /dev/null @@ -1,353 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 . - -//! # XVM pallet -//! -//! A module to provide -//! -//! ## Overview -//! -//! The XVM pallet provides a runtime interface to call different VMs. It currently -//! supports two VMs: EVM and WASM. With further development, more VMs can be added. -//! -//! Together with other functionalities like Chain Extension and precompiles, -//! the XVM pallet enables the runtime to support cross-VM calls. -//! -//! ## Interface -//! -//! ### Implementation -//! -//! - Implements `XvmCall` trait. -//! - -#![cfg_attr(not(feature = "std"), no_std)] - -extern crate alloc; -use alloc::format; - -use fp_evm::ExitReason; -use frame_support::{ensure, traits::fungible::Inspect, weights::Weight}; -use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; -use pallet_contracts_uapi::ReturnFlags; -use pallet_evm::GasWeightMapping; -use parity_scale_codec::Decode; -use sp_core::{H160, U256}; -use sp_std::{marker::PhantomData, prelude::*}; - -use astar_primitives::{ - ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx, EthereumTxInput}, - evm::UnifiedAddressMapper, - xvm::{ - CallFailure, CallOutput, CallResult, Context, FailureError::*, FailureRevert::*, VmId, - XvmCall, - }, - Balance, -}; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - -pub mod weights; -pub use weights::WeightInfo; - -mod mock; -mod tests; - -pub use pallet::*; - -pub type WeightInfoOf = ::WeightInfo; - -environmental::thread_local_impl!(static IN_XVM: environmental::RefCell = environmental::RefCell::new(false)); - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::pallet] - pub struct Pallet(PhantomData); - - #[pallet::config] - pub trait Config: frame_system::Config + pallet_contracts::Config { - /// Mapping from `Account` to `H160`. - type AddressMapper: UnifiedAddressMapper; - - /// Mapping from Ethereum gas to Substrate weight. - type GasWeightMapping: GasWeightMapping; - - /// `CheckedEthereumTransact` implementation. - type EthereumTransact: CheckedEthereumTransact; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - } -} - -impl XvmCall for Pallet -where - T: Config, - T::Currency: Inspect, -{ - fn call( - context: Context, - vm_id: VmId, - source: T::AccountId, - target: Vec, - input: Vec, - value: Balance, - storage_deposit_limit: Option, - ) -> CallResult { - Pallet::::do_call( - context, - vm_id, - source, - target, - input, - value, - storage_deposit_limit, - false, - ) - } -} - -impl Pallet -where - T: Config, - T::Currency: Inspect, -{ - fn do_call( - context: Context, - vm_id: VmId, - source: T::AccountId, - target: Vec, - input: Vec, - value: Balance, - storage_deposit_limit: Option, - skip_execution: bool, - ) -> CallResult { - let overheads = match vm_id { - VmId::Evm => WeightInfoOf::::evm_call_overheads(), - VmId::Wasm => WeightInfoOf::::wasm_call_overheads(), - }; - - ensure!( - context.source_vm_id != vm_id, - CallFailure::error(SameVmCallDenied, overheads) - ); - - // Set `IN_XVM` to true & check reentrance. - if IN_XVM.with(|in_xvm| in_xvm.replace(true)) { - return Err(CallFailure::error(ReentranceDenied, overheads)); - } - - let res = match vm_id { - VmId::Evm => Pallet::::evm_call( - context, - source, - target, - input, - value, - overheads, - skip_execution, - ), - VmId::Wasm => Pallet::::wasm_call( - context, - source, - target, - input, - value, - overheads, - storage_deposit_limit, - skip_execution, - ), - }; - - // Set `IN_XVM` to false. - // We should make sure that this line is executed whatever the execution path. - let _ = IN_XVM.with(|in_xvm| in_xvm.take()); - - res - } - - fn evm_call( - context: Context, - source: T::AccountId, - target: Vec, - input: Vec, - value: Balance, - overheads: Weight, - skip_execution: bool, - ) -> CallResult { - log::trace!( - target: "xvm::evm_call", - "Calling EVM: {:?} {:?}, {:?}, {:?}, {:?}", - context, source, target, input, value, - ); - - ensure!( - target.len() == H160::len_bytes(), - CallFailure::revert(InvalidTarget, overheads) - ); - let target_decoded = Decode::decode(&mut target.as_ref()) - .map_err(|_| CallFailure::revert(InvalidTarget, overheads))?; - let bounded_input = EthereumTxInput::try_from(input) - .map_err(|_| CallFailure::revert(InputTooLarge, overheads))?; - - let value_u256 = U256::from(value); - // With overheads, less weight is available. - let weight_limit = context.weight_limit.saturating_sub(overheads); - let gas_limit = U256::from(T::GasWeightMapping::weight_to_gas(weight_limit)); - - let source = T::AddressMapper::to_h160_or_default(&source).into_address(); - let tx = CheckedEthereumTx { - gas_limit, - target: target_decoded, - value: value_u256, - input: bounded_input, - maybe_access_list: None, - }; - - // Note the skip execution check should be exactly before `T::EthereumTransact::xvm_transact` - // to benchmark the correct overheads. - if skip_execution { - return Ok(CallOutput::new(vec![], overheads)); - } - - let transact_result = T::EthereumTransact::xvm_transact(source, tx); - log::trace!( - target: "xvm::evm_call", - "EVM call result: {:?}", transact_result, - ); - - match transact_result { - Ok((post_dispatch_info, call_info)) => { - let used_weight = post_dispatch_info - .actual_weight - .unwrap_or_default() - .saturating_add(overheads); - match call_info.exit_reason { - ExitReason::Succeed(_) => Ok(CallOutput::new(call_info.value, used_weight)), - ExitReason::Revert(_) => { - // On revert, the `call_info.value` is the encoded error data. Refer to Contract - // ABI specification for details. https://docs.soliditylang.org/en/latest/abi-spec.html#errors - Err(CallFailure::revert(VmRevert(call_info.value), used_weight)) - } - ExitReason::Error(err) => Err(CallFailure::error( - VmError(format!("EVM call error: {:?}", err).into()), - used_weight, - )), - ExitReason::Fatal(err) => Err(CallFailure::error( - VmError(format!("EVM call error: {:?}", err).into()), - used_weight, - )), - } - } - Err(e) => { - let used_weight = e - .post_info - .actual_weight - .unwrap_or_default() - .saturating_add(overheads); - Err(CallFailure::error( - VmError(format!("EVM call error: {:?}", e.error).into()), - used_weight, - )) - } - } - } - - fn wasm_call( - context: Context, - source: T::AccountId, - target: Vec, - input: Vec, - value: Balance, - overheads: Weight, - storage_deposit_limit: Option, - skip_execution: bool, - ) -> CallResult { - log::trace!( - target: "xvm::wasm_call", - "Calling WASM: {:?} {:?}, {:?}, {:?}, {:?}, {:?}", - context, source, target, input, value, storage_deposit_limit, - ); - - let dest = { - let error = CallFailure::revert(InvalidTarget, overheads); - Decode::decode(&mut target.as_ref()).map_err(|_| error.clone()) - }?; - - // With overheads, less weight is available. - let weight_limit = context.weight_limit.saturating_sub(overheads); - - // Note the skip execution check should be exactly before `pallet_contracts::bare_call` - // to benchmark the correct overheads. - if skip_execution { - return Ok(CallOutput::new(vec![], overheads)); - } - - let call_result = pallet_contracts::Pallet::::bare_call( - source, - dest, - value, - weight_limit, - storage_deposit_limit, - input, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); - log::trace!(target: "xvm::wasm_call", "WASM call result: {:?}", call_result); - - let used_weight = call_result.gas_consumed.saturating_add(overheads); - match call_result.result { - Ok(val) => { - if val.flags.contains(ReturnFlags::REVERT) { - Err(CallFailure::revert(VmRevert(val.data), used_weight)) - } else { - Ok(CallOutput::new(val.data, used_weight)) - } - } - Err(error) => Err(CallFailure::error( - VmError(format!("WASM call error: {:?}", error).into()), - used_weight, - )), - } - } - - #[cfg(feature = "runtime-benchmarks")] - pub fn call_without_execution( - context: Context, - vm_id: VmId, - source: T::AccountId, - target: Vec, - input: Vec, - value: Balance, - storage_deposit_limit: Option, - ) -> CallResult { - Self::do_call( - context, - vm_id, - source, - target, - input, - value, - storage_deposit_limit, - true, - ) - } -} diff --git a/pallets/xvm/src/mock.rs b/pallets/xvm/src/mock.rs deleted file mode 100644 index e35927a86e..0000000000 --- a/pallets/xvm/src/mock.rs +++ /dev/null @@ -1,233 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 astar_primitives::evm::HashedDefaultMappings; -use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; -use frame_support::{ - construct_runtime, - dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, - pallet_prelude::*, - parameter_types, - traits::{ConstBool, ConstU128, ConstU64, Nothing}, -}; -use frame_system::EnsureSigned; -use sp_core::{H160, H256}; -use sp_io::TestExternalities; -use sp_runtime::{ - traits::{AccountIdLookup, BlakeTwo256}, - AccountId32, BuildStorage, Perbill, -}; -use sp_std::cell::RefCell; - -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 Nonce = u64; - type RuntimeCall = RuntimeCall; - type Block = Block; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = AccountIdLookup; - 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>; - type RuntimeTask = RuntimeTask; - type SingleBlockMigrations = (); - type MultiBlockMigrator = (); - type PreInherents = (); - type PostInherents = (); - type PostTransactions = (); -} - -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 = (); - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); - type RuntimeFreezeReason = (); - type MaxFreezes = ConstU32<0>; -} - -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 const DefaultDepositLimit: Balance = 1_000; - pub const MaxDelegateDependencies: u32 = 32; - pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(10); - 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 RuntimeHoldReason = RuntimeHoldReason; - type CallFilter = Nothing; - type DepositPerItem = DepositPerItem; - type DepositPerByte = DepositPerByte; - type DefaultDepositLimit = DefaultDepositLimit; - type CallStack = [pallet_contracts::Frame; 5]; - type WeightPrice = (); - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = (); - 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 }>; - type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; - type MaxDelegateDependencies = MaxDelegateDependencies; - type Migrations = (); - type Debug = (); - type Environment = (); - type Xcm = (); - type UploadOrigin = EnsureSigned; - type InstantiateOrigin = EnsureSigned; - type ApiVersion = (); -} - -thread_local! { - static TRANSACTED: RefCell> = RefCell::new(None); -} - -pub struct MockEthereumTransact; -impl MockEthereumTransact { - pub(crate) fn assert_transacted(source: H160, checked_tx: CheckedEthereumTx) { - let transacted = TRANSACTED.with(|v| v.borrow().clone()); - assert_eq!(transacted, Some((source, checked_tx))); - } -} -impl CheckedEthereumTransact for MockEthereumTransact { - fn xvm_transact( - source: H160, - checked_tx: CheckedEthereumTx, - ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> { - TRANSACTED.with(|v| *v.borrow_mut() = Some((source, checked_tx))); - Ok(( - PostDispatchInfo { - actual_weight: Default::default(), - pays_fee: Default::default(), - }, - EvmCallInfo { - exit_reason: ExitReason::Succeed(ExitSucceed::Returned), - value: Default::default(), - used_gas: UsedGas { - standard: Default::default(), - effective: Default::default(), - }, - logs: Default::default(), - weight_info: None, - }, - )) - } -} - -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 AddressMapper = HashedDefaultMappings; - type EthereumTransact = MockEthereumTransact; - type WeightInfo = weights::SubstrateWeight; -} - -pub(crate) type AccountId = AccountId32; - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub struct TestRuntime { - System: frame_system, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, - Contracts: pallet_contracts, - Xvm: pallet_xvm, - } -); - -pub(crate) const ALICE: AccountId = AccountId32::new([0u8; 32]); - -#[derive(Default)] -pub struct ExtBuilder; - -impl ExtBuilder { - #[allow(dead_code)] - pub fn build(self) -> TestExternalities { - TRANSACTED.with(|v| *v.borrow_mut() = None); - - 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/pallets/xvm/src/tests.rs b/pallets/xvm/src/tests.rs deleted file mode 100644 index f94a001a6c..0000000000 --- a/pallets/xvm/src/tests.rs +++ /dev/null @@ -1,195 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 mock::*; - -use frame_support::{assert_noop, assert_ok, weights::Weight}; -use parity_scale_codec::Encode; -use sp_core::H160; - -#[test] -fn calling_into_same_vm_is_not_allowed() { - ExtBuilder::default().build().execute_with(|| { - // Calling EVM from EVM - let evm_context = Context { - source_vm_id: VmId::Evm, - weight_limit: Weight::from_parts(1_000_000, 1_000_000), - }; - let evm_vm_id = VmId::Evm; - let evm_target = H160::repeat_byte(1).encode(); - let input = vec![1, 2, 3]; - let value = 1_000_000u128; - let evm_used_weight: Weight = weights::SubstrateWeight::::evm_call_overheads(); - assert_noop!( - Xvm::call( - evm_context, - evm_vm_id, - ALICE, - evm_target, - input.clone(), - value, - None - ), - CallFailure::error(SameVmCallDenied, evm_used_weight,), - ); - - // Calling WASM from WASM - let wasm_context = Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000, 1_000_000), - }; - let wasm_vm_id = VmId::Wasm; - let wasm_target = ALICE.encode(); - let wasm_used_weight: Weight = - weights::SubstrateWeight::::wasm_call_overheads(); - assert_noop!( - Xvm::call( - wasm_context, - wasm_vm_id, - ALICE, - wasm_target, - input, - value, - None - ), - CallFailure::error(SameVmCallDenied, wasm_used_weight,), - ); - }); -} - -#[test] -fn evm_call_fails_if_target_not_h160() { - ExtBuilder::default().build().execute_with(|| { - 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 input = vec![1; 65_536]; - let value = 1_000_000u128; - let used_weight: Weight = weights::SubstrateWeight::::evm_call_overheads(); - - assert_noop!( - Xvm::call( - context.clone(), - vm_id, - ALICE, - ALICE.encode(), - input.clone(), - value, - None - ), - CallFailure::revert(InvalidTarget, used_weight,), - ); - - assert_noop!( - Xvm::call(context, vm_id, ALICE, vec![1, 2, 3], input, value, None), - CallFailure::revert(InvalidTarget, used_weight,), - ); - }); -} - -#[test] -fn evm_call_fails_if_input_too_large() { - ExtBuilder::default().build().execute_with(|| { - 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 target = H160::repeat_byte(0xFF); - let value = 1_000_000u128; - let used_weight: Weight = weights::SubstrateWeight::::evm_call_overheads(); - - assert_noop!( - Xvm::call( - context, - vm_id, - ALICE, - target.encode(), - vec![1; 65_537], - value, - None - ), - CallFailure::revert(InputTooLarge, used_weight,), - ); - }); -} - -#[test] -fn evm_call_works() { - ExtBuilder::default().build().execute_with(|| { - 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 target = H160::repeat_byte(0xFF); - let input = vec![1; 65_536]; - let value = 1_000_000u128; - - assert_ok!(Xvm::call( - context, - vm_id, - ALICE, - target.encode(), - input.clone(), - value, - None - )); - let source = Decode::decode( - &mut hex::decode("f0bd9ffde7f9f4394d8cc1d86bf24d87e5d5a9a9") - .expect("invalid source hex") - .as_ref(), - ) - .expect("invalid source"); - MockEthereumTransact::assert_transacted( - source, - CheckedEthereumTx { - gas_limit: U256::from(246000), - target: H160::repeat_byte(0xFF), - value: U256::from(value), - input: EthereumTxInput::try_from(input).expect("input too large"), - maybe_access_list: None, - }, - ); - }); -} - -#[test] -fn wasm_call_fails_if_invalid_target() { - ExtBuilder::default().build().execute_with(|| { - 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 target = vec![1, 2, 3]; - let input = vec![1, 2, 3]; - let value = 1_000_000u128; - let used_weight: Weight = weights::SubstrateWeight::::wasm_call_overheads(); - - assert_noop!( - Xvm::call(context, vm_id, ALICE, target.encode(), input, value, None), - CallFailure::revert(InvalidTarget, used_weight,), - ); - }); -} diff --git a/pallets/xvm/src/weights.rs b/pallets/xvm/src/weights.rs deleted file mode 100644 index bdf5ae3e09..0000000000 --- a/pallets/xvm/src/weights.rs +++ /dev/null @@ -1,90 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 . - -//! Autogenerated weights for pallet_xvm -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/astar-collator -// benchmark -// pallet -// --chain=shibuya-dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_xvm -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./benchmark-results/xvm_weights.rs -// --template=./scripts/templates/weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for pallet_xvm. -pub trait WeightInfo { - fn evm_call_overheads() -> Weight; - fn wasm_call_overheads() -> Weight; -} - -/// Weights for pallet_xvm using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - fn evm_call_overheads() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 730_000 picoseconds. - Weight::from_parts(754_000, 0) - } - fn wasm_call_overheads() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 309_000 picoseconds. - Weight::from_parts(347_000, 0) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - fn evm_call_overheads() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 730_000 picoseconds. - Weight::from_parts(754_000, 0) - } - fn wasm_call_overheads() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 309_000 picoseconds. - Weight::from_parts(347_000, 0) - } -} diff --git a/precompiles/xvm/Cargo.toml b/precompiles/xvm/Cargo.toml deleted file mode 100644 index 2c50aa18aa..0000000000 --- a/precompiles/xvm/Cargo.toml +++ /dev/null @@ -1,61 +0,0 @@ -[package] -name = "pallet-evm-precompile-xvm" -description = "Cross-VM call support for EVM." -version = "0.1.1" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -hex = { workspace = true } -log = { workspace = true } -num_enum = { workspace = true } -precompile-utils = { workspace = true } - -# Substrate -frame-support = { workspace = true } -frame-system = { workspace = true } -parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } -sp-core = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } -sp-std = { workspace = true } - -# Frontier -fp-evm = { workspace = true } -pallet-evm = { workspace = true } - -# Astar -astar-primitives = { workspace = true } - -[dev-dependencies] -derive_more = { workspace = true } -hex-literal = { workspace = true } -scale-info = { workspace = true } -serde = { workspace = true } - -precompile-utils = { workspace = true, features = ["testing"] } - -pallet-balances = { workspace = true, features = ["std"] } -pallet-timestamp = { workspace = true } -sp-runtime = { workspace = true } - -[features] -default = ["std"] -std = [ - "parity-scale-codec/std", - "fp-evm/std", - "frame-support/std", - "frame-system/std", - "pallet-evm/std", - "precompile-utils/std", - "sp-core/std", - "sp-std/std", - "sp-io/std", - "sp-runtime/std", - "astar-primitives/std", - "hex/std", - "log/std", - "num_enum/std", -] diff --git a/precompiles/xvm/evm_sdk/XVM.sol b/precompiles/xvm/evm_sdk/XVM.sol deleted file mode 100644 index b54e5da717..0000000000 --- a/precompiles/xvm/evm_sdk/XVM.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity ^0.8.0; - -/** - * @title XVM interface. - */ -interface XVM { - /** - * @dev Execute external VM call - * @param vm_id - target VM id - * @param to - call recipient - * @param input - SCALE-encoded call arguments - * @param value - value to transfer - * @param storage_deposit_limit - storage deposit limit, use 0 for unlimited. - * @return success - operation outcome - * @return data - output data if successful, error data on error - */ - function xvm_call( - uint8 vm_id, - bytes calldata to, - bytes calldata input, - uint256 value, - uint256 storage_deposit_limit - ) external payable returns (bool success, bytes memory data); -} diff --git a/precompiles/xvm/evm_sdk/flipper.sol b/precompiles/xvm/evm_sdk/flipper.sol deleted file mode 100644 index 058f649baa..0000000000 --- a/precompiles/xvm/evm_sdk/flipper.sol +++ /dev/null @@ -1,19 +0,0 @@ -pragma solidity ^0.8.0; - -interface XVM { - function xvm_call( - uint8 vm_id, - bytes calldata to, - bytes calldata input, - uint256 value - ) external payable returns (bool success, bytes memory data); -} - -library Flipper { - const XVM XVM_PRECOMPILE = XVM(0x0000000000000000000000000000000000005005); - - function flip(bytes to) { - bytes input = "0xcafecafe"; - XVM_PRECOMPILE.xvm_call(0x1F, to, input, 1000000); - } -} diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs deleted file mode 100644 index 3bb538009b..0000000000 --- a/precompiles/xvm/src/lib.rs +++ /dev/null @@ -1,145 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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_attr(not(feature = "std"), no_std)] - -extern crate alloc; -use alloc::format; - -use astar_primitives::xvm::{Context, FailureReason, VmId, XvmCall}; -use fp_evm::{ExitRevert, PrecompileFailure, PrecompileHandle}; -use pallet_evm::{AddressMapping, GasWeightMapping}; -use sp_core::U256; -use sp_runtime::traits::Dispatchable; -use sp_std::marker::PhantomData; - -use precompile_utils::prelude::*; -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -// The selector on EVM revert, calculated by: `Keccak256::digest(b"Error(string)")[..4]` -const EVM_ERROR_MSG_SELECTOR: [u8; 4] = [8, 195, 121, 160]; - -/// A precompile that expose XVM related functions. -pub struct XvmPrecompile(PhantomData<(T, XC)>); - -#[precompile_utils::precompile] -impl XvmPrecompile -where - R: pallet_evm::Config, - <::RuntimeCall as Dispatchable>::RuntimeOrigin: - From>, - XC: XvmCall, -{ - #[precompile::public("xvm_call(uint8,bytes,bytes,uint256,uint256)")] - fn xvm_call( - handle: &mut impl PrecompileHandle, - vm_id: u8, - call_to: UnboundedBytes, - call_input: UnboundedBytes, - value: U256, - storage_deposit_limit: U256, - ) -> EvmResult<(bool, UnboundedBytes)> { - let vm_id = vm_id.try_into().map_err(|_| revert("invalid vm id"))?; - - let mut gas_limit = handle.remaining_gas(); - // If user specified a gas limit, make sure it's not exceeded. - if let Some(user_limit) = handle.gas_limit() { - gas_limit = gas_limit.min(user_limit); - } - let weight_limit = R::GasWeightMapping::gas_to_weight(gas_limit, true); - let xvm_context = Context { - source_vm_id: VmId::Evm, - weight_limit, - }; - - let call_to = call_to.into(); - let call_input = call_input.into(); - let value = value.try_into().map_err(|_| revert("value overflow"))?; - let storage_deposit_limit: u128 = storage_deposit_limit - .try_into() - .map_err(|_| revert("value overflow"))?; - - let limit = { - if storage_deposit_limit == 0 { - None - } else { - Some(storage_deposit_limit) - } - }; - - let from = R::AddressMapping::into_account_id(handle.context().caller); - - log::trace!( - target: "xvm-precompile::xvm_call", - "vm_id: {:?}, from: {:?}, call_to: {:?}, call_input: {:?}, value: {:?}, limit: {:?}", vm_id, from, call_to, call_input, value, limit - ); - let call_result = XC::call(xvm_context, vm_id, from, call_to, call_input, value, limit); - - let used_weight = match &call_result { - Ok(s) => s.used_weight, - Err(f) => f.used_weight, - }; - handle.record_cost(R::GasWeightMapping::weight_to_gas(used_weight))?; - handle.record_external_cost( - Some(used_weight.ref_time()), - Some(used_weight.proof_size()), - None, - )?; - - match call_result { - Ok(success) => { - log::trace!( - target: "xvm-precompile::xvm_call", - "success: {:?}", success - ); - - Ok((true, success.output.into())) - } - - Err(failure) => { - log::trace!( - target: "xvm-precompile::xvm_call", - "failure: {:?}", failure - ); - - // On `FailureReason::Error` cases, use `revert` instead of `error` to - // allow error details propagate to caller. EVM implementation always reverts, - // no matter which one is used. - let message = match failure.reason { - FailureReason::Revert(failure_revert) => { - format!("{:?}", failure_revert) - } - FailureReason::Error(failure_error) => { - format!("{:?}", failure_error) - } - }; - let data = solidity::encode_with_selector( - u32::from_be_bytes(EVM_ERROR_MSG_SELECTOR), - UnboundedBytes::from(message.into_bytes()), - ); - Err(PrecompileFailure::Revert { - exit_status: ExitRevert::Reverted, - output: data, - }) - } - } - } -} diff --git a/precompiles/xvm/src/mock.rs b/precompiles/xvm/src/mock.rs deleted file mode 100644 index a9228843f8..0000000000 --- a/precompiles/xvm/src/mock.rs +++ /dev/null @@ -1,323 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 . - -//! Testing utilities. - -use super::*; - -use fp_evm::{IsPrecompileResult, Precompile}; -use frame_support::{ - construct_runtime, ensure, parameter_types, - traits::{ConstU32, ConstU64, Everything}, - weights::Weight, -}; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; - -use pallet_evm::{ - AddressMapping, EnsureAddressNever, EnsureAddressRoot, PrecompileResult, PrecompileSet, -}; -use sp_core::{H160, H256}; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; -use sp_std::cell::RefCell; - -use astar_primitives::xvm::{ - CallFailure, CallOutput, CallResult, FailureError::*, FailureRevert::*, -}; - -pub type AccountId = TestAccount; -pub type Balance = u128; -pub type Block = frame_system::mocking::MockBlock; - -pub const PRECOMPILE_ADDRESS: H160 = H160::repeat_byte(0x7B); - -#[derive( - Eq, - PartialEq, - Ord, - PartialOrd, - Clone, - Encode, - Decode, - Debug, - MaxEncodedLen, - Serialize, - Deserialize, - derive_more::Display, - TypeInfo, -)] -pub enum TestAccount { - Alice, - Bob, - Charlie, - Bogus, - Precompile, -} - -impl Default for TestAccount { - fn default() -> Self { - Self::Alice - } -} - -impl AddressMapping for TestAccount { - fn into_account_id(h160_account: H160) -> TestAccount { - match h160_account { - a if a == H160::repeat_byte(0xAA) => Self::Alice, - a if a == H160::repeat_byte(0xBB) => Self::Bob, - a if a == H160::repeat_byte(0xCC) => Self::Charlie, - a if a == PRECOMPILE_ADDRESS => Self::Precompile, - _ => Self::Bogus, - } - } -} - -impl From for TestAccount { - fn from(x: H160) -> TestAccount { - TestAccount::into_account_id(x) - } -} - -impl From for H160 { - fn from(value: TestAccount) -> H160 { - match value { - TestAccount::Alice => H160::repeat_byte(0xAA), - TestAccount::Bob => H160::repeat_byte(0xBB), - TestAccount::Charlie => H160::repeat_byte(0xCC), - TestAccount::Precompile => PRECOMPILE_ADDRESS, - TestAccount::Bogus => Default::default(), - } - } -} - -impl From for [u8; 32] { - fn from(value: TestAccount) -> [u8; 32] { - match value { - TestAccount::Alice => [0xAA; 32], - TestAccount::Bob => [0xBB; 32], - TestAccount::Charlie => [0xCC; 32], - _ => Default::default(), - } - } -} - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = Everything; - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Block = Block; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type SS58Prefix = SS58Prefix; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - type RuntimeTask = RuntimeTask; - type SingleBlockMigrations = (); - type MultiBlockMigrator = (); - type PreInherents = (); - type PostInherents = (); - type PostTransactions = (); -} - -#[derive(Debug, Clone, Copy)] -pub struct TestPrecompileSet(PhantomData); - -impl PrecompileSet for TestPrecompileSet -where - R: pallet_evm::Config, - XvmPrecompile: Precompile, -{ - fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { - match handle.code_address() { - a if a == PRECOMPILE_ADDRESS => { - Some(XvmPrecompile::::execute(handle)) - } - _ => None, - } - } - - fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { - IsPrecompileResult::Answer { - is_precompile: address == PRECOMPILE_ADDRESS, - extra_cost: 0, - } - } -} - -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = (); -} - -parameter_types! { - pub const ExistentialDeposit: u128 = 1; -} - -impl pallet_balances::Config for Runtime { - type MaxReserves = (); - type ReserveIdentifier = (); - type MaxLocks = (); - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = (); - type RuntimeFreezeReason = (); - type MaxFreezes = ConstU32<0>; -} - -parameter_types! { - pub const PrecompilesValue: TestPrecompileSet = - TestPrecompileSet(PhantomData); - pub WeightPerGas: Weight = Weight::from_parts(1, 0); -} - -pub type PrecompileCall = XvmPrecompileCall; - -impl pallet_evm::Config for Runtime { - type FeeCalculator = (); - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type WeightPerGas = WeightPerGas; - type CallOrigin = EnsureAddressRoot; - type WithdrawOrigin = EnsureAddressNever; - type AddressMapping = AccountId; - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; - type Runner = pallet_evm::runner::stack::Runner; - type PrecompilesType = TestPrecompileSet; - type PrecompilesValue = PrecompilesValue; - type Timestamp = Timestamp; - type ChainId = (); - type OnChargeTransaction = (); - type BlockGasLimit = (); - type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; - type FindAuthor = (); - type OnCreate = (); - type WeightInfo = (); - type GasLimitPovSizeRatio = ConstU64<4>; - type SuicideQuickClearLimit = ConstU32<0>; -} - -thread_local! { - static WEIGHT_LIMIT: RefCell = RefCell::new(Weight::zero()); -} - -pub(crate) struct WeightLimitCalledWith; -impl WeightLimitCalledWith { - pub(crate) fn get() -> Weight { - WEIGHT_LIMIT.with(|gas_limit| *gas_limit.borrow()) - } - - pub(crate) fn set(value: Weight) { - WEIGHT_LIMIT.with(|gas_limit| *gas_limit.borrow_mut() = value) - } - - pub(crate) fn reset() { - Self::set(Weight::zero()); - } -} - -pub struct MockXvmWithArgsCheck; -impl XvmCall for MockXvmWithArgsCheck { - fn call( - context: Context, - vm_id: VmId, - _source: AccountId, - target: Vec, - input: Vec, - _value: Balance, - _storage_deposit_limit: Option, - ) -> CallResult { - ensure!( - vm_id != VmId::Evm, - CallFailure::error(SameVmCallDenied, Weight::zero()) - ); - ensure!( - target.len() == 20, - CallFailure::revert(InvalidTarget, Weight::zero()), - ); - ensure!( - input.len() <= 1024, - CallFailure::revert(InputTooLarge, Weight::zero()), - ); - - WeightLimitCalledWith::set(context.weight_limit); - - Ok(CallOutput::new(vec![], Weight::zero())) - } -} - -// Configure a mock runtime to test the pallet. -construct_runtime!( - pub enum Runtime - { - System: frame_system, - Balances: pallet_balances, - Evm: pallet_evm, - Timestamp: pallet_timestamp, - } -); - -#[derive(Default)] -pub(crate) struct ExtBuilder; - -impl ExtBuilder { - pub(crate) fn build(self) -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default() - .build_storage() - .expect("Frame system builds valid default genesis config"); - - WeightLimitCalledWith::reset(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} diff --git a/precompiles/xvm/src/tests.rs b/precompiles/xvm/src/tests.rs deleted file mode 100644 index ee7d9541de..0000000000 --- a/precompiles/xvm/src/tests.rs +++ /dev/null @@ -1,128 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 crate::mock::*; -use crate::*; - -use precompile_utils::testing::*; - -fn precompiles() -> TestPrecompileSet { - PrecompilesValue::get() -} - -#[test] -fn wrong_argument_reverts() { - ExtBuilder::default().build().execute_with(|| { - precompiles() - .prepare_test( - TestAccount::Alice, - PRECOMPILE_ADDRESS, - solidity::encode_with_selector(PrecompileCall::xvm_call_selectors()[0], 42u32), - ) - .expect_no_logs() - .execute_reverts(|output| output == b"Expected at least 5 arguments"); - - precompiles() - .prepare_test( - TestAccount::Alice, - PRECOMPILE_ADDRESS, - PrecompileCall::xvm_call { - vm_id: 0.into(), - call_to: b"".into(), - call_input: b"".into(), - value: 1.into(), - storage_deposit_limit: 0.into(), - }, - ) - .expect_no_logs() - .execute_reverts(|output| output == b"invalid vm id"); - }) -} - -#[test] -fn correct_arguments_works() { - ExtBuilder::default().build().execute_with(|| { - precompiles() - .prepare_test( - TestAccount::Alice, - PRECOMPILE_ADDRESS, - PrecompileCall::xvm_call { - vm_id: 0x1Fu8.into(), - call_to: b"".into(), - call_input: hex::decode("0000000000000000000000000000000000000000") - .expect("invalid hex") - .into(), - value: 1.into(), - storage_deposit_limit: 0.into(), - }, - ) - .expect_no_logs() - .execute_some(); - }) -} - -#[test] -fn weight_limit_is_min_of_remaining_and_user_limit() { - ExtBuilder::default().build().execute_with(|| { - // The caller didn't set a limit. - precompiles() - .prepare_test( - TestAccount::Alice, - PRECOMPILE_ADDRESS, - PrecompileCall::xvm_call { - vm_id: 0x1Fu8.into(), - call_to: hex::decode("0000000000000000000000000000000000000000") - .expect("invalid hex") - .into(), - call_input: b"".into(), - value: 1.into(), - storage_deposit_limit: 0.into(), - }, - ) - .expect_no_logs() - .execute_some(); - assert_eq!( - WeightLimitCalledWith::get(), - ::GasWeightMapping::gas_to_weight(u64::MAX, true) - ); - - // The caller set a limit. - let gas_limit = 1_000; - precompiles() - .prepare_test( - TestAccount::Alice, - PRECOMPILE_ADDRESS, - PrecompileCall::xvm_call { - vm_id: 0x1Fu8.into(), - call_to: hex::decode("0000000000000000000000000000000000000000") - .expect("invalid hex") - .into(), - call_input: b"".into(), - value: 1.into(), - storage_deposit_limit: 0.into(), - }, - ) - .with_target_gas(gas_limit.into()) - .expect_no_logs() - .execute_some(); - assert_eq!( - WeightLimitCalledWith::get(), - ::GasWeightMapping::gas_to_weight(gas_limit, true) - ); - }); -} diff --git a/primitives/src/ethereum_checked.rs b/primitives/src/ethereum_checked.rs index e473277203..eeef9fff7a 100644 --- a/primitives/src/ethereum_checked.rs +++ b/primitives/src/ethereum_checked.rs @@ -23,14 +23,8 @@ use ethereum::{ AccessListItem, EIP1559Transaction, TransactionAction, TransactionV2 as Transaction, }; use ethereum_types::{H160, H256, U256}; -use fp_evm::CallInfo; -use frame_support::{ - dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, - pallet_prelude::*, - traits::ConstU32, - BoundedVec, -}; -use sp_std::{prelude::*, result::Result}; +use frame_support::{pallet_prelude::*, traits::ConstU32, BoundedVec}; +use sp_std::prelude::*; /// Max Ethereum tx input size: 65_536 bytes pub const MAX_ETHEREUM_TX_INPUT_SIZE: u32 = 2u32.pow(16); @@ -86,13 +80,3 @@ impl CheckedEthereumTx { fn dummy_rs() -> H256 { H256::from_low_u64_be(1u64) } - -/// Transact an checked Ethereum transaction. Similar to `pallet_ethereum::Transact` but -/// doesn't require tx signature. -pub trait CheckedEthereumTransact { - /// Transact an checked Ethereum transaction in XVM. - fn xvm_transact( - source: H160, - checked_tx: CheckedEthereumTx, - ) -> Result<(PostDispatchInfo, CallInfo), DispatchErrorWithPostInfo>; -} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 40f4239d0a..277c6a3915 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -26,9 +26,6 @@ pub mod xcm; /// Checked Ethereum transaction primitives. pub mod ethereum_checked; -/// XVM primitives. -pub mod xvm; - /// EVM primitives. pub mod evm; diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs deleted file mode 100644 index 830003a137..0000000000 --- a/primitives/src/xvm.rs +++ /dev/null @@ -1,172 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 crate::Balance; - -use frame_support::weights::Weight; -use parity_scale_codec::{Decode, Encode}; -use scale_info::TypeInfo; -use sp_runtime::RuntimeDebug; -use sp_std::{convert::TryFrom, prelude::*, result::Result}; - -/// Vm Id. -#[repr(u8)] -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum VmId { - Evm = 0x0F, - Wasm = 0x1F, -} - -impl TryFrom for VmId { - type Error = FailureReason; - - fn try_from(value: u8) -> Result { - if value == VmId::Evm as u8 { - Ok(VmId::Evm) - } else if value == VmId::Wasm as u8 { - Ok(VmId::Wasm) - } else { - Err(FailureReason::Error(FailureError::InvalidVmId)) - } - } -} - -/// XVM call info on success. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CallOutput { - /// Output of the call. - pub output: Vec, - /// Actual used weight. - pub used_weight: Weight, -} - -impl CallOutput { - /// Create a new `CallOutput`. - pub fn new(output: Vec, used_weight: Weight) -> Self { - Self { - output, - used_weight, - } - } -} - -/// XVM call failure. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CallFailure { - /// Failure reason. - pub reason: FailureReason, - /// Actual used weight. - pub used_weight: Weight, -} - -impl CallFailure { - /// Create a new `CallFailure` on revert. - pub fn revert(details: FailureRevert, used_weight: Weight) -> Self { - Self { - reason: FailureReason::Revert(details), - used_weight, - } - } - - /// Create a new `CallFailure` on error. - pub fn error(details: FailureError, used_weight: Weight) -> Self { - Self { - reason: FailureReason::Error(details), - used_weight, - } - } -} - -/// Failure reason of XVM calls. -/// -/// `Error` vs `Revert`: -/// - `Error` is for execution failed and the VM must stop. It maps to EVM -/// `ExitError/ExistFatal` and WASM `DispatchError`. -/// - `Revert` is for execution succeeded but the callee explicitly asked to -/// revert. It maps to EVM `ExitRevert` and WASM `REVERT` flag. It also includes -/// the case that wrong input was passed to XVM call, for instance invalid target, -/// as from VM/WASM perspective, it's an input guard condition failure. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum FailureReason { - /// XVM call failed with explicit revert. - Revert(FailureRevert), - /// XVM call failed with error. - Error(FailureError), -} - -/// Failure reason on revert. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum FailureRevert { - /// Target contract address is invalid. - InvalidTarget, - /// Input is too large. - InputTooLarge, - /// VM execution exit with revert. - VmRevert(Vec), -} - -/// Failure reason on error. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum FailureError { - /// Invalid VM id. - InvalidVmId, - /// Calling the contracts in the same VM is not allowed. - SameVmCallDenied, - /// Reentrance is not allowed. - ReentranceDenied, - /// The call failed with error on EVM or WASM execution. - VmError(Vec), - /// Out of gas. - OutOfGas, -} - -/// XVM call result. -pub type CallResult = Result; - -/// XVM context. -/// -/// Note this should be set by runtime, instead of passed by callers. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct Context { - /// The source VM of the call. - pub source_vm_id: VmId, - /// Max weight limit. - pub weight_limit: Weight, -} - -pub trait XvmCall { - /// Call a contract in XVM. - /// - /// Parameters: - /// - `context`: XVM context. - /// - `vm_id`: the VM Id of the target contract. - /// - `source`: Caller Id. - /// - `target`: Target contract address. - /// - `input`: call input data. - /// - `value`: value to transfer. - /// - `storage_deposit_limit`: storage deposit limit for wasm calls. - fn call( - context: Context, - vm_id: VmId, - source: AccountId, - target: Vec, - input: Vec, - value: Balance, - storage_deposit_limit: Option, - ) -> CallResult; -} diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index 1ac76bd3f9..0dbe366798 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -70,7 +70,6 @@ pallet-transaction-payment-rpc-runtime-api = { workspace = true } # Astar pallets astar-primitives = { workspace = true } pallet-chain-extension-unified-accounts = { workspace = true } -pallet-chain-extension-xvm = { workspace = true } pallet-collective-proxy = { workspace = true } pallet-dapp-staking-v3 = { workspace = true } pallet-dynamic-evm-base-fee = { workspace = true } @@ -80,11 +79,9 @@ pallet-evm-precompile-dispatch-lockdrop = { workspace = true } pallet-evm-precompile-sr25519 = { workspace = true } pallet-evm-precompile-substrate-ecdsa = { workspace = true } pallet-evm-precompile-unified-accounts = { workspace = true } -pallet-evm-precompile-xvm = { workspace = true } pallet-inflation = { workspace = true } pallet-static-price-provider = { workspace = true } pallet-unified-accounts = { workspace = true } -pallet-xvm = { workspace = true } dapp-staking-v3-runtime-api = { workspace = true } @@ -125,7 +122,6 @@ std = [ "pallet-membership/std", "pallet-balances/std", "pallet-contracts/std", - "pallet-chain-extension-xvm/std", "pallet-chain-extension-unified-accounts/std", "pallet-dapp-staking-v3/std", "dapp-staking-v3-runtime-api/std", @@ -146,7 +142,6 @@ std = [ "pallet-evm-precompile-sr25519/std", "pallet-evm-precompile-substrate-ecdsa/std", "pallet-evm-precompile-unified-accounts/std", - "pallet-evm-precompile-xvm/std", "pallet-evm-precompile-dispatch-lockdrop/std", "pallet-grandpa/std", "pallet-insecure-randomness-collective-flip/std", @@ -178,7 +173,6 @@ std = [ "frame-try-runtime/std", "frame-metadata-hash-extension/std", "pallet-scheduler/std", - "pallet-xvm/std", "pallet-unified-accounts/std", "pallet-ethereum-checked/std", "moonbeam-evm-tracer/std", @@ -229,7 +223,6 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", - "pallet-xvm/runtime-benchmarks", ] try-runtime = [ "fp-self-contained/try-runtime", @@ -253,7 +246,6 @@ try-runtime = [ "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", "pallet-vesting/try-runtime", - "pallet-xvm/try-runtime", "pallet-unified-accounts/try-runtime", "pallet-ethereum/try-runtime", "pallet-assets/try-runtime", diff --git a/runtime/local/src/chain_extensions.rs b/runtime/local/src/chain_extensions.rs index fd0a1e3e2c..b08131be29 100644 --- a/runtime/local/src/chain_extensions.rs +++ b/runtime/local/src/chain_extensions.rs @@ -16,21 +16,16 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -use super::{Runtime, UnifiedAccounts, Xvm}; +use super::{Runtime, UnifiedAccounts}; /// Registered WASM contracts chain extensions. pub use pallet_chain_extension_assets::AssetsExtension; use pallet_contracts::chain_extension::RegisteredChainExtension; pub use pallet_chain_extension_unified_accounts::UnifiedAccountsExtension; -pub use pallet_chain_extension_xvm::XvmExtension; // Following impls defines chain extension IDs. -impl RegisteredChainExtension for XvmExtension { - const ID: u16 = 01; -} - impl RegisteredChainExtension for AssetsExtension { const ID: u16 = 02; } @@ -39,8 +34,7 @@ impl RegisteredChainExtension for UnifiedAccountsExtension = ( +pub type LocalChainExtensions = ( AssetsExtension, UnifiedAccountsExtension, - XvmExtension, ); diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 23558e9095..e9bc2a3655 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -558,14 +558,11 @@ impl pallet_unified_accounts::Config for Runtime { } parameter_types! { - /// Equal to normal class dispatch weight limit. - pub XvmTxWeightLimit: Weight = NORMAL_DISPATCH_RATIO * Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, u64::MAX); pub ReservedXcmpWeight: Weight = Weight::zero(); } impl pallet_ethereum_checked::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; - type XvmTxWeightLimit = XvmTxWeightLimit; type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; type AddressMapper = UnifiedAccounts; @@ -573,13 +570,6 @@ impl pallet_ethereum_checked::Config for Runtime { type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; } -impl pallet_xvm::Config for Runtime { - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type AddressMapper = UnifiedAccounts; - type EthereumTransact = EthereumChecked; - type WeightInfo = pallet_xvm::weights::SubstrateWeight; -} - /// Current approximation of the gas/s consumption considering /// EVM execution over compiled WASM (on 4.4Ghz CPU). /// Given the 500ms Weight, from which 75% only are used for transactions, @@ -747,7 +737,7 @@ impl pallet_contracts::Config for Runtime { type CallStack = [pallet_contracts::Frame; 5]; type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = LocalChainExtensions; + type ChainExtension = LocalChainExtensions; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 123 * 1024 }>; @@ -1159,6 +1149,7 @@ construct_runtime!( Aura: pallet_aura = 43, Grandpa: pallet_grandpa = 44, + EVM: pallet_evm = 60, Ethereum: pallet_ethereum = 61, DynamicEvmBaseFee: pallet_dynamic_evm_base_fee = 62, @@ -1166,8 +1157,10 @@ construct_runtime!( UnifiedAccounts: pallet_unified_accounts = 65, Contracts: pallet_contracts = 70, + Preimage: pallet_preimage = 84, - Xvm: pallet_xvm = 90, + + // skip 90 - for runtimes consistency (pallet_xvm previously) // Governance Sudo: pallet_sudo = 99, diff --git a/runtime/local/src/precompiles.rs b/runtime/local/src/precompiles.rs index e8fa54a5c3..662d56cf14 100644 --- a/runtime/local/src/precompiles.rs +++ b/runtime/local/src/precompiles.rs @@ -35,7 +35,6 @@ use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripe use pallet_evm_precompile_sr25519::Sr25519Precompile; use pallet_evm_precompile_substrate_ecdsa::SubstrateEcdsaPrecompile; use pallet_evm_precompile_unified_accounts::UnifiedAccountsPrecompile; -use pallet_evm_precompile_xvm::XvmPrecompile; use precompile_utils::precompile_set::*; use sp_std::fmt::Debug; @@ -133,11 +132,7 @@ pub type LocalPrecompilesSetAt = ( (CallableByContract, CallableByPrecompile), >, // skip 20484 for xcm precompile - PrecompileAt< - AddressU64<20485>, - XvmPrecompile>, - (CallableByContract, CallableByPrecompile), - >, + // Skipping 20485 to make sure all network have consistent precompiles address PrecompileAt< AddressU64<20486>, UnifiedAccountsPrecompile, diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index 6bb257a8da..a4a80a48f4 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -105,7 +105,6 @@ orml-xtokens = { workspace = true } astar-primitives = { workspace = true } astar-xcm-benchmarks = { workspace = true, optional = true } pallet-chain-extension-unified-accounts = { workspace = true } -pallet-chain-extension-xvm = { workspace = true } pallet-collator-selection = { workspace = true } pallet-dapp-staking-v3 = { workspace = true } pallet-dynamic-evm-base-fee = { workspace = true } @@ -117,14 +116,12 @@ pallet-evm-precompile-sr25519 = { workspace = true } pallet-evm-precompile-substrate-ecdsa = { workspace = true } pallet-evm-precompile-unified-accounts = { workspace = true } pallet-evm-precompile-xcm = { workspace = true } -pallet-evm-precompile-xvm = { workspace = true } pallet-inflation = { workspace = true } pallet-price-aggregator = { workspace = true } pallet-unified-accounts = { workspace = true } pallet-xc-asset-config = { workspace = true } pallet-xcm = { workspace = true } pallet-xcm-benchmarks = { workspace = true, optional = true } -pallet-xvm = { workspace = true } dapp-staking-v3-runtime-api = { workspace = true } @@ -183,7 +180,6 @@ std = [ "pallet-assets/std", "pallet-balances/std", "pallet-contracts/std", - "pallet-chain-extension-xvm/std", "pallet-chain-extension-unified-accounts/std", "pallet-dynamic-evm-base-fee/std", "pallet-ethereum/std", @@ -202,7 +198,6 @@ std = [ "pallet-evm-precompile-substrate-ecdsa/std", "pallet-evm-precompile-assets-erc20/std", "pallet-evm-precompile-xcm/std", - "pallet-evm-precompile-xvm/std", "pallet-evm-precompile-unified-accounts/std", "pallet-evm-precompile-dispatch-lockdrop/std", "pallet-dapp-staking-v3/std", @@ -225,7 +220,6 @@ std = [ "pallet-transaction-payment-rpc-runtime-api/std", "pallet-xcm/std", "pallet-xc-asset-config/std", - "pallet-xvm/std", "pallet-unified-accounts/std", "pallet-ethereum-checked/std", "pallet-scheduler/std", @@ -291,7 +285,6 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", "pallet-unified-accounts/runtime-benchmarks", - "pallet-xvm/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", "astar-primitives/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -366,7 +359,6 @@ try-runtime = [ "cumulus-pallet-xcm/try-runtime", "cumulus-pallet-xcmp-queue/try-runtime", "parachain-info/try-runtime", - "pallet-xvm/try-runtime", "pallet-preimage/try-runtime", "pallet-dynamic-evm-base-fee/try-runtime", "pallet-evm/try-runtime", diff --git a/runtime/shibuya/src/chain_extensions.rs b/runtime/shibuya/src/chain_extensions.rs index fe13982798..dae721e8e5 100644 --- a/runtime/shibuya/src/chain_extensions.rs +++ b/runtime/shibuya/src/chain_extensions.rs @@ -16,21 +16,16 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -use super::{Runtime, UnifiedAccounts, Xvm}; +use super::{Runtime, UnifiedAccounts}; /// Registered WASM contracts chain extensions. pub use pallet_chain_extension_assets::AssetsExtension; use pallet_contracts::chain_extension::RegisteredChainExtension; pub use pallet_chain_extension_unified_accounts::UnifiedAccountsExtension; -pub use pallet_chain_extension_xvm::XvmExtension; // Following impls defines chain extension IDs. -impl RegisteredChainExtension for XvmExtension { - const ID: u16 = 01; -} - impl RegisteredChainExtension for AssetsExtension { const ID: u16 = 02; } @@ -39,8 +34,7 @@ impl RegisteredChainExtension for UnifiedAccountsExtension = ( +pub type ShibuyaChainExtensions = ( AssetsExtension, UnifiedAccountsExtension, - XvmExtension, ); diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 47b925d259..e00ad7bb26 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -737,7 +737,7 @@ impl pallet_contracts::Config for Runtime { type CallStack = [pallet_contracts::Frame; 5]; type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = ShibuyaChainExtensions; + type ChainExtension = ShibuyaChainExtensions; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 123 * 1024 }>; @@ -863,14 +863,8 @@ impl pallet_dynamic_evm_base_fee::Config for Runtime { type WeightInfo = pallet_dynamic_evm_base_fee::weights::SubstrateWeight; } -parameter_types! { - /// Equal to normal class dispatch weight limit. - pub XvmTxWeightLimit: Weight = NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT; -} - impl pallet_ethereum_checked::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; - type XvmTxWeightLimit = XvmTxWeightLimit; type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; type AddressMapper = UnifiedAccounts; @@ -878,13 +872,6 @@ impl pallet_ethereum_checked::Config for Runtime { type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; } -impl pallet_xvm::Config for Runtime { - type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type AddressMapper = UnifiedAccounts; - type EthereumTransact = EthereumChecked; - type WeightInfo = pallet_xvm::weights::SubstrateWeight; -} - /// Current approximation of the gas/s consumption considering /// EVM execution over compiled WASM (on 4.4Ghz CPU). /// Given the 500ms Weight, from which 75% only are used for transactions, @@ -1560,7 +1547,7 @@ construct_runtime!( Preimage: pallet_preimage = 84, - Xvm: pallet_xvm = 90, + // skip 90 - pallet_xvm previously // Governance Sudo: pallet_sudo = 99, @@ -1706,7 +1693,6 @@ mod benches { [pallet_collator_selection, CollatorSelection] [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_ethereum_checked, EthereumChecked] - [pallet_xvm, Xvm] [pallet_dynamic_evm_base_fee, DynamicEvmBaseFee] [pallet_unified_accounts, UnifiedAccounts] [xcm_benchmarks_generic, XcmGeneric] diff --git a/runtime/shibuya/src/precompiles.rs b/runtime/shibuya/src/precompiles.rs index 917d3fca94..5fb0d3e256 100644 --- a/runtime/shibuya/src/precompiles.rs +++ b/runtime/shibuya/src/precompiles.rs @@ -18,7 +18,7 @@ //! The Astar Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm. -use crate::{RuntimeCall, UnifiedAccounts, Xvm}; +use crate::{RuntimeCall, UnifiedAccounts}; use astar_primitives::precompiles::DispatchFilterValidate; use frame_support::traits::ConstU32; use frame_support::{parameter_types, traits::Contains}; @@ -36,7 +36,6 @@ use pallet_evm_precompile_sr25519::Sr25519Precompile; use pallet_evm_precompile_substrate_ecdsa::SubstrateEcdsaPrecompile; use pallet_evm_precompile_unified_accounts::UnifiedAccountsPrecompile; use pallet_evm_precompile_xcm::XcmPrecompile; -use pallet_evm_precompile_xvm::XvmPrecompile; use precompile_utils::precompile_set::*; use sp_std::fmt::Debug; @@ -144,11 +143,7 @@ pub type ShibuyaPrecompilesSetAt = ( CallableByPrecompile, ), >, - PrecompileAt< - AddressU64<20485>, - XvmPrecompile, - (CallableByContract, CallableByPrecompile), - >, + // Skipping 20485 to make sure all network have consistent precompiles address PrecompileAt< AddressU64<20486>, UnifiedAccountsPrecompile, diff --git a/tests/ink-contracts/README.md b/tests/ink-contracts/README.md index 24b9891009..41a45de469 100644 --- a/tests/ink-contracts/README.md +++ b/tests/ink-contracts/README.md @@ -2,7 +2,7 @@ This directory contains Ink! contracts which are used in integration tests. -`.wasm` files in this directory are used by `pallet-contracts` scenarios, typically `src/xvm.rs`. The json +`.wasm` files in this directory are used by `pallet-contracts` scenarios. The json files are for informational purposes only and are not consumed by the tests. The source code for the contracts can be found at https://github.com/AstarNetwork/ink-test-contracts diff --git a/tests/ink-contracts/call_xvm_payable.json b/tests/ink-contracts/call_xvm_payable.json deleted file mode 100644 index 774d549f04..0000000000 --- a/tests/ink-contracts/call_xvm_payable.json +++ /dev/null @@ -1,438 +0,0 @@ -{ - "source": { - "hash": "0x2f161d6093ea4272bde71b8e3c8e81efbd7b15bc3b482ebd8bac2f3f43950af9", - "language": "ink! 4.2.1", - "compiler": "rustc 1.68.0-nightly", - "build_info": { - "build_mode": "Debug", - "cargo_contract_version": "3.0.1", - "rust_toolchain": "nightly-aarch64-apple-darwin", - "wasm_opt_settings": { - "keep_debug_symbols": false, - "optimization_passes": "Z" - } - } - }, - "contract": { - "name": "call_xvm_payable", - "version": "0.1.0", - "authors": [ - "[your_name] <[your_email]>" - ] - }, - "spec": { - "constructors": [ - { - "args": [], - "default": false, - "docs": [], - "label": "new", - "payable": false, - "returnType": { - "displayName": [ - "ink_primitives", - "ConstructorResult" - ], - "type": 0 - }, - "selector": "0x9bae9d5e" - } - ], - "docs": [], - "environment": { - "accountId": { - "displayName": [ - "AccountId" - ], - "type": 8 - }, - "balance": { - "displayName": [ - "Balance" - ], - "type": 10 - }, - "blockNumber": { - "displayName": [ - "BlockNumber" - ], - "type": 13 - }, - "chainExtension": { - "displayName": [ - "ChainExtension" - ], - "type": 14 - }, - "hash": { - "displayName": [ - "Hash" - ], - "type": 11 - }, - "maxEventTopics": 4, - "timestamp": { - "displayName": [ - "Timestamp" - ], - "type": 12 - } - }, - "events": [], - "lang_error": { - "displayName": [ - "ink", - "LangError" - ], - "type": 2 - }, - "messages": [ - { - "args": [ - { - "label": "target", - "type": { - "displayName": [ - "Vec" - ], - "type": 3 - } - }, - { - "label": "input", - "type": { - "displayName": [ - "Vec" - ], - "type": 3 - } - } - ], - "default": false, - "docs": [], - "label": "call_xvm_payable", - "mutates": false, - "payable": true, - "returnType": { - "displayName": [ - "ink", - "MessageResult" - ], - "type": 5 - }, - "selector": "0x0000002a" - } - ] - }, - "storage": { - "root": { - "layout": { - "struct": { - "fields": [], - "name": "CallXvmPayable" - } - }, - "root_key": "0x00000000" - } - }, - "types": [ - { - "id": 0, - "type": { - "def": { - "variant": { - "variants": [ - { - "fields": [ - { - "type": 1 - } - ], - "index": 0, - "name": "Ok" - }, - { - "fields": [ - { - "type": 2 - } - ], - "index": 1, - "name": "Err" - } - ] - } - }, - "params": [ - { - "name": "T", - "type": 1 - }, - { - "name": "E", - "type": 2 - } - ], - "path": [ - "Result" - ] - } - }, - { - "id": 1, - "type": { - "def": { - "tuple": [] - } - } - }, - { - "id": 2, - "type": { - "def": { - "variant": { - "variants": [ - { - "index": 1, - "name": "CouldNotReadInput" - } - ] - } - }, - "path": [ - "ink_primitives", - "LangError" - ] - } - }, - { - "id": 3, - "type": { - "def": { - "sequence": { - "type": 4 - } - } - } - }, - { - "id": 4, - "type": { - "def": { - "primitive": "u8" - } - } - }, - { - "id": 5, - "type": { - "def": { - "variant": { - "variants": [ - { - "fields": [ - { - "type": 6 - } - ], - "index": 0, - "name": "Ok" - }, - { - "fields": [ - { - "type": 2 - } - ], - "index": 1, - "name": "Err" - } - ] - } - }, - "params": [ - { - "name": "T", - "type": 6 - }, - { - "name": "E", - "type": 2 - } - ], - "path": [ - "Result" - ] - } - }, - { - "id": 6, - "type": { - "def": { - "variant": { - "variants": [ - { - "fields": [ - { - "type": 3 - } - ], - "index": 0, - "name": "Ok" - }, - { - "fields": [ - { - "type": 7 - } - ], - "index": 1, - "name": "Err" - } - ] - } - }, - "params": [ - { - "name": "T", - "type": 3 - }, - { - "name": "E", - "type": 7 - } - ], - "path": [ - "Result" - ] - } - }, - { - "id": 7, - "type": { - "def": { - "variant": { - "variants": [ - { - "index": 0, - "name": "InvalidVmId" - }, - { - "index": 1, - "name": "SameVmCallNotAllowed" - }, - { - "index": 2, - "name": "InvalidTarget" - }, - { - "index": 3, - "name": "InputTooLarge" - }, - { - "index": 4, - "name": "BadOrigin" - }, - { - "index": 5, - "name": "ExecutionFailed" - } - ] - } - }, - "path": [ - "call_xvm_payable", - "XvmCallError" - ] - } - }, - { - "id": 8, - "type": { - "def": { - "composite": { - "fields": [ - { - "type": 9, - "typeName": "[u8; 32]" - } - ] - } - }, - "path": [ - "ink_primitives", - "types", - "AccountId" - ] - } - }, - { - "id": 9, - "type": { - "def": { - "array": { - "len": 32, - "type": 4 - } - } - } - }, - { - "id": 10, - "type": { - "def": { - "primitive": "u128" - } - } - }, - { - "id": 11, - "type": { - "def": { - "composite": { - "fields": [ - { - "type": 9, - "typeName": "[u8; 32]" - } - ] - } - }, - "path": [ - "ink_primitives", - "types", - "Hash" - ] - } - }, - { - "id": 12, - "type": { - "def": { - "primitive": "u64" - } - } - }, - { - "id": 13, - "type": { - "def": { - "primitive": "u32" - } - } - }, - { - "id": 14, - "type": { - "def": { - "variant": {} - }, - "path": [ - "call_xvm_payable", - "XvmCall" - ] - } - } - ], - "version": "4" -} \ No newline at end of file diff --git a/tests/ink-contracts/call_xvm_payable.wasm b/tests/ink-contracts/call_xvm_payable.wasm deleted file mode 100644 index 9d2b538e7c..0000000000 Binary files a/tests/ink-contracts/call_xvm_payable.wasm and /dev/null differ diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index 354c48c2e2..b66c0ecf76 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -29,9 +29,6 @@ mod proxy; #[cfg(any(feature = "shibuya", feature = "shiden", feature = "astar"))] mod assets; -#[cfg(feature = "shibuya")] -mod xvm; - #[cfg(any(feature = "shibuya", feature = "shiden", feature = "astar"))] mod dispatch_precompile_filter; diff --git a/tests/integration/src/xvm.rs b/tests/integration/src/xvm.rs deleted file mode 100644 index 5439f363c1..0000000000 --- a/tests/integration/src/xvm.rs +++ /dev/null @@ -1,816 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 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 crate::setup::*; - -use sha3::{Digest, Keccak256}; - -use astar_primitives::{ - ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx, EthereumTxInput}, - xvm::{CallFailure, Context, FailureError, FailureReason, FailureRevert, VmId, XvmCall}, -}; -use fp_evm::{ExecutionInfoV2, ExitReason, ExitRevert}; -use frame_support::{dispatch::PostDispatchInfo, traits::Currency, weights::Weight}; -use pallet_contracts::ExecReturnValue; -use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; -use pallet_contracts_uapi::ReturnFlags; -use parity_scale_codec::Encode; -use precompile_utils::{prelude::*, solidity}; -use sp_runtime::MultiAddress; - -// Build EVM revert message error data. -fn evm_revert_message_error(msg: &str) -> Vec { - let hash = &Keccak256::digest(b"Error(string)")[..4]; - let selector = u32::from_be_bytes([hash[0], hash[1], hash[2], hash[3]]); - - solidity::encode_with_selector(selector, UnboundedBytes::from(msg.to_owned().into_bytes())) -} - -/* - -pragma solidity >=0.8.2 <0.9.0; - -contract Payable { - address payable public owner; - - constructor() payable { - owner = payable(msg.sender); - } - - // 0xd0e30db0 - function deposit() public payable {} - - // 0x3ccfd60b - function withdraw() public { - uint amount = address(this).balance; - (bool success, ) = owner.call{value: amount}(""); - require(success, "Failed to withdraw Ether"); - } -} - - */ -const EVM_PAYABLE: &str = "6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102d6806100536000396000f3fe6080604052600436106100345760003560e01c80633ccfd60b146100395780638da5cb5b14610050578063d0e30db01461007b575b600080fd5b34801561004557600080fd5b5061004e610085565b005b34801561005c57600080fd5b5061006561015b565b60405161007291906101c2565b60405180910390f35b61008361017f565b005b600047905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16826040516100d19061020e565b60006040518083038185875af1925050503d806000811461010e576040519150601f19603f3d011682016040523d82523d6000602084013e610113565b606091505b5050905080610157576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014e90610280565b60405180910390fd5b5050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101ac82610181565b9050919050565b6101bc816101a1565b82525050565b60006020820190506101d760008301846101b3565b92915050565b600081905092915050565b50565b60006101f86000836101dd565b9150610203826101e8565b600082019050919050565b6000610219826101eb565b9150819050919050565b600082825260208201905092915050565b7f4661696c656420746f2077697468647261772045746865720000000000000000600082015250565b600061026a601883610223565b915061027582610234565b602082019050919050565b600060208201905081810360008301526102998161025d565b905091905056fea2646970667358221220bd8883b6a524d12ac9c29f105fdd1a0221a0436a79002f2a04e69d252596a62a64736f6c63430008120033"; - -/* WASM payable: - -#![cfg_attr(not(feature = "std"), no_std, no_main)] - -#[ink::contract] -mod payable { - #[ink(storage)] - pub struct Payable {} - - impl Payable { - #[ink(constructor)] - pub fn new() -> Self { - Self {} - } - - #[ink(message, payable, selector = 42)] - pub fn deposit(&self) {} - } -} - -*/ -const WASM_PAYABLE_NAME: &'static str = "payable"; - -/* Call WASM payable: - -pragma solidity >=0.8.2 <0.9.0; - -interface XVM { - function xvm_call( - uint8 vm_id, - bytes calldata to, - bytes calldata input, - uint256 value, - uint256 storage_deposit_limit - ) external payable returns (bool success, bytes memory data); -} - -contract CallXVMPayble { - function call_xvm_payable(bytes calldata to, bytes calldata input, uint256 value) external payable returns (bool success, bytes memory data) { - // Call with unlimited storage deposit limit. - return XVM(0x0000000000000000000000000000000000005005).xvm_call(0x1F, to, input, value, 0); - } -} - - */ -const CALL_WASM_PAYBLE: &str = "608060405234801561001057600080fd5b50610632806100206000396000f3fe60806040526004361061001e5760003560e01c80634012b91414610023575b600080fd5b61003d600480360381019061003891906101a6565b610054565b60405161004b9291906102e6565b60405180910390f35b6000606061500573ffffffffffffffffffffffffffffffffffffffff1663acc57c7e601f898989898960006040518863ffffffff1660e01b81526004016100a197969594939291906103ee565b6000604051808303816000875af11580156100c0573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906100e991906105a0565b915091509550959350505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126101305761012f61010b565b5b8235905067ffffffffffffffff81111561014d5761014c610110565b5b60208301915083600182028301111561016957610168610115565b5b9250929050565b6000819050919050565b61018381610170565b811461018e57600080fd5b50565b6000813590506101a08161017a565b92915050565b6000806000806000606086880312156101c2576101c1610101565b5b600086013567ffffffffffffffff8111156101e0576101df610106565b5b6101ec8882890161011a565b9550955050602086013567ffffffffffffffff81111561020f5761020e610106565b5b61021b8882890161011a565b9350935050604061022e88828901610191565b9150509295509295909350565b60008115159050919050565b6102508161023b565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610290578082015181840152602081019050610275565b60008484015250505050565b6000601f19601f8301169050919050565b60006102b882610256565b6102c28185610261565b93506102d2818560208601610272565b6102db8161029c565b840191505092915050565b60006040820190506102fb6000830185610247565b818103602083015261030d81846102ad565b90509392505050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b600061035261034d61034884610316565b61032d565b610320565b9050919050565b61036281610337565b82525050565b82818337600083830152505050565b60006103838385610261565b9350610390838584610368565b6103998361029c565b840190509392505050565b6103ad81610170565b82525050565b6000819050919050565b60006103d86103d36103ce846103b3565b61032d565b610170565b9050919050565b6103e8816103bd565b82525050565b600060a082019050610403600083018a610359565b818103602083015261041681888a610377565b9050818103604083015261042b818688610377565b905061043a60608301856103a4565b61044760808301846103df565b98975050505050505050565b61045c8161023b565b811461046757600080fd5b50565b60008151905061047981610453565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6104bc8261029c565b810181811067ffffffffffffffff821117156104db576104da610484565b5b80604052505050565b60006104ee6100f7565b90506104fa82826104b3565b919050565b600067ffffffffffffffff82111561051a57610519610484565b5b6105238261029c565b9050602081019050919050565b600061054361053e846104ff565b6104e4565b90508281526020810184848401111561055f5761055e61047f565b5b61056a848285610272565b509392505050565b600082601f8301126105875761058661010b565b5b8151610597848260208601610530565b91505092915050565b600080604083850312156105b7576105b6610101565b5b60006105c58582860161046a565b925050602083015167ffffffffffffffff8111156105e6576105e5610106565b5b6105f285828601610572565b915050925092905056fea2646970667358221220f15cb6d78fafea8cb36c2871d64ba6fab808db64581058721f11e89d77c0af3064736f6c63430008120033"; - -/* Call EVM Payable: - -#![cfg_attr(not(feature = "std"), no_std, no_main)] - -use ink::env::{DefaultEnvironment, Environment}; -use ink::prelude::vec::Vec; - -#[ink::contract(env = CustomEnvironment)] -mod call_xvm_payable { - use super::*; - - #[ink(storage)] - pub struct CallXvmPayable {} - - impl CallXvmPayable { - #[ink(constructor)] - pub fn new() -> Self { - Self {} - } - - #[ink(message, payable, selector = 42)] - pub fn call_xvm_payable( - &self, - target: Vec, - input: Vec, - ) -> CallResult { - let value = Self::env().transferred_value(); - // Calling EVM - Self::env().extension().call(0x0F, target, input, value) - } - } -} - -pub type CallResult = u32; - -#[ink::chain_extension] -pub trait XvmCall { - type ErrorCode = u32; - - #[ink(extension = 0x00010001, handle_status = false)] - fn call(vm_id: u8, target: Vec, input: Vec, value: u128) -> CallResult; -} - -pub enum CustomEnvironment {} -impl Environment for CustomEnvironment { - const MAX_EVENT_TOPICS: usize = ::MAX_EVENT_TOPICS; - - type AccountId = ::AccountId; - type Balance = ::Balance; - type Hash = ::Hash; - type BlockNumber = ::BlockNumber; - type Timestamp = ::Timestamp; - - type ChainExtension = XvmCall; -} - - */ -const CALL_EVM_PAYBLE_NAME: &'static str = "call_xvm_payable"; - -#[test] -fn evm_payable_call_via_xvm_works() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let evm_payable_addr = deploy_evm_contract(EVM_PAYABLE); - - let value = UNIT; - assert_ok!(Xvm::call( - Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000_000, 1024 * 1024), - }, - VmId::Evm, - ALICE, - evm_payable_addr.as_ref().to_vec(), - // Calling `deposit` - hex::decode("d0e30db0").expect("invalid selector hex"), - value, - None, - )); - assert_eq!( - Balances::free_balance(account_id_from(evm_payable_addr)), - value - ); - - assert_ok!(Xvm::call( - Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(10_000_000_000, 1024 * 1024), - }, - VmId::Evm, - ALICE, - evm_payable_addr.as_ref().to_vec(), - // `Calling withdraw` - hex::decode("3ccfd60b").expect("invalid selector hex"), - 0, - None, - )); - assert_eq!( - Balances::free_balance(account_id_from(evm_payable_addr)), - ExistentialDeposit::get(), - ); - }); -} - -#[test] -fn wasm_payable_call_via_xvm_works() { - new_test_ext().execute_with(|| { - let wasm_payable_addr = deploy_wasm_contract(WASM_PAYABLE_NAME); - - let prev_balance = Balances::free_balance(&wasm_payable_addr); - let value = UNIT; - assert_ok!(Xvm::call( - Context { - source_vm_id: VmId::Evm, - weight_limit: Weight::from_parts(10_000_000_000, 1024 * 1024), - }, - VmId::Wasm, - ALICE, - wasm_payable_addr.clone().encode(), - // Calling `deposit` - hex::decode("0000002a").expect("invalid selector hex"), - value, - None, - )); - assert_eq!( - Balances::free_balance(wasm_payable_addr.clone()), - value + prev_balance - ); - }); -} - -#[test] -fn calling_wasm_payable_from_evm_fails_if_caller_contract_balance_below_ed() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let _ = deploy_wasm_contract(WASM_PAYABLE_NAME); - let evm_caller_addr = deploy_evm_contract(CALL_WASM_PAYBLE); - - let value = 1_000_000_000; - assert_ok!(EVM::call( - RuntimeOrigin::root(), - alith(), - evm_caller_addr.clone(), - // to: 0xa8f69d59df362b69a8d4acdb9001eb3e1b8d067b8fdaa70081aed945bde5c48c - // input: 0x0000002a (deposit) - // value: 1000000000 - hex::decode("4012b914000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000020a8f69d59df362b69a8d4acdb9001eb3e1b8d067b8fdaa70081aed945bde5c48c00000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"), - U256::from(value), - 1_000_000, - U256::from(DefaultBaseFeePerGas::get()), - None, - None, - vec![], - )); - - assert_eq!( - System::events().iter().last().expect("no event found").event, - RuntimeEvent::EVM( - pallet_evm::Event::ExecutedFailed { address: evm_caller_addr }, - ), - ); - // EVM caller contract balance should be unchanged. - assert_eq!( - Balances::free_balance(&account_id_from(evm_caller_addr)), - 0, - ); - }); -} - -#[test] -fn calling_wasm_payable_from_evm_works() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let wasm_payable_callee_addr = deploy_wasm_contract(WASM_PAYABLE_NAME); - let evm_caller_addr = deploy_evm_contract(CALL_WASM_PAYBLE); - - let _ = Balances::deposit_creating(&account_id_from(evm_caller_addr.clone()), ExistentialDeposit::get()); - - let prev_wasm_payable_balance = Balances::free_balance(&wasm_payable_callee_addr); - let value = 1_000_000_000; - assert_ok!(EVM::call( - RuntimeOrigin::root(), - alith(), - evm_caller_addr.clone(), - // to: 0xa8f69d59df362b69a8d4acdb9001eb3e1b8d067b8fdaa70081aed945bde5c48c - // input: 0x0000002a (deposit) - // value: 1000000000 - hex::decode("4012b914000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000020a8f69d59df362b69a8d4acdb9001eb3e1b8d067b8fdaa70081aed945bde5c48c00000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"), - U256::from(value), - 1_000_000, - U256::from(DefaultBaseFeePerGas::get()), - None, - None, - vec![], - )); - let received = Balances::free_balance(&wasm_payable_callee_addr) - prev_wasm_payable_balance; - assert_eq!(received, value); - }); -} - -#[test] -fn calling_evm_payable_from_wasm_works() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let evm_payable_callee_addr = deploy_evm_contract(EVM_PAYABLE); - let wasm_caller_addr = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); - - let value = UNIT; - - // fund the wasm contract address for paying storage fees for - // AU mappings. - assert_ok!(Balances::transfer_allow_death( - RuntimeOrigin::signed(ALICE), - wasm_caller_addr.clone().into(), - AccountMappingStorageFee::get() - )); - - let evm_payable = evm_payable_callee_addr.as_ref().to_vec(); - let deposit_func = hex::decode("d0e30db0").expect("invalid deposit function hex"); - let input = hex::decode("0000002a") - .expect("invalid selector hex") - .iter() - .chain(evm_payable.encode().iter()) - .chain(deposit_func.encode().iter()) - .cloned() - .collect::>(); - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - MultiAddress::Id(wasm_caller_addr.clone()), - value, - Weight::from_parts(10_000_000_000, 1024 * 1024), - None, - input, - )); - - assert_eq!( - Balances::free_balance(account_id_from(evm_payable_callee_addr)), - value - ); - - assert_eq!( - Balances::free_balance(&wasm_caller_addr), - ExistentialDeposit::get() - ); - }); -} - -#[test] -fn reentrance_not_allowed() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - // Call path: WASM -> EVM -> WASM - let wasm_caller_addr = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); - let evm_caller_addr = deploy_evm_contract(CALL_WASM_PAYBLE); - let _ = deploy_wasm_contract(WASM_PAYABLE_NAME); - - // to: 0xa8f69d59df362b69a8d4acdb9001eb3e1b8d067b8fdaa70081aed945bde5c48c - // input: 0x0000002a (deposit) - // value: 1000000000 - let call_wasm_payable_input = hex::decode("4012b914000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000020a8f69d59df362b69a8d4acdb9001eb3e1b8d067b8fdaa70081aed945bde5c48c00000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"); - let input = hex::decode("0000002a") - .expect("invalid selector hex") - .iter() - .chain(evm_caller_addr.as_ref().to_vec().encode().iter()) - .chain(call_wasm_payable_input.encode().iter()) - .cloned() - .collect::>(); - - // assert `ReentranceDenied` error - let result = Contracts::bare_call( - ALICE, - wasm_caller_addr, - 0, - Weight::from_parts(10_000_000_000, 1024 * 1024), - None, - input, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); - match result.result { - Ok(ExecReturnValue { flags, data }) => { - assert!(flags.contains(ReturnFlags::REVERT)); - - let reentrance_msg_error = evm_revert_message_error(&format!("{:?}", FailureError::ReentranceDenied)); - let error_string = String::from_utf8(data).expect("invalid utf8"); - assert!(error_string.contains(&format!("{:?}", reentrance_msg_error))); - } - _ => panic!("unexpected wasm call result"), - } - }); -} - -/* - -pragma solidity >=0.8.2 <0.9.0; - -contract ShinyError { - error TooShiny(uint256 a, uint256 star); - - function revert_with_err_msg() public pure { - revert("too shiny"); - } - - function revert_with_err_type() public pure { - revert TooShiny(1, 2); - } -} - - */ -const EVM_DUMMY_ERROR: &'static str = "608060405234801561001057600080fd5b50610231806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806328fd58ae1461003b578063cb1c03b214610045575b600080fd5b61004361004f565b005b61004d61008a565b005b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161008190610128565b60405180910390fd5b600160026040517f2cdac97f0000000000000000000000000000000000000000000000000000000081526004016100c29291906101d2565b60405180910390fd5b600082825260208201905092915050565b7f746f6f207368696e790000000000000000000000000000000000000000000000600082015250565b60006101126009836100cb565b915061011d826100dc565b602082019050919050565b6000602082019050818103600083015261014181610105565b9050919050565b6000819050919050565b6000819050919050565b6000819050919050565b600061018161017c61017784610148565b61015c565b610152565b9050919050565b61019181610166565b82525050565b6000819050919050565b60006101bc6101b76101b284610197565b61015c565b610152565b9050919050565b6101cc816101a1565b82525050565b60006040820190506101e76000830185610188565b6101f460208301846101c3565b939250505056fea26469706673582212203b6d6f183650a1e330bb63d34c4d28865e8356715721534381292e37b07c8dd664736f6c63430008120033"; - -#[test] -fn evm_call_via_xvm_fails_if_revert() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let evm_callee_addr = deploy_evm_contract(EVM_DUMMY_ERROR); - - let result = Xvm::call( - Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000_000, 1024 * 1024), - }, - VmId::Evm, - ALICE, - evm_callee_addr.as_ref().to_vec(), - // Calling `revert_with_err_msg` - hex::decode("28fd58ae").expect("invalid selector hex"), - 0, - None, - ); - match result { - Err(CallFailure { - reason: FailureReason::Revert(FailureRevert::VmRevert(data)), - .. - }) => { - assert_eq!(data, evm_revert_message_error("too shiny")); - } - _ => panic!("unexpected evm call result: {:?}", result), - } - - let result1 = Xvm::call( - Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000_000, 1024 * 1024), - }, - VmId::Evm, - ALICE, - evm_callee_addr.as_ref().to_vec(), - // Calling `revert_with_err_type` - hex::decode("cb1c03b2").expect("invalid selector hex"), - 0, - None, - ); - match result1 { - Err(CallFailure { - reason: FailureReason::Revert(FailureRevert::VmRevert(data)), - .. - }) => { - // data with error type `TooShiny(uint256,uint256)` on revert: selector(4) ++ payload(32) ++ paylaod(32) - let mut encoded = [0u8; 4 + 32 + 32]; - encoded[..4].copy_from_slice(&Keccak256::digest(b"TooShiny(uint256,uint256)")[..4]); - U256::from(1).to_big_endian(&mut encoded[4..36]); - U256::from(2).to_big_endian(&mut encoded[36..]); - assert_eq!(data, encoded); - } - _ => panic!("unexpected evm call result: {:?}", result1), - } - }); -} - -/* Dummy Error: - -#![cfg_attr(not(feature = "std"), no_std, no_main)] - -#[ink::contract] -mod dummy_error { - - #[ink(storage)] - pub struct DummyError {} - - #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] - #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] - pub enum Error { - #[codec(index = 7)] - DummyError, - } - - impl DummyError { - #[ink(constructor)] - pub fn new() -> Self { - Self {} - } - - #[ink(message, selector = 42)] - pub fn do_revert(&self) -> Result<(), Error> { - Err(Error::DummyError) - } - } -} - - */ -const WASM_DUMMY_ERROR_NAME: &'static str = "dummy_error"; - -#[test] -fn wasm_call_via_xvm_fails_if_revert() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let wasm_callee_addr = deploy_wasm_contract(WASM_DUMMY_ERROR_NAME); - let input = hex::decode("0000002a").expect("invalid selector hex"); - let result = Xvm::call( - Context { - source_vm_id: VmId::Evm, - weight_limit: Weight::from_parts(10_000_000_000, 1024 * 1024), - }, - VmId::Wasm, - ALICE, - wasm_callee_addr.clone().encode(), - input, - 0, - None, - ); - match result { - Err(CallFailure { - reason: FailureReason::Revert(FailureRevert::VmRevert(data)), - .. - }) => { - // `DummyError` error index is set `7` in wasm contract. - assert_eq!(data.last(), Some(&7u8)); - } - _ => panic!("unexpected wasm call result: {:?}", result), - } - }); -} - -#[test] -fn evm_caller_reverts_if_wasm_callee_reverted() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let _ = deploy_wasm_contract(WASM_DUMMY_ERROR_NAME); - let evm_caller_addr = deploy_evm_contract(CALL_WASM_PAYBLE); - - // to: 0xa0565d335eb7545deeb25563471219e6f0c9b9bb504a112a5f26fe61237c5a23 - // input: 0x0000002a (do_revert) - // value: 0 - let input = hex::decode("4012b914000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a0565d335eb7545deeb25563471219e6f0c9b9bb504a112a5f26fe61237c5a2300000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"); - let tx = CheckedEthereumTx { - target: evm_caller_addr.clone(), - input: EthereumTxInput::try_from(input).expect("input too large"), - value: U256::zero(), - gas_limit: U256::from(1_000_000), - maybe_access_list: None, - }; - - // Note `EVM::call` won't log details of the revert error, so we need to - // use `EthereumChecked` here for error checks. - match EthereumChecked::xvm_transact(alith(), tx) { - Ok((PostDispatchInfo { .. }, ExecutionInfoV2 { exit_reason, value, .. })) => { - assert_eq!(exit_reason, ExitReason::Revert(ExitRevert::Reverted)); - - // The last item `7` of `[0, 1, 7]` indicates the `DummyError` error index. - let revert_msg_error = evm_revert_message_error("FailureRevert::VmRevert([0, 1, 7])"); - assert_eq!(value, revert_msg_error); - }, - _ => panic!("unexpected evm call result"), - } - }); -} - -#[test] -fn wasm_caller_reverts_if_evm_callee_reverted() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let evm_callee_addr = deploy_evm_contract(EVM_DUMMY_ERROR); - let wasm_caller_addr = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); - - // Calling `revert_with_err_msg` - let revert_func = hex::decode("28fd58ae").expect("invalid selector hex"); - let input = hex::decode("0000002a") - .expect("invalid selector hex") - .iter() - .chain(evm_callee_addr.as_ref().to_vec().encode().iter()) - .chain(revert_func.encode().iter()) - .cloned() - .collect::>(); - - // assert `too shiny` error - let result = Contracts::bare_call( - ALICE, - wasm_caller_addr, - 0, - Weight::from_parts(10_000_000_000, 1024 * 1024), - None, - input, - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); - match result.result { - Ok(ExecReturnValue { flags, data }) => { - assert!(flags.contains(ReturnFlags::REVERT)); - - let revert_failure = FailureReason::Revert(FailureRevert::VmRevert( - evm_revert_message_error("too shiny"), - )); - let error_string = String::from_utf8(data).expect("invalid utf8"); - assert!(error_string.contains(&format!("{:?}", revert_failure))); - } - _ => panic!("unexpected wasm call result"), - } - }); -} - -/* - -#![cfg_attr(not(feature = "std"), no_std, no_main)] - -#[ink::contract] -mod simple_storage { - use ink::storage::Mapping; - - #[ink(storage)] - pub struct SimpleStorage { - storages: Mapping, - } - - impl SimpleStorage { - #[ink(constructor)] - pub fn new() -> Self { - let storages = Mapping::default(); - Self { storages } - } - - #[ink(message, selector = 42)] - pub fn store(&mut self) { - let caller = self.env().caller(); - self.storages.insert(caller, &42); - } - - #[ink(message, selector = 43)] - pub fn get(&self) -> u32 { - let caller = self.env().caller(); - self.storages.get(caller).unwrap_or(0) - } - } -} - - */ -const WASM_SIMPLE_STORAGE_NAME: &'static str = "simple_storage"; - -#[test] -fn wasm_call_via_xvm_fails_if_storage_deposit_limit_exhausted() { - new_test_ext().execute_with(|| { - let wasm_callee_addr = deploy_wasm_contract(WASM_SIMPLE_STORAGE_NAME); - let input = hex::decode("0000002a") - .expect("invalid selector hex"); - let result = Xvm::call( - Context { - source_vm_id: VmId::Evm, - weight_limit: Weight::from_parts(10_000_000_000, 1024 * 1024), - }, - VmId::Wasm, - ALICE, - wasm_callee_addr.clone().encode(), - input, - 0, - Some(0) - ); - match result { - Err(CallFailure { - reason: FailureReason::Error(FailureError::VmError(data)), - .. - }) => { - let error_string = "WASM call error: Module(ModuleError { index: 70, error: [24, 0, 0, 0], message: Some(\"StorageDepositLimitExhausted\") })"; - assert_eq!(data, error_string.as_bytes()); - }, - _ => panic!("unexpected wasm call result"), - } - }); -} - -#[test] -fn wasm_call_via_xvm_call_works_if_sufficient_storage_deposit_limit() { - new_test_ext().execute_with(|| { - let wasm_callee_addr = deploy_wasm_contract(WASM_SIMPLE_STORAGE_NAME); - let input = hex::decode("0000002a").expect("invalid selector hex"); - assert_ok!(Xvm::call( - Context { - source_vm_id: VmId::Evm, - weight_limit: Weight::from_parts(10_000_000_000, 1024 * 1024), - }, - VmId::Wasm, - ALICE, - wasm_callee_addr.clone().encode(), - input, - 0, - Some(UNIT) - )); - }); -} - -/* - -// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >=0.8.2 <0.9.0; - -interface XVM { - function xvm_call( - uint8 vm_id, - bytes calldata to, - bytes calldata input, - uint256 value, - uint256 storage_deposit_limit - ) external payable returns (bool success, bytes memory data); -} - -contract CallXVMPayble { - function call_xvm_payable(bytes calldata to, bytes calldata input, uint256 value, uint256 storage_deposit_limit) external payable returns (bool success, bytes memory data) { - return XVM(0x0000000000000000000000000000000000005005).xvm_call(0x1F, to, input, value, storage_deposit_limit); - } -} - - */ -const CALL_XVM_PAYABLE_WITH_SDL: &'static str = "608060405234801561001057600080fd5b50610609806100206000396000f3fe60806040526004361061001e5760003560e01c80632d9338da14610023575b600080fd5b61003d600480360381019061003891906101a6565b610054565b60405161004b9291906102f8565b60405180910390f35b6000606061500573ffffffffffffffffffffffffffffffffffffffff1663acc57c7e601f8a8a8a8a8a8a6040518863ffffffff1660e01b81526004016100a097969594939291906103c5565b6000604051808303816000875af11580156100bf573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906100e89190610577565b91509150965096945050505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126101305761012f61010b565b5b8235905067ffffffffffffffff81111561014d5761014c610110565b5b60208301915083600182028301111561016957610168610115565b5b9250929050565b6000819050919050565b61018381610170565b811461018e57600080fd5b50565b6000813590506101a08161017a565b92915050565b600080600080600080608087890312156101c3576101c2610101565b5b600087013567ffffffffffffffff8111156101e1576101e0610106565b5b6101ed89828a0161011a565b9650965050602087013567ffffffffffffffff8111156102105761020f610106565b5b61021c89828a0161011a565b9450945050604061022f89828a01610191565b925050606061024089828a01610191565b9150509295509295509295565b60008115159050919050565b6102628161024d565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156102a2578082015181840152602081019050610287565b60008484015250505050565b6000601f19601f8301169050919050565b60006102ca82610268565b6102d48185610273565b93506102e4818560208601610284565b6102ed816102ae565b840191505092915050565b600060408201905061030d6000830185610259565b818103602083015261031f81846102bf565b90509392505050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b600061036461035f61035a84610328565b61033f565b610332565b9050919050565b61037481610349565b82525050565b82818337600083830152505050565b60006103958385610273565b93506103a283858461037a565b6103ab836102ae565b840190509392505050565b6103bf81610170565b82525050565b600060a0820190506103da600083018a61036b565b81810360208301526103ed81888a610389565b90508181036040830152610402818688610389565b905061041160608301856103b6565b61041e60808301846103b6565b98975050505050505050565b6104338161024d565b811461043e57600080fd5b50565b6000815190506104508161042a565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610493826102ae565b810181811067ffffffffffffffff821117156104b2576104b161045b565b5b80604052505050565b60006104c56100f7565b90506104d1828261048a565b919050565b600067ffffffffffffffff8211156104f1576104f061045b565b5b6104fa826102ae565b9050602081019050919050565b600061051a610515846104d6565b6104bb565b90508281526020810184848401111561053657610535610456565b5b610541848285610284565b509392505050565b600082601f83011261055e5761055d61010b565b5b815161056e848260208601610507565b91505092915050565b6000806040838503121561058e5761058d610101565b5b600061059c85828601610441565b925050602083015167ffffffffffffffff8111156105bd576105bc610106565b5b6105c985828601610549565b915050925092905056fea2646970667358221220e44af7386feb3ae682c95df11f7b3de851b515869a073d6fabe05758e94e351f64736f6c63430008120033"; - -#[test] -fn calling_wasm_from_evm_works_if_sufficient_storage_deposit_limit() { - new_test_ext().execute_with(|| { - // create account mappings - connect_accounts(&ALICE, &alith_secret_key()); - - let wasm_callee_addr = deploy_wasm_contract(WASM_SIMPLE_STORAGE_NAME); - let evm_caller_addr = deploy_evm_contract(CALL_XVM_PAYABLE_WITH_SDL); - - // Fund the EVM contract to pay for storage deposit. - let _ = Balances::deposit_creating(&account_id_from(evm_caller_addr.clone()), UNIT); - - assert_ok!(EVM::call( - RuntimeOrigin::root(), - alith(), - evm_caller_addr.clone(), - // to: 0x0e0ddb5a5f0b99d7be468a3051a94073ec6b1900178316401a52b93415026999 - // input: 0x0000002a (store) - // value: 0 - // storage_deposit_limit: 1_000_000_000_000_000 - hex::decode("2d9338da000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000000000000000200e0ddb5a5f0b99d7be468a3051a94073ec6b1900178316401a52b9341502699900000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"), - U256::zero(), - 1_000_000, - U256::from(DefaultBaseFeePerGas::get()), - None, - None, - vec![], - )); - assert_eq!( - System::events().iter().last().expect("no event found").event, - RuntimeEvent::EVM( - pallet_evm::Event::Executed { address: evm_caller_addr }, - ), - ); - - let result = Contracts::bare_call( - account_id_from(evm_caller_addr), - wasm_callee_addr, - 0, - Weight::from_parts(10_000_000_000, 1024 * 1024), - None, - // `get` selector - hex::decode("0000002b").expect("invalid selector hex"), - DebugInfo::Skip, - CollectEvents::Skip, - Determinism::Enforced, - ); - match result.result { - Ok(ExecReturnValue { flags, data }) => { - assert!(!flags.contains(ReturnFlags::REVERT)); - // Retrive stored value `42`. - assert_eq!(data[1], 42); - }, - _ => panic!("unexpected wasm call result"), - } - }); -}