From 49de894a1576864fb5f697086667e51690fe6acf Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 20 Jul 2023 22:07:23 +1200 Subject: [PATCH 01/26] pallet-xvm refactor. --- Cargo.lock | 21 +++ pallets/xvm/Cargo.toml | 59 +++++++++ pallets/xvm/src/lib.rs | 293 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 pallets/xvm/Cargo.toml create mode 100644 pallets/xvm/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 5f4837adb..054dd4cf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8061,6 +8061,27 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-xvm-v2" +version = "0.2.1" +dependencies = [ + "astar-primitives", + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-contracts", + "pallet-ethereum-checked", + "pallet-evm", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "parachain-info" version = "0.1.0" diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml new file mode 100644 index 000000000..e25f833db --- /dev/null +++ b/pallets/xvm/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "pallet-xvm-v2" +version = "0.2.1" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +impl-trait-for-tuples = { 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 +pallet-evm = { workspace = true } + +# Substrate WASM VM support +pallet-contracts = { workspace = true } + +# Astar +astar-primitives = { workspace = true } +pallet-ethereum-checked = { workspace = true } + +[dev-dependencies] + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "frame-support/std", + "frame-system/std", + "pallet-contracts/std", + "pallet-evm/std", + "scale-info/std", + "serde", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", + "astar-primitives/std", + "pallet-ethereum-checked/std", +] + +runtime-benchmarks = [ + "frame-benchmarking", + "pallet-ethereum-checked/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs new file mode 100644 index 000000000..248479d5e --- /dev/null +++ b/pallets/xvm/src/lib.rs @@ -0,0 +1,293 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +//! # XVM pallet +//! +//! ## Overview +//! +//! ## Interface +//! +//! ### Dispatchable Function +//! +//! +//! ### Other +//! +//! + +use frame_support::{pallet_prelude::*, traits::ConstU32, BoundedVec}; +use pallet_evm::GasWeightMapping; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::U256; +use sp_runtime::{traits::StaticLookup, RuntimeDebug}; +use sp_std::{marker::PhantomData, prelude::*, result::Result}; + +use astar_primitives::ethereum_checked::{ + AccountMapping, CheckedEthereumTransact, CheckedEthereumTx, MAX_ETHEREUM_TX_INPUT_SIZE, +}; + +pub use pallet::*; + +/// XVM call info on success. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CallInfo { + /// Output of the call. + pub output: Vec, + /// Actual used weight. + pub used_weight: Weight, +} + +/// XVM call error on failure. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum CallError { + /// The call failed on EVM or WASM execution. + ExecutionFailed(Vec), + /// Input is too large. + InputTooLarge, + /// Target contract address is invalid. + InvalidTarget, +} + +/// XVM call error with used weight info. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CallErrorWithWeight { + /// Error info. + pub error: CallError, + /// Actual used weight. + pub used_weight: Weight, +} + +/// XVM call result. +pub type XvmCallResult = Result; + +/// XVM context. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct XvmContext { + /// Max weight limit. + pub weight_limit: Weight, + /// Optional encoded execution environment. + pub env: Option>, +} + +pub trait XvmCall { + /// Call a contract in XVM. + /// + /// Parameters: + /// - `context`: XVM context. + /// - `source`: Caller Id. + /// - `target`: Target contract address. + /// - `input`: call input data. + fn xvm_call( + context: XvmContext, + source: AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: + frame_system::Config + + pallet_evm::Config + + pallet_ethereum_checked::Config + + pallet_contracts::Config + { + /// `CheckedEthereumTransact` implementation. + type EthereumTransact: CheckedEthereumTransact; + } +} + +// TODO: benchmark XVM calls overhead +pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); + +/// XVM call to EVM. +pub struct EvmCall(PhantomData); +impl XvmCall for EvmCall { + fn xvm_call( + context: XvmContext, + source: T::AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult { + Pallet::::evm_call(context, source, target, input, false) + } +} + +/// XVM call to WASM. +pub struct WasmCall(PhantomData); +impl XvmCall for WasmCall { + fn xvm_call( + context: XvmContext, + source: T::AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult { + Pallet::::wasm_call(context, source, target, input, false) + } +} + +impl Pallet { + fn evm_call( + context: XvmContext, + source: T::AccountId, + target: Vec, + input: Vec, + skip_apply: bool, + ) -> XvmCallResult { + log::trace!( + target: "xvm::evm_call", + "Calling EVM: {:?} {:?}, {:?}, {:?}", + context, source, target, input, + ); + + let value = U256::zero(); + let gas_limit = T::GasWeightMapping::weight_to_gas(context.weight_limit); + + let target_decoded = + Decode::decode(&mut target.as_ref()).map_err(|_| CallErrorWithWeight { + error: CallError::InvalidTarget, + used_weight: PLACEHOLDER_WEIGHT, + })?; + let bounded_input = BoundedVec::>::try_from(input) + .map_err(|_| CallErrorWithWeight { + error: CallError::InputTooLarge, + used_weight: PLACEHOLDER_WEIGHT, + })?; + + if skip_apply { + return Ok(CallInfo { + output: vec![], + used_weight: PLACEHOLDER_WEIGHT, + }); + } + + let (post_dispatch_info, call_info) = T::EthereumTransact::xvm_transact( + T::AccountMapping::into_h160(source), + CheckedEthereumTx { + gas_limit: U256::from(gas_limit), + target: target_decoded, + value, + input: bounded_input, + maybe_access_list: None, + }, + ) + .map_err(|e| { + let used_weight = e.post_info.actual_weight.unwrap_or_default(); + CallErrorWithWeight { + error: CallError::ExecutionFailed(Into::<&str>::into(e.error).into()), + used_weight, + } + })?; + + log::trace!( + target: "xvm::evm_call", + "EVM call result: exit_reason: {:?}, used_gas: {:?}", call_info.exit_reason, call_info.used_gas, + ); + + // TODO: add overhead to used weight + Ok(CallInfo { + output: call_info.value, + used_weight: post_dispatch_info.actual_weight.unwrap_or_default(), + }) + } + + fn wasm_call( + context: XvmContext, + source: T::AccountId, + target: Vec, + input: Vec, + skip_apply: bool, + ) -> XvmCallResult { + log::trace!( + target: "xvm::wasm_call", + "Calling WASM: {:?} {:?}, {:?}, {:?}", + context, source, target, input, + ); + + let dest = { + let error = CallErrorWithWeight { + error: CallError::InvalidTarget, + used_weight: PLACEHOLDER_WEIGHT, + }; + let decoded = Decode::decode(&mut target.as_ref()).map_err(|_| error.clone())?; + T::Lookup::lookup(decoded).map_err(|_| error) + }?; + + if skip_apply { + return Ok(CallInfo { + output: vec![], + used_weight: PLACEHOLDER_WEIGHT, + }); + } + + let call_result = pallet_contracts::Pallet::::bare_call( + source, + dest, + Default::default(), + context.weight_limit, + None, + input, + false, + pallet_contracts::Determinism::Deterministic, + ); + log::trace!(target: "xvm::wasm_call", "WASM call result: {:?}", call_result); + + // TODO: add overhead to used weight + let used_weight = call_result.gas_consumed; + + match call_result.result { + Ok(success) => Ok(CallInfo { + output: success.data, + used_weight, + }), + + Err(error) => Err(CallErrorWithWeight { + error: CallError::ExecutionFailed(Into::<&str>::into(error).into()), + used_weight, + }), + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl Pallet { + pub fn evm_call_without_apply( + context: XvmContext, + source: T::AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult { + Self::evm_call(context, source, target, input, true) + } + + pub fn wasm_call_without_apply( + context: XvmContext, + source: T::AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult { + Self::wasm_call(context, source, target, input, true) + } +} From 5ea897cdbcc9c64176ebd4974070292a08c7be27 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 20 Jul 2023 22:13:35 +1200 Subject: [PATCH 02/26] Add TODOs. --- pallets/xvm/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 248479d5e..72705a232 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -43,6 +43,8 @@ use astar_primitives::ethereum_checked::{ pub use pallet::*; +// TODO: move types and traits to `astar-primitives`. + /// XVM call info on success. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct CallInfo { From 57ad0c9bb4570023612ca2e22b09813ae4910600 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 20 Jul 2023 22:59:09 +1200 Subject: [PATCH 03/26] Update design. --- pallets/xvm/src/lib.rs | 72 ++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 72705a232..71111d0d9 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -63,6 +63,8 @@ pub enum CallError { InputTooLarge, /// Target contract address is invalid. InvalidTarget, + /// Calling the contracts in the same VM is not allowed. + SameVmCallNotAllowed, } /// XVM call error with used weight info. @@ -77,9 +79,17 @@ pub struct CallErrorWithWeight { /// XVM call result. pub type XvmCallResult = Result; +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum Vm { + Evm, + Wasm, +} + /// XVM context. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct XvmContext { + /// The source VM of the call. + pub source_vm: Vm, /// Max weight limit. pub weight_limit: Weight, /// Optional encoded execution environment. @@ -87,14 +97,28 @@ pub struct XvmContext { } pub trait XvmCall { - /// Call a contract in XVM. + /// Call a contract in EVM. + /// + /// Parameters: + /// - `context`: XVM context. + /// - `source`: Caller Id. + /// - `target`: Target contract address. + /// - `input`: call input data. + fn evm_call( + context: XvmContext, + source: AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult; + + /// Call a contract in EVM. /// /// Parameters: /// - `context`: XVM context. /// - `source`: Caller Id. /// - `target`: Target contract address. /// - `input`: call input data. - fn xvm_call( + fn wasm_call( context: XvmContext, source: AccountId, target: Vec, @@ -121,37 +145,31 @@ pub mod pallet { } } -// TODO: benchmark XVM calls overhead -pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); - -/// XVM call to EVM. -pub struct EvmCall(PhantomData); -impl XvmCall for EvmCall { - fn xvm_call( +impl XvmCall for Pallet { + fn evm_call( context: XvmContext, source: T::AccountId, target: Vec, input: Vec, ) -> XvmCallResult { - Pallet::::evm_call(context, source, target, input, false) + Pallet::::do_evm_call(context, source, target, input, false) } -} -/// XVM call to WASM. -pub struct WasmCall(PhantomData); -impl XvmCall for WasmCall { - fn xvm_call( + fn wasm_call( context: XvmContext, source: T::AccountId, target: Vec, input: Vec, ) -> XvmCallResult { - Pallet::::wasm_call(context, source, target, input, false) + Pallet::::do_wasm_call(context, source, target, input, false) } } +// TODO: benchmark XVM calls overhead +pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); + impl Pallet { - fn evm_call( + fn do_evm_call( context: XvmContext, source: T::AccountId, target: Vec, @@ -164,6 +182,13 @@ impl Pallet { context, source, target, input, ); + if context.source_vm == Vm::Evm { + return Err(CallErrorWithWeight { + error: CallError::SameVmCallNotAllowed, + used_weight: PLACEHOLDER_WEIGHT, + }); + } + let value = U256::zero(); let gas_limit = T::GasWeightMapping::weight_to_gas(context.weight_limit); @@ -215,7 +240,7 @@ impl Pallet { }) } - fn wasm_call( + fn do_wasm_call( context: XvmContext, source: T::AccountId, target: Vec, @@ -228,6 +253,13 @@ impl Pallet { context, source, target, input, ); + if context.source_vm == Vm::Wasm { + return Err(CallErrorWithWeight { + error: CallError::SameVmCallNotAllowed, + used_weight: PLACEHOLDER_WEIGHT, + }); + } + let dest = { let error = CallErrorWithWeight { error: CallError::InvalidTarget, @@ -281,7 +313,7 @@ impl Pallet { target: Vec, input: Vec, ) -> XvmCallResult { - Self::evm_call(context, source, target, input, true) + Self::do_evm_call(context, source, target, input, true) } pub fn wasm_call_without_apply( @@ -290,6 +322,6 @@ impl Pallet { target: Vec, input: Vec, ) -> XvmCallResult { - Self::wasm_call(context, source, target, input, true) + Self::do_wasm_call(context, source, target, input, true) } } From 46263d272df85b4cabb3bb12e5ed458d475b26a3 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 20 Jul 2023 23:31:58 +1200 Subject: [PATCH 04/26] Keep XVM call interface unified. --- pallets/xvm/src/lib.rs | 85 +++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 71111d0d9..0cc260b15 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -79,17 +79,20 @@ pub struct CallErrorWithWeight { /// XVM call result. pub type XvmCallResult = Result; -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum Vm { Evm, Wasm, } +// TODO: Note caller shouldn't be able to specify `source_vm`. /// XVM context. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct XvmContext { /// The source VM of the call. pub source_vm: Vm, + /// The target VM of the call. + pub target_vm: Vm, /// Max weight limit. pub weight_limit: Weight, /// Optional encoded execution environment. @@ -97,28 +100,14 @@ pub struct XvmContext { } pub trait XvmCall { - /// Call a contract in EVM. + /// Call a contract in XVM. /// /// Parameters: /// - `context`: XVM context. /// - `source`: Caller Id. /// - `target`: Target contract address. /// - `input`: call input data. - fn evm_call( - context: XvmContext, - source: AccountId, - target: Vec, - input: Vec, - ) -> XvmCallResult; - - /// Call a contract in EVM. - /// - /// Parameters: - /// - `context`: XVM context. - /// - `source`: Caller Id. - /// - `target`: Target contract address. - /// - `input`: call input data. - fn wasm_call( + fn xvm_call( context: XvmContext, source: AccountId, target: Vec, @@ -146,30 +135,41 @@ pub mod pallet { } impl XvmCall for Pallet { - fn evm_call( + fn xvm_call( context: XvmContext, source: T::AccountId, target: Vec, input: Vec, ) -> XvmCallResult { - Pallet::::do_evm_call(context, source, target, input, false) + Pallet::::do_xvm_call(context, source, target, input, false) } +} - fn wasm_call( +// TODO: benchmark XVM calls overhead +pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); + +impl Pallet { + fn do_xvm_call( context: XvmContext, source: T::AccountId, target: Vec, input: Vec, + skip_apply: bool, ) -> XvmCallResult { - Pallet::::do_wasm_call(context, source, target, input, false) - } -} + if context.source_vm == context.target_vm { + return Err(CallErrorWithWeight { + error: CallError::SameVmCallNotAllowed, + used_weight: PLACEHOLDER_WEIGHT, + }); + } -// TODO: benchmark XVM calls overhead -pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); + match context.source_vm { + Vm::Evm => Pallet::::evm_call(context, source, target, input, skip_apply), + Vm::Wasm => Pallet::::wasm_call(context, source, target, input, skip_apply), + } + } -impl Pallet { - fn do_evm_call( + fn evm_call( context: XvmContext, source: T::AccountId, target: Vec, @@ -182,13 +182,6 @@ impl Pallet { context, source, target, input, ); - if context.source_vm == Vm::Evm { - return Err(CallErrorWithWeight { - error: CallError::SameVmCallNotAllowed, - used_weight: PLACEHOLDER_WEIGHT, - }); - } - let value = U256::zero(); let gas_limit = T::GasWeightMapping::weight_to_gas(context.weight_limit); @@ -240,7 +233,7 @@ impl Pallet { }) } - fn do_wasm_call( + fn wasm_call( context: XvmContext, source: T::AccountId, target: Vec, @@ -253,13 +246,6 @@ impl Pallet { context, source, target, input, ); - if context.source_vm == Vm::Wasm { - return Err(CallErrorWithWeight { - error: CallError::SameVmCallNotAllowed, - used_weight: PLACEHOLDER_WEIGHT, - }); - } - let dest = { let error = CallErrorWithWeight { error: CallError::InvalidTarget, @@ -303,11 +289,9 @@ impl Pallet { }), } } -} -#[cfg(feature = "runtime-benchmarks")] -impl Pallet { - pub fn evm_call_without_apply( + #[cfg(feature = "runtime-benchmarks")] + pub fn xvm_call_without_apply( context: XvmContext, source: T::AccountId, target: Vec, @@ -315,13 +299,4 @@ impl Pallet { ) -> XvmCallResult { Self::do_evm_call(context, source, target, input, true) } - - pub fn wasm_call_without_apply( - context: XvmContext, - source: T::AccountId, - target: Vec, - input: Vec, - ) -> XvmCallResult { - Self::do_wasm_call(context, source, target, input, true) - } } From 5c7924461abb1157761337303dfc8ff7b59ab42e Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 20 Jul 2023 23:48:13 +1200 Subject: [PATCH 05/26] Renaming. --- pallets/xvm/src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 0cc260b15..133af0197 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -154,7 +154,7 @@ impl Pallet { source: T::AccountId, target: Vec, input: Vec, - skip_apply: bool, + skip_execution: bool, ) -> XvmCallResult { if context.source_vm == context.target_vm { return Err(CallErrorWithWeight { @@ -164,8 +164,8 @@ impl Pallet { } match context.source_vm { - Vm::Evm => Pallet::::evm_call(context, source, target, input, skip_apply), - Vm::Wasm => Pallet::::wasm_call(context, source, target, input, skip_apply), + Vm::Evm => Pallet::::evm_call(context, source, target, input, skip_execution), + Vm::Wasm => Pallet::::wasm_call(context, source, target, input, skip_execution), } } @@ -174,7 +174,7 @@ impl Pallet { source: T::AccountId, target: Vec, input: Vec, - skip_apply: bool, + skip_execution: bool, ) -> XvmCallResult { log::trace!( target: "xvm::evm_call", @@ -196,7 +196,7 @@ impl Pallet { used_weight: PLACEHOLDER_WEIGHT, })?; - if skip_apply { + if skip_execution { return Ok(CallInfo { output: vec![], used_weight: PLACEHOLDER_WEIGHT, @@ -238,7 +238,7 @@ impl Pallet { source: T::AccountId, target: Vec, input: Vec, - skip_apply: bool, + skip_execution: bool, ) -> XvmCallResult { log::trace!( target: "xvm::wasm_call", @@ -255,7 +255,7 @@ impl Pallet { T::Lookup::lookup(decoded).map_err(|_| error) }?; - if skip_apply { + if skip_execution { return Ok(CallInfo { output: vec![], used_weight: PLACEHOLDER_WEIGHT, @@ -291,12 +291,12 @@ impl Pallet { } #[cfg(feature = "runtime-benchmarks")] - pub fn xvm_call_without_apply( + pub fn xvm_call_without_execution( context: XvmContext, source: T::AccountId, target: Vec, input: Vec, ) -> XvmCallResult { - Self::do_evm_call(context, source, target, input, true) + Self::do_xvm_call(context, source, target, input, true) } } From 2a81a2db646806c578efbc2e8a2e1ef2859137e6 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Tue, 25 Jul 2023 22:51:59 +1200 Subject: [PATCH 06/26] update & integration. --- Cargo.lock | 32 +--- Cargo.toml | 2 +- chain-extensions/xvm/Cargo.toml | 4 +- chain-extensions/xvm/src/lib.rs | 40 +++-- pallets/pallet-xvm/Cargo.toml | 66 -------- pallets/pallet-xvm/src/evm.rs | 97 ------------ pallets/pallet-xvm/src/lib.rs | 229 --------------------------- pallets/pallet-xvm/src/pallet/mod.rs | 160 ------------------- pallets/pallet-xvm/src/wasm.rs | 93 ----------- pallets/xvm/Cargo.toml | 16 +- pallets/xvm/src/lib.rs | 119 ++++---------- precompiles/xvm/Cargo.toml | 13 +- precompiles/xvm/src/lib.rs | 37 ++--- precompiles/xvm/src/tests.rs | 2 +- primitives/src/lib.rs | 3 + primitives/src/xvm.rs | 110 +++++++++++++ runtime/local/Cargo.toml | 2 +- runtime/local/src/lib.rs | 9 +- runtime/shibuya/Cargo.toml | 2 +- runtime/shibuya/src/lib.rs | 17 +- 20 files changed, 221 insertions(+), 832 deletions(-) delete mode 100644 pallets/pallet-xvm/Cargo.toml delete mode 100644 pallets/pallet-xvm/src/evm.rs delete mode 100644 pallets/pallet-xvm/src/lib.rs delete mode 100644 pallets/pallet-xvm/src/pallet/mod.rs delete mode 100644 pallets/pallet-xvm/src/wasm.rs create mode 100644 primitives/src/xvm.rs diff --git a/Cargo.lock b/Cargo.lock index 054dd4cf3..6d7e36cf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6735,8 +6735,9 @@ dependencies = [ [[package]] name = "pallet-chain-extension-xvm" -version = "0.1.0" +version = "0.1.1" dependencies = [ + "astar-primitives", "frame-support", "frame-system", "log", @@ -7291,8 +7292,9 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-xvm" -version = "0.1.0" +version = "0.1.1" dependencies = [ + "astar-primitives", "derive_more", "fp-evm", "frame-support", @@ -7301,6 +7303,8 @@ dependencies = [ "log", "num_enum", "pallet-balances", + "pallet-contracts", + "pallet-ethereum-checked", "pallet-evm", "pallet-timestamp", "pallet-xvm", @@ -8042,34 +8046,12 @@ dependencies = [ [[package]] name = "pallet-xvm" -version = "0.2.1" -dependencies = [ - "astar-primitives", - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-contracts", - "pallet-ethereum-checked", - "pallet-evm", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-xvm-v2" -version = "0.2.1" +version = "0.2.2" dependencies = [ "astar-primitives", "frame-benchmarking", "frame-support", "frame-system", - "impl-trait-for-tuples", "log", "pallet-contracts", "pallet-ethereum-checked", diff --git a/Cargo.toml b/Cargo.toml index 653e47163..f0d46ab66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -273,7 +273,7 @@ pallet-collator-selection = { path = "./pallets/collator-selection", default-fea pallet-custom-signatures = { path = "./pallets/custom-signatures", default-features = false } pallet-dapps-staking = { path = "./pallets/dapps-staking", default-features = false } pallet-xc-asset-config = { path = "./pallets/xc-asset-config", default-features = false } -pallet-xvm = { path = "./pallets/pallet-xvm", default-features = false } +pallet-xvm = { path = "./pallets/xvm", default-features = false } pallet-xcm = { path = "./pallets/pallet-xcm", default-features = false } pallet-ethereum-checked = { path = "./pallets/ethereum-checked", default-features = false } diff --git a/chain-extensions/xvm/Cargo.toml b/chain-extensions/xvm/Cargo.toml index ae661fa79..333e22d8a 100644 --- a/chain-extensions/xvm/Cargo.toml +++ b/chain-extensions/xvm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-chain-extension-xvm" -version = "0.1.0" +version = "0.1.1" license = "Apache-2.0" description = "Chain extension for XVM" authors.workspace = true @@ -22,6 +22,7 @@ sp-runtime = { workspace = true } sp-std = { workspace = true } # Astar +astar-primitives = { workspace = true } pallet-xvm = { workspace = true } xvm-chain-extension-types = { workspace = true } @@ -40,4 +41,5 @@ std = [ "sp-runtime/std", # Astar "pallet-xvm/std", + "astar-primitives/std", ] diff --git a/chain-extensions/xvm/src/lib.rs b/chain-extensions/xvm/src/lib.rs index 592c7dc31..5f419fe23 100644 --- a/chain-extensions/xvm/src/lib.rs +++ b/chain-extensions/xvm/src/lib.rs @@ -18,15 +18,15 @@ #![cfg_attr(not(feature = "std"), no_std)] +use astar_primitives::xvm::{Context, VmId, XvmCall}; use frame_support::dispatch::Encode; use pallet_contracts::chain_extension::{ChainExtension, Environment, Ext, InitState, RetVal}; -use pallet_xvm::XvmContext; use sp_runtime::DispatchError; use sp_std::marker::PhantomData; use xvm_chain_extension_types::{XvmCallArgs, XvmExecutionResult}; enum XvmFuncId { - XvmCall, + Call, // TODO: expand with other calls too } @@ -35,7 +35,7 @@ impl TryFrom for XvmFuncId { fn try_from(value: u16) -> Result { match value { - 1 => Ok(XvmFuncId::XvmCall), + 1 => Ok(XvmFuncId::Call), _ => Err(DispatchError::Other( "Unsupported func id in Xvm chain extension", )), @@ -64,13 +64,13 @@ where let mut env = env.buf_in_buf_out(); match func_id { - XvmFuncId::XvmCall => { + XvmFuncId::Call => { // We need to immediately charge for the worst case scenario. Gas equals Weight in pallet-contracts context. - let remaining_weight = env.ext().gas_meter().gas_left(); + let weight_limit = env.ext().gas_meter().gas_left(); + // TODO: track proof size in align fees ticket // We don't track used proof size, so we can't refund after. // So we will charge a 32KB dummy value as a temporary replacement. - let charged_weight = - env.charge_weight(remaining_weight.set_proof_size(32 * 1024))?; + let charged_weight = env.charge_weight(weight_limit.set_proof_size(32 * 1024))?; let caller = env.ext().caller().clone(); @@ -78,16 +78,28 @@ where let _origin_address = env.ext().address().clone(); let _value = env.ext().value_transferred(); - let xvm_context = XvmContext { - id: vm_id, - max_weight: remaining_weight, - env: None, + let xvm_context = Context { + source_vm_id: VmId::Wasm, + weight_limit, }; + let vm_id = { + let result = vm_id.try_into(); + match result { + Ok(id) => id, + Err(_) => { + // TODO: Propagate error + return Ok(RetVal::Converging(XvmExecutionResult::UnknownError as u32)); + } + } + }; let call_result = - pallet_xvm::Pallet::::xvm_bare_call(xvm_context, caller, to, input); + pallet_xvm::Pallet::::call(xvm_context, vm_id, caller, to, input); - let actual_weight = pallet_xvm::consumed_weight(&call_result); + let actual_weight = match call_result { + Ok(ref info) => info.used_weight, + Err(ref err) => err.used_weight, + }; env.adjust_weight(charged_weight, actual_weight); match call_result { @@ -97,7 +109,7 @@ where "success: {:?}", success ); - let buffer: sp_std::vec::Vec<_> = success.output().encode(); + let buffer: sp_std::vec::Vec<_> = success.output.encode(); env.write(&buffer, false, None)?; Ok(RetVal::Converging(XvmExecutionResult::Success as u32)) } diff --git a/pallets/pallet-xvm/Cargo.toml b/pallets/pallet-xvm/Cargo.toml deleted file mode 100644 index 0d0fa29d1..000000000 --- a/pallets/pallet-xvm/Cargo.toml +++ /dev/null @@ -1,66 +0,0 @@ -[package] -name = "pallet-xvm" -version = "0.2.1" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -impl-trait-for-tuples = { 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 -pallet-evm = { workspace = true, optional = true } - -# Substrate WASM VM support -pallet-contracts = { workspace = true, optional = true } - -# Astar -astar-primitives = { workspace = true } -pallet-ethereum-checked = { workspace = true, optional = true } - -[dev-dependencies] - -[features] -default = ["std"] -evm = [ - "pallet-evm", - "pallet-ethereum-checked", -] -wasm = [ - "pallet-contracts", -] -std = [ - "parity-scale-codec/std", - "frame-support/std", - "frame-system/std", - "pallet-contracts/std", - "pallet-evm/std", - "scale-info/std", - "serde", - "sp-core/std", - "sp-runtime/std", - "sp-std/std", - "astar-primitives/std", - "pallet-ethereum-checked/std", -] - -runtime-benchmarks = [ - "frame-benchmarking", - "pallet-ethereum-checked/runtime-benchmarks", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/pallet-xvm/src/evm.rs b/pallets/pallet-xvm/src/evm.rs deleted file mode 100644 index 383e43a86..000000000 --- a/pallets/pallet-xvm/src/evm.rs +++ /dev/null @@ -1,97 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later - -// Astar is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Astar is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Astar. If not, see . - -//! EVM support for XVM pallet. - -use crate::*; -use frame_support::{traits::ConstU32, BoundedVec}; -use pallet_evm::GasWeightMapping; -use sp_core::U256; -use sp_runtime::traits::Get; - -use astar_primitives::ethereum_checked::{ - AccountMapping as AccountMappingT, CheckedEthereumTransact, CheckedEthereumTx, - MAX_ETHEREUM_TX_INPUT_SIZE, -}; - -/// EVM adapter for XVM calls. -/// -/// This adapter supports generic XVM calls and encode it into EVM native calls -/// using Solidity ABI codec (https://docs.soliditylang.org/en/v0.8.16/abi-spec.html). -pub struct EVM(sp_std::marker::PhantomData<(I, T, Transact)>); - -impl SyncVM for EVM -where - I: Get, - T: frame_system::Config + pallet_evm::Config + pallet_ethereum_checked::Config, - Transact: CheckedEthereumTransact, -{ - fn id() -> VmId { - I::get() - } - - fn xvm_call(context: XvmContext, from: T::AccountId, to: Vec, input: Vec) -> XvmResult { - log::trace!( - target: "xvm::EVM::xvm_call", - "Start EVM XVM: {:?}, {:?}, {:?}", - from, to, input, - ); - - let value = U256::zero(); - let gas_limit = T::GasWeightMapping::weight_to_gas(context.max_weight); - - let source = T::AccountMapping::into_h160(from); - let target = Decode::decode(&mut to.as_ref()).map_err(|_| XvmCallError { - error: XvmError::EncodingFailure, - consumed_weight: PLACEHOLDER_WEIGHT, - })?; - let bounded_input = BoundedVec::>::try_from(input) - .map_err(|_| XvmCallError { - error: XvmError::InputTooLarge, - consumed_weight: PLACEHOLDER_WEIGHT, - })?; - - let (post_dispatch_info, call_info) = Transact::xvm_transact( - source, - CheckedEthereumTx { - gas_limit: U256::from(gas_limit), - target, - value, - input: bounded_input, - maybe_access_list: None, - }, - ) - .map_err(|e| { - let consumed_weight = e.post_info.actual_weight.unwrap_or_default(); - XvmCallError { - error: XvmError::ExecutionError(Into::<&str>::into(e.error).into()), - consumed_weight, - } - })?; - - log::trace!( - target: "xvm::EVM::xvm_call", - "EVM XVM call result: exit_reason: {:?}, used_gas: {:?}", call_info.exit_reason, call_info.used_gas, - ); - - Ok(XvmCallOk { - output: call_info.value, - consumed_weight: post_dispatch_info.actual_weight.unwrap_or_default(), - }) - } -} diff --git a/pallets/pallet-xvm/src/lib.rs b/pallets/pallet-xvm/src/lib.rs deleted file mode 100644 index c38b8bcb6..000000000 --- a/pallets/pallet-xvm/src/lib.rs +++ /dev/null @@ -1,229 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later - -// Astar is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Astar is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Astar. If not, see . - -//! # XVM pallet -//! -//! ## Overview -//! -//! ## Interface -//! -//! ### Dispatchable Function -//! -//! -//! ### Other -//! -//! - -#![cfg_attr(not(feature = "std"), no_std)] - -use frame_support::weights::Weight; -use parity_scale_codec::{Decode, Encode}; -use sp_runtime::{traits::Member, RuntimeDebug}; -use sp_std::prelude::*; - -pub mod pallet; -pub use pallet::pallet::*; - -/// EVM call adapter. -#[cfg(feature = "evm")] -pub mod evm; - -/// Wasm call adapter. -#[cfg(feature = "wasm")] -pub mod wasm; - -/// Unique VM identifier. -pub type VmId = u8; - -// TODO: remove later after solution is properly benchmarked -// Just a arbitrary weight constant to avoid having ZERO weight in some parts of execution -pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 0); - -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] -pub enum XvmError { - VmNotRecognized, - EncodingFailure, - ContextConversionFailed, - OutOfGas, - ExecutionError(Vec), - InputTooLarge, - // extend this list as part of improved error handling -} - -// TODO: Currently our precompile/chain-extension calls rely on direct `Call` usage of XVM pallet. -// This is perfectly fine when we're just calling a function in other VM and are interested whether the call was -// successful or not. -// -// Problem arises IF we want to get back arbitrary read value from the other VM - `DispatchResultWithPostInfo` isn't enough for this. -// We need to receive back a concrete value back from the other VM. - -/// Denotes a successful XVM call execution -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] -pub struct XvmCallOk { - /// Output of XVM call. E.g. if call was a query, this will contain query response. - output: Vec, - /// Total consumed weight. This is in context of Substrate (1 unit of weight ~ 1 ps of execution time) - consumed_weight: Weight, -} - -impl XvmCallOk { - pub fn output(&self) -> &[u8] { - &self.output - } -} - -/// Denotes an successful XVM call execution -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] -pub struct XvmCallError { - /// Result of XVM call - // TODO: use XvmError enum from pallet? Perhaps that's a better approach. Or at least provide mapping? - error: XvmError, - /// Total consumed weight. This is in context of Substrate (1 unit of weight ~ 1 ps of execution time) - consumed_weight: Weight, -} - -impl XvmCallError { - pub fn error(&self) -> &XvmError { - &self.error - } -} - -/// Result for executing X-VM calls -pub type XvmResult = Result; - -pub fn consumed_weight(result: &XvmResult) -> Weight { - match result { - Ok(res) => res.consumed_weight, - Err(err) => err.consumed_weight, - } -} - -/// XVM context consist of unique ID and optional execution arguments. -#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] -pub struct XvmContext { - /// Identifier (should be unique for each VM in tuple). - pub id: VmId, - /// Max allowed weight for the call - pub max_weight: Weight, - /// Encoded VM execution environment. - pub env: Option>, -} - -/// The engine that support synchronous smart contract execution. -/// For example, EVM. -pub trait SyncVM { - /// Unique VM identifier. - fn id() -> VmId; - - /// Make a call to VM contract and return result or error. - /// - /// - fn xvm_call(context: XvmContext, from: AccountId, to: Vec, input: Vec) -> XvmResult; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl SyncVM for Tuple { - fn id() -> VmId { - Default::default() - } - - fn xvm_call(context: XvmContext, from: AccountId, to: Vec, input: Vec) -> XvmResult { - for_tuples!( #( - if Tuple::id() == context.id { - log::trace!( - target: "xvm::SyncVm::xvm_call", - "VM found, run XVM call: {:?}, {:?}, {:?}, {:?}", - context, from, to, input, - ); - return Tuple::xvm_call(context, from, to, input) - } - )* ); - log::trace!( - target: "xvm::SyncVm::xvm_call", - "VM with ID {:?} not found", context.id - ); - Err(XvmCallError { - error: XvmError::VmNotRecognized, - consumed_weight: PLACEHOLDER_WEIGHT, - }) - } -} - -/// The engine that support asynchronous smart contract execution. -/// For example, XCVM. -pub trait AsyncVM { - /// Unique VM identifier. - fn id() -> VmId; - - /// Send a message. - fn xvm_send(context: XvmContext, from: AccountId, to: Vec, message: Vec) -> XvmResult; - - /// Query for incoming messages. - fn xvm_query(context: XvmContext, inbox: AccountId) -> XvmResult; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl AsyncVM for Tuple { - fn id() -> VmId { - Default::default() - } - - fn xvm_send(context: XvmContext, from: AccountId, to: Vec, message: Vec) -> XvmResult { - for_tuples!( #( - if Tuple::id() == context.id { - log::trace!( - target: "xvm::AsyncVM::xvm_send", - "VM found, send message: {:?}, {:?}, {:?}, {:?}", - context, from, to, message, - ); - return Tuple::xvm_send(context, from, to, message) - } - )* ); - log::trace!( - target: "xvm::AsyncVM::xvm_send", - "VM with ID {:?} not found", context.id - ); - - Err(XvmCallError { - error: XvmError::VmNotRecognized, - consumed_weight: PLACEHOLDER_WEIGHT, - }) - } - - fn xvm_query(context: XvmContext, inbox: AccountId) -> XvmResult { - for_tuples!( #( - if Tuple::id() == context.id { - log::trace!( - target: "xvm::AsyncVM::xvm_query", - "VM found, query messages: {:?} {:?}", - context, inbox, - ); - return Tuple::xvm_query(context, inbox) - } - )* ); - log::trace!( - target: "xvm::AsyncVM::xvm_query", - "VM with ID {:?} not found", context.id - ); - - Err(XvmCallError { - error: XvmError::VmNotRecognized, - consumed_weight: PLACEHOLDER_WEIGHT, - }) - } -} diff --git a/pallets/pallet-xvm/src/pallet/mod.rs b/pallets/pallet-xvm/src/pallet/mod.rs deleted file mode 100644 index b34d4090a..000000000 --- a/pallets/pallet-xvm/src/pallet/mod.rs +++ /dev/null @@ -1,160 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later - -// Astar is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Astar is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Astar. If not, see . - -//! # XVM pallet -//! -//! ## Overview -//! -//! -//! ## Interface -//! -//! ### Dispatchable Function -//! -//! -//! ### Other -//! -//! - -#[frame_support::pallet] -#[allow(clippy::module_inception)] -pub mod pallet { - use crate::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - #[pallet::without_storage_info] - pub struct Pallet(PhantomData); - - #[pallet::config] - pub trait Config: frame_system::Config { - /// Supported synchronous VM list, for example (EVM, WASM) - type SyncVM: SyncVM; - /// Supported asynchronous VM list. - type AsyncVM: AsyncVM; - /// General event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - } - - #[pallet::error] - pub enum Error {} - - #[pallet::event] - #[pallet::generate_deposit(pub(crate) fn deposit_event)] - pub enum Event { - XvmCall { result: Result, XvmError> }, - XvmSend { result: Result, XvmError> }, - XvmQuery { result: Result, XvmError> }, - } - - impl Pallet { - /// Internal interface for cross-pallet invocation. - /// Essentially does the same thing as `xvm_call`, but a bit differently: - /// - It does not verify origin - /// - It does not use `Dispatchable` API (cannot be called from tx) - /// - It does not deposit event upon completion - /// - It returns `XvmResult` letting the caller get return data directly - pub fn xvm_bare_call( - context: XvmContext, - from: T::AccountId, - to: Vec, - input: Vec, - ) -> XvmResult { - let result = T::SyncVM::xvm_call(context, from, to, input); - - log::trace!( - target: "xvm::pallet::xvm_bare_call", - "Execution result: {:?}", result - ); - - result - } - } - - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(context.max_weight)] - pub fn xvm_call( - origin: OriginFor, - context: XvmContext, - to: Vec, - input: Vec, - ) -> DispatchResultWithPostInfo { - let from = ensure_signed(origin)?; - - // Executing XVM call logic itself will consume some weight so that should be subtracted from the max allowed weight of XCM call - // TODO: fix - //context.max_weight = context.max_weight - PLACEHOLDER_WEIGHT; - - let result = T::SyncVM::xvm_call(context, from, to, input); - let consumed_weight = consumed_weight(&result); - - log::trace!( - target: "xvm::pallet::xvm_call", - "Execution result: {:?}, consumed_weight: {:?}", result, consumed_weight, - ); - - Self::deposit_event(Event::::XvmCall { - result: match result { - Ok(result) => Ok(result.output), - Err(result) => Err(result.error), - }, - }); - - Ok(Some(consumed_weight).into()) - } - - #[pallet::call_index(1)] - #[pallet::weight(context.max_weight)] - pub fn xvm_send( - origin: OriginFor, - context: XvmContext, - to: Vec, - message: Vec, - ) -> DispatchResultWithPostInfo { - let from = ensure_signed(origin)?; - let result = T::AsyncVM::xvm_send(context, from, to, message); - - Self::deposit_event(Event::::XvmSend { - result: match result { - Ok(result) => Ok(result.output), - Err(result) => Err(result.error), - }, - }); - - Ok(().into()) - } - - #[pallet::call_index(2)] - #[pallet::weight(context.max_weight)] - pub fn xvm_query(origin: OriginFor, context: XvmContext) -> DispatchResultWithPostInfo { - let inbox = ensure_signed(origin)?; - let result = T::AsyncVM::xvm_query(context, inbox); - - Self::deposit_event(Event::::XvmQuery { - result: match result { - Ok(result) => Ok(result.output), - Err(result) => Err(result.error), - }, - }); - - Ok(().into()) - } - } -} diff --git a/pallets/pallet-xvm/src/wasm.rs b/pallets/pallet-xvm/src/wasm.rs deleted file mode 100644 index d034f4282..000000000 --- a/pallets/pallet-xvm/src/wasm.rs +++ /dev/null @@ -1,93 +0,0 @@ -// This file is part of Astar. - -// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later - -// Astar is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Astar is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Astar. If not, see . - -//! WASM (substrate contracts) support for XVM pallet. - -use crate::*; -use frame_support::traits::Currency; -use parity_scale_codec::HasCompact; -use scale_info::TypeInfo; -use sp_runtime::traits::Get; -use sp_runtime::traits::StaticLookup; -use sp_std::fmt::Debug; -pub struct WASM(sp_std::marker::PhantomData<(I, T)>); - -type BalanceOf = <::Currency as Currency< - ::AccountId, ->>::Balance; - -impl SyncVM for WASM -where - I: Get, - T: pallet_contracts::Config + frame_system::Config, - as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, -{ - fn id() -> VmId { - I::get() - } - - fn xvm_call(context: XvmContext, from: T::AccountId, to: Vec, input: Vec) -> XvmResult { - log::trace!( - target: "xvm::WASM::xvm_call", - "Start WASM XVM: {:?}, {:?}, {:?}", - from, to, input, - ); - let gas_limit = context.max_weight; - log::trace!( - target: "xvm::WASM::xvm_call", - "WASM xvm call gas (weight) limit: {:?}", gas_limit); - let dest = Decode::decode(&mut to.as_ref()).map_err(|_| XvmCallError { - error: XvmError::EncodingFailure, - consumed_weight: PLACEHOLDER_WEIGHT, - })?; - - let dest = T::Lookup::lookup(dest).map_err(|error| XvmCallError { - error: XvmError::ExecutionError(Into::<&str>::into(error).into()), - consumed_weight: PLACEHOLDER_WEIGHT, - })?; - let call_result = pallet_contracts::Pallet::::bare_call( - from, // no need to check origin, we consider it signed here - dest, - Default::default(), - gas_limit.into(), - None, - input, - false, - pallet_contracts::Determinism::Deterministic, - ); - - log::trace!( - target: "xvm::WASM::xvm_call", - "WASM XVM call result: {:?}", call_result - ); - - let consumed_weight = call_result.gas_consumed; - - match call_result.result { - Ok(success) => Ok(XvmCallOk { - output: success.data, - consumed_weight, - }), - - Err(error) => Err(XvmCallError { - error: XvmError::ExecutionError(Into::<&str>::into(error).into()), - consumed_weight, - }), - } - } -} diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml index e25f833db..0f0c1576e 100644 --- a/pallets/xvm/Cargo.toml +++ b/pallets/xvm/Cargo.toml @@ -1,13 +1,12 @@ [package] -name = "pallet-xvm-v2" -version = "0.2.1" +name = "pallet-xvm" +version = "0.2.2" authors.workspace = true edition.workspace = true homepage.workspace = true repository.workspace = true [dependencies] -impl-trait-for-tuples = { workspace = true } log = { workspace = true } serde = { workspace = true, optional = true } @@ -38,22 +37,29 @@ pallet-ethereum-checked = { workspace = true } [features] default = ["std"] std = [ + "log/std", "parity-scale-codec/std", "frame-support/std", "frame-system/std", "pallet-contracts/std", "pallet-evm/std", "scale-info/std", - "serde", + "serde/std", "sp-core/std", "sp-runtime/std", "sp-std/std", "astar-primitives/std", "pallet-ethereum-checked/std", + "frame-benchmarking?/std", ] runtime-benchmarks = [ "frame-benchmarking", "pallet-ethereum-checked/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = [ + "frame-support/try-runtime", + "pallet-contracts/try-runtime", + "pallet-evm/try-runtime", + "pallet-ethereum-checked/try-runtime", +] diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 133af0197..04d578c5b 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -29,92 +29,24 @@ //! //! +#![cfg_attr(not(feature = "std"), no_std)] + use frame_support::{pallet_prelude::*, traits::ConstU32, BoundedVec}; use pallet_evm::GasWeightMapping; -use parity_scale_codec::{Decode, Encode}; -use scale_info::TypeInfo; +use parity_scale_codec::Decode; use sp_core::U256; -use sp_runtime::{traits::StaticLookup, RuntimeDebug}; -use sp_std::{marker::PhantomData, prelude::*, result::Result}; - -use astar_primitives::ethereum_checked::{ - AccountMapping, CheckedEthereumTransact, CheckedEthereumTx, MAX_ETHEREUM_TX_INPUT_SIZE, +use sp_runtime::traits::StaticLookup; +use sp_std::{marker::PhantomData, prelude::*}; + +use astar_primitives::{ + ethereum_checked::{ + AccountMapping, CheckedEthereumTransact, CheckedEthereumTx, MAX_ETHEREUM_TX_INPUT_SIZE, + }, + xvm::{CallError, CallErrorWithWeight, CallInfo, Context, VmId, XvmCall, XvmCallResult}, }; pub use pallet::*; -// TODO: move types and traits to `astar-primitives`. - -/// XVM call info on success. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CallInfo { - /// Output of the call. - pub output: Vec, - /// Actual used weight. - pub used_weight: Weight, -} - -/// XVM call error on failure. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum CallError { - /// The call failed on EVM or WASM execution. - ExecutionFailed(Vec), - /// Input is too large. - InputTooLarge, - /// Target contract address is invalid. - InvalidTarget, - /// Calling the contracts in the same VM is not allowed. - SameVmCallNotAllowed, -} - -/// XVM call error with used weight info. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct CallErrorWithWeight { - /// Error info. - pub error: CallError, - /// Actual used weight. - pub used_weight: Weight, -} - -/// XVM call result. -pub type XvmCallResult = Result; - -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum Vm { - Evm, - Wasm, -} - -// TODO: Note caller shouldn't be able to specify `source_vm`. -/// XVM context. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct XvmContext { - /// The source VM of the call. - pub source_vm: Vm, - /// The target VM of the call. - pub target_vm: Vm, - /// Max weight limit. - pub weight_limit: Weight, - /// Optional encoded execution environment. - pub env: Option>, -} - -pub trait XvmCall { - /// Call a contract in XVM. - /// - /// Parameters: - /// - `context`: XVM context. - /// - `source`: Caller Id. - /// - `target`: Target contract address. - /// - `input`: call input data. - fn xvm_call( - context: XvmContext, - source: AccountId, - target: Vec, - input: Vec, - ) -> XvmCallResult; -} - #[frame_support::pallet] pub mod pallet { use super::*; @@ -135,13 +67,14 @@ pub mod pallet { } impl XvmCall for Pallet { - fn xvm_call( - context: XvmContext, + fn call( + context: Context, + vm_id: VmId, source: T::AccountId, target: Vec, input: Vec, ) -> XvmCallResult { - Pallet::::do_xvm_call(context, source, target, input, false) + Pallet::::do_call(context, vm_id, source, target, input, false) } } @@ -149,28 +82,29 @@ impl XvmCall for Pallet { pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); impl Pallet { - fn do_xvm_call( - context: XvmContext, + fn do_call( + context: Context, + vm_id: VmId, source: T::AccountId, target: Vec, input: Vec, skip_execution: bool, ) -> XvmCallResult { - if context.source_vm == context.target_vm { + if context.source_vm_id == vm_id { return Err(CallErrorWithWeight { error: CallError::SameVmCallNotAllowed, used_weight: PLACEHOLDER_WEIGHT, }); } - match context.source_vm { - Vm::Evm => Pallet::::evm_call(context, source, target, input, skip_execution), - Vm::Wasm => Pallet::::wasm_call(context, source, target, input, skip_execution), + match context.source_vm_id { + VmId::Evm => Pallet::::evm_call(context, source, target, input, skip_execution), + VmId::Wasm => Pallet::::wasm_call(context, source, target, input, skip_execution), } } fn evm_call( - context: XvmContext, + context: Context, source: T::AccountId, target: Vec, input: Vec, @@ -234,7 +168,7 @@ impl Pallet { } fn wasm_call( - context: XvmContext, + context: Context, source: T::AccountId, target: Vec, input: Vec, @@ -292,11 +226,12 @@ impl Pallet { #[cfg(feature = "runtime-benchmarks")] pub fn xvm_call_without_execution( - context: XvmContext, + context: Context, + vm_id: VmId, source: T::AccountId, target: Vec, input: Vec, ) -> XvmCallResult { - Self::do_xvm_call(context, source, target, input, true) + Self::do_call(context, vm_id, source, target, input, true) } } diff --git a/precompiles/xvm/Cargo.toml b/precompiles/xvm/Cargo.toml index cb431293f..652816f42 100644 --- a/precompiles/xvm/Cargo.toml +++ b/precompiles/xvm/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pallet-evm-precompile-xvm" description = "Cross-VM call support for EVM." -version = "0.1.0" +version = "0.1.1" authors.workspace = true edition.workspace = true homepage.workspace = true @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] log = { workspace = true } num_enum = { workspace = true } -pallet-xvm = { workspace = true } precompile-utils = { workspace = true } # Substrate @@ -26,6 +25,10 @@ sp-std = { workspace = true } fp-evm = { workspace = true } pallet-evm = { workspace = true } +# Astar +astar-primitives = { workspace = true } +pallet-xvm = { workspace = true } + [dev-dependencies] derive_more = { workspace = true } hex-literal = { workspace = true } @@ -35,9 +38,12 @@ serde = { workspace = true } precompile-utils = { workspace = true, features = ["testing"] } pallet-balances = { workspace = true } +pallet-contracts = { workspace = true } pallet-timestamp = { workspace = true } sp-runtime = { workspace = true } +pallet-ethereum-checked = { workspace = true } + [features] default = ["std"] std = [ @@ -46,10 +52,11 @@ std = [ "frame-support/std", "frame-system/std", "pallet-evm/std", - "pallet-xvm/std", "precompile-utils/std", "sp-core/std", "sp-std/std", "sp-io/std", "sp-runtime/std", + "pallet-xvm/std", + "astar-primitives/std", ] diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs index 1b4ec02ee..d33237b40 100644 --- a/precompiles/xvm/src/lib.rs +++ b/precompiles/xvm/src/lib.rs @@ -19,11 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(test, feature(assert_matches))] +use astar_primitives::xvm::{Context, VmId, XvmCall}; use fp_evm::{PrecompileHandle, PrecompileOutput}; -use frame_support::dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}; -use pallet_evm::{AddressMapping, Precompile}; -use pallet_xvm::XvmContext; -use parity_scale_codec::Decode; +use frame_support::dispatch::Dispatchable; +use pallet_evm::{AddressMapping, GasWeightMapping, Precompile}; use sp_runtime::codec::Encode; use sp_std::marker::PhantomData; use sp_std::prelude::*; @@ -51,8 +50,6 @@ where R: pallet_evm::Config + pallet_xvm::Config, <::RuntimeCall as Dispatchable>::RuntimeOrigin: From>, - ::RuntimeCall: - From> + Dispatchable + GetDispatchInfo, { fn execute(handle: &mut impl PrecompileHandle) -> EvmResult { log::trace!(target: "xvm-precompile", "In XVM precompile"); @@ -73,30 +70,28 @@ where R: pallet_evm::Config + pallet_xvm::Config, <::RuntimeCall as Dispatchable>::RuntimeOrigin: From>, - ::RuntimeCall: - From> + Dispatchable + GetDispatchInfo, { fn xvm_call(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = handle.read_input()?; input.expect_arguments(4)?; - // Read arguments and check it - // TODO: This approach probably needs to be revised - does contract call need to specify gas/weight? Usually it is implicit. - let context_raw = input.read::()?; - let context: XvmContext = Decode::decode(&mut context_raw.0.as_ref()) - .map_err(|_| revert("can not decode XVM context"))?; + let vm_id = { + let id = input.read::()?; + id.try_into().map_err(|_| revert("invalid vm id")) + }?; - // Fetch the remaining gas (weight) available for execution - // TODO: rework - //let remaining_gas = handle.remaining_gas(); - //let remaining_weight = R::GasWeightMapping::gas_to_weight(remaining_gas); - //context.max_weight = remaining_weight; + let remaining_gas = handle.remaining_gas(); + let weight_limit = R::GasWeightMapping::gas_to_weight(remaining_gas, true); + let xvm_context = Context { + source_vm_id: VmId::Evm, + weight_limit, + }; let call_to = input.read::()?.0; let call_input = input.read::()?.0; let from = R::AddressMapping::into_account_id(handle.context().caller); - match &pallet_xvm::Pallet::::xvm_bare_call(context, from, call_to, call_input) { + match &pallet_xvm::Pallet::::call(xvm_context, vm_id, from, call_to, call_input) { Ok(success) => { log::trace!( target: "xvm-precompile::xvm_call", @@ -106,7 +101,7 @@ where Ok(succeed( EvmDataWriter::new() .write(true) - .write(Bytes(success.output().to_vec())) // TODO redundant clone + .write(Bytes(success.output.to_vec())) // TODO redundant clone .build(), )) } @@ -118,7 +113,7 @@ where ); let mut error_buffer = Vec::new(); - failure.error().encode_to(&mut error_buffer); + failure.error.encode_to(&mut error_buffer); Ok(succeed( EvmDataWriter::new() diff --git a/precompiles/xvm/src/tests.rs b/precompiles/xvm/src/tests.rs index 2f3ba8183..d87d164a5 100644 --- a/precompiles/xvm/src/tests.rs +++ b/precompiles/xvm/src/tests.rs @@ -59,7 +59,7 @@ fn wrong_argument_reverts() { #[test] fn correct_arguments_works() { - let context: XvmContext = Default::default(); + let context: Context = Default::default(); ExtBuilder::default().build().execute_with(|| { precompiles() .prepare_test( diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 386a79f5a..777ba49fd 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -26,6 +26,9 @@ pub mod xcm; /// Checked Ethereum transaction primitives. pub mod ethereum_checked; +/// XVM primitives. +pub mod xvm; + use sp_runtime::traits::BlakeTwo256; use sp_runtime::{ generic, diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs new file mode 100644 index 000000000..9a8c444a4 --- /dev/null +++ b/primitives/src/xvm.rs @@ -0,0 +1,110 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +use 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 = CallError; + + 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(CallError::InvalidVmId) + } + } +} + +/// XVM call info on success. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CallInfo { + /// Output of the call. + pub output: Vec, + /// Actual used weight. + pub used_weight: Weight, +} + +/// XVM call error on failure. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum CallError { + /// Invalid VM id. + InvalidVmId, + /// The call failed on EVM or WASM execution. + ExecutionFailed(Vec), + /// Input is too large. + InputTooLarge, + /// Target contract address is invalid. + InvalidTarget, + /// Calling the contracts in the same VM is not allowed. + SameVmCallNotAllowed, +} + +/// XVM call error with used weight info. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CallErrorWithWeight { + /// Error info. + pub error: CallError, + /// Actual used weight. + pub used_weight: Weight, +} + +/// XVM call result. +pub type XvmCallResult = 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. + fn call( + context: Context, + vm_id: VmId, + source: AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult; +} diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index b5873f008..cb6451ba7 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -75,7 +75,7 @@ pallet-evm-precompile-dapps-staking = { workspace = true } pallet-evm-precompile-sr25519 = { workspace = true } pallet-evm-precompile-substrate-ecdsa = { workspace = true } pallet-evm-precompile-xvm = { workspace = true } -pallet-xvm = { workspace = true, features = ["evm", "wasm"] } +pallet-xvm = { workspace = true } # Moonbeam tracing moonbeam-evm-tracer = { workspace = true, optional = true } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 50aad7f25..dc01e5708 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -470,14 +470,8 @@ parameter_types! { pub WasmId: u8 = 0x1F; } -use pallet_xvm::{evm, wasm}; impl pallet_xvm::Config for Runtime { - type SyncVM = ( - evm::EVM, - wasm::WASM, - ); - type AsyncVM = (); - type RuntimeEvent = RuntimeEvent; + type EthereumTransact = EthereumChecked; } parameter_types! { @@ -909,7 +903,6 @@ impl InstanceFilter for ProxyType { | RuntimeCall::Council(..) | RuntimeCall::TechnicalCommittee(..) | RuntimeCall::Treasury(..) - | RuntimeCall::Xvm(..) ) } // All Runtime calls from Pallet Balances allowed for proxy account diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index 12c2c14ea..a1cb4ab9a 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -113,7 +113,7 @@ pallet-evm-precompile-xcm = { workspace = true } pallet-evm-precompile-xvm = { workspace = true } pallet-xc-asset-config = { workspace = true } pallet-xcm = { workspace = true } -pallet-xvm = { workspace = true, features = ["evm", "wasm"] } +pallet-xvm = { workspace = true } # Moonbeam tracing moonbeam-evm-tracer = { workspace = true, optional = true } diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 0a46aab23..8eb90e297 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -68,7 +68,8 @@ use sp_runtime::{ use sp_std::prelude::*; pub use astar_primitives::{ - AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature, + ethereum_checked::CheckedEthereumTransact, AccountId, Address, AssetId, Balance, BlockNumber, + Hash, Header, Index, Signature, }; use astar_primitives::xcm::AssetLocationIdConverter; @@ -782,19 +783,8 @@ impl pallet_ethereum_checked::Config for Runtime { type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; } -parameter_types! { - pub EvmId: u8 = 0x0F; - pub WasmId: u8 = 0x1F; -} - -use pallet_xvm::{evm, wasm}; impl pallet_xvm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SyncVM = ( - evm::EVM, - wasm::WASM, - ); - type AsyncVM = (); + type EthereumTransact = EthereumChecked; } parameter_types! { @@ -1136,7 +1126,6 @@ impl InstanceFilter for ProxyType { | RuntimeCall::Council(..) | RuntimeCall::TechnicalCommittee(..) | RuntimeCall::Treasury(..) - | RuntimeCall::Xvm(..) ) } // All Runtime calls from Pallet Balances allowed for proxy account From e576f744c3beb5fec4cbb2ab1166c523b34f4b77 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Tue, 25 Jul 2023 23:42:50 +1200 Subject: [PATCH 07/26] Update xvm precompiles mock & tests. --- Cargo.lock | 2 + precompiles/xvm/Cargo.toml | 7 +++- precompiles/xvm/src/lib.rs | 13 +++---- precompiles/xvm/src/mock.rs | 75 ++++++++++++++++++++++++++++++++++-- precompiles/xvm/src/tests.rs | 10 ++--- 5 files changed, 87 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d7e36cf6..27948edda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7304,8 +7304,10 @@ dependencies = [ "num_enum", "pallet-balances", "pallet-contracts", + "pallet-ethereum", "pallet-ethereum-checked", "pallet-evm", + "pallet-insecure-randomness-collective-flip", "pallet-timestamp", "pallet-xvm", "parity-scale-codec", diff --git a/precompiles/xvm/Cargo.toml b/precompiles/xvm/Cargo.toml index 652816f42..3f28053fe 100644 --- a/precompiles/xvm/Cargo.toml +++ b/precompiles/xvm/Cargo.toml @@ -40,9 +40,10 @@ precompile-utils = { workspace = true, features = ["testing"] } pallet-balances = { workspace = true } pallet-contracts = { workspace = true } pallet-timestamp = { workspace = true } -sp-runtime = { workspace = true } - +pallet-ethereum = { workspace = true } pallet-ethereum-checked = { workspace = true } +pallet-insecure-randomness-collective-flip = { workspace = true } +sp-runtime = { workspace = true } [features] default = ["std"] @@ -59,4 +60,6 @@ std = [ "sp-runtime/std", "pallet-xvm/std", "astar-primitives/std", + "pallet-balances/std", + "pallet-ethereum/std", ] diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs index d33237b40..349b5f3c3 100644 --- a/precompiles/xvm/src/lib.rs +++ b/precompiles/xvm/src/lib.rs @@ -39,7 +39,7 @@ mod tests; #[precompile_utils::generate_function_selector] #[derive(Debug, PartialEq)] pub enum Action { - XvmCall = "xvm_call(bytes,bytes,bytes)", + XvmCall = "xvm_call(uint8,bytes,bytes)", } /// A precompile that expose XVM related functions. @@ -73,7 +73,7 @@ where { fn xvm_call(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = handle.read_input()?; - input.expect_arguments(4)?; + input.expect_arguments(3)?; let vm_id = { let id = input.read::()?; @@ -91,7 +91,7 @@ where let call_input = input.read::()?.0; let from = R::AddressMapping::into_account_id(handle.context().caller); - match &pallet_xvm::Pallet::::call(xvm_context, vm_id, from, call_to, call_input) { + match pallet_xvm::Pallet::::call(xvm_context, vm_id, from, call_to, call_input) { Ok(success) => { log::trace!( target: "xvm-precompile::xvm_call", @@ -101,7 +101,7 @@ where Ok(succeed( EvmDataWriter::new() .write(true) - .write(Bytes(success.output.to_vec())) // TODO redundant clone + .write(Bytes(success.output)) .build(), )) } @@ -112,13 +112,10 @@ where "failure: {:?}", failure ); - let mut error_buffer = Vec::new(); - failure.error.encode_to(&mut error_buffer); - Ok(succeed( EvmDataWriter::new() .write(false) - .write(Bytes(error_buffer)) + .write(Bytes(failure.error.encode())) .build(), )) } diff --git a/precompiles/xvm/src/mock.rs b/precompiles/xvm/src/mock.rs index 5ebfaad7a..217903057 100644 --- a/precompiles/xvm/src/mock.rs +++ b/precompiles/xvm/src/mock.rs @@ -21,7 +21,11 @@ use super::*; use fp_evm::IsPrecompileResult; -use frame_support::{construct_runtime, parameter_types, traits::Everything, weights::Weight}; +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstBool, ConstU32, Everything, Nothing}, + weights::Weight, +}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; @@ -223,10 +227,69 @@ impl pallet_evm::Config for Runtime { type WeightInfo = (); } -impl pallet_xvm::Config for Runtime { +impl pallet_ethereum::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = (); + type ExtraDataLength = ConstU32<30>; +} + +impl pallet_insecure_randomness_collective_flip::Config for Runtime {} + +parameter_types! { + pub const DepositPerItem: Balance = 1_000; + pub const DepositPerByte: Balance = 1_000; + pub DeletionWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX); + pub Schedule: pallet_contracts::Schedule = Default::default(); +} + +impl pallet_contracts::Config for Runtime { + type Time = Timestamp; + type Randomness = RandomnessCollectiveFlip; + type Currency = Balances; type RuntimeEvent = RuntimeEvent; - type SyncVM = (); - type AsyncVM = (); + type RuntimeCall = RuntimeCall; + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type CallStack = [pallet_contracts::Frame; 5]; + type WeightPrice = (); + type WeightInfo = pallet_contracts::weights::SubstrateWeight; + type ChainExtension = (); + type DeletionQueueDepth = ConstU32<128>; + type DeletionWeightLimit = DeletionWeightLimit; + type Schedule = Schedule; + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; +} + +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + } +} + +parameter_types! { + pub XvmTxWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX); +} + +impl pallet_ethereum_checked::Config for Runtime { + type ReservedXcmpWeight = XvmTxWeightLimit; + type XvmTxWeightLimit = XvmTxWeightLimit; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type AccountMapping = HashedAccountMapping; + type XcmTransactOrigin = pallet_ethereum_checked::EnsureXcmEthereumTx; + type WeightInfo = (); +} + +impl pallet_xvm::Config for Runtime { + type EthereumTransact = EthereumChecked; } // Configure a mock runtime to test the pallet. @@ -240,6 +303,10 @@ construct_runtime!( Balances: pallet_balances, Evm: pallet_evm, Timestamp: pallet_timestamp, + RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, + Contracts: pallet_contracts, + Ethereum: pallet_ethereum, + EthereumChecked: pallet_ethereum_checked, Xvm: pallet_xvm, } ); diff --git a/precompiles/xvm/src/tests.rs b/precompiles/xvm/src/tests.rs index d87d164a5..844267fc4 100644 --- a/precompiles/xvm/src/tests.rs +++ b/precompiles/xvm/src/tests.rs @@ -19,6 +19,7 @@ use crate::mock::*; use crate::*; +use astar_primitives::xvm::CallError; use parity_scale_codec::Encode; use precompile_utils::testing::*; use precompile_utils::EvmDataWriter; @@ -49,25 +50,22 @@ fn wrong_argument_reverts() { .write(0u8) .write(Bytes(b"".to_vec())) .write(Bytes(b"".to_vec())) - .write(Bytes(b"".to_vec())) .build(), ) .expect_no_logs() - .execute_reverts(|output| output == b"can not decode XVM context"); + .execute_reverts(|output| output == b"invalid vm id"); }) } #[test] fn correct_arguments_works() { - let context: Context = Default::default(); ExtBuilder::default().build().execute_with(|| { precompiles() .prepare_test( TestAccount::Alice, PRECOMPILE_ADDRESS, EvmDataWriter::new_with_selector(Action::XvmCall) - .write(Bytes(context.encode())) - .write(Bytes(b"".to_vec())) + .write(0x1Fu8) .write(Bytes(b"".to_vec())) .write(Bytes(b"".to_vec())) .build(), @@ -76,7 +74,7 @@ fn correct_arguments_works() { .execute_returns( EvmDataWriter::new() .write(false) // the XVM call should succeed but the internal should fail - .write(vec![0u8]) + .write(Bytes(CallError::InvalidTarget.encode())) .build(), ); }) From 401cf8c9622f73441b80462e3a649d4caa2625ec Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Wed, 26 Jul 2023 16:38:45 +1200 Subject: [PATCH 08/26] Replace 'UnknownError' with concrete errors. --- Cargo.lock | 1 + chain-extensions/types/xvm/Cargo.toml | 2 ++ chain-extensions/types/xvm/src/lib.rs | 39 ++++++++++++++++----------- chain-extensions/xvm/src/lib.rs | 23 ++++++++-------- pallets/xvm/Cargo.toml | 3 +-- precompiles/xvm/Cargo.toml | 6 ++--- primitives/src/xvm.rs | 12 ++++----- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27948edda..d3b3762d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15514,6 +15514,7 @@ dependencies = [ name = "xvm-chain-extension-types" version = "0.1.0" dependencies = [ + "astar-primitives", "parity-scale-codec", "scale-info", "sp-runtime", diff --git a/chain-extensions/types/xvm/Cargo.toml b/chain-extensions/types/xvm/Cargo.toml index dd9129cc2..e9888174c 100644 --- a/chain-extensions/types/xvm/Cargo.toml +++ b/chain-extensions/types/xvm/Cargo.toml @@ -9,6 +9,7 @@ homepage.workspace = true repository.workspace = true [dependencies] +astar-primitives = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } sp-runtime = { workspace = true } @@ -21,4 +22,5 @@ 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 index 76443104f..c1cd231cd 100644 --- a/chain-extensions/types/xvm/src/lib.rs +++ b/chain-extensions/types/xvm/src/lib.rs @@ -18,31 +18,41 @@ #![cfg_attr(not(feature = "std"), no_std)] +use astar_primitives::xvm::CallError; use parity_scale_codec::{Decode, Encode}; -use sp_runtime::{DispatchError, ModuleError}; 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 - Success = 0, - // TODO: expand this with concrete XVM errors - /// Error not (yet) covered by a dedidacted code - UnknownError = 255, + Ok, + /// Failure + Err(u32), } -impl TryFrom for XvmExecutionResult { - type Error = DispatchError; +impl From for XvmExecutionResult { + fn from(input: CallError) -> Self { + use CallError::*; - fn try_from(input: DispatchError) -> Result { - let _error_text = match input { - DispatchError::Module(ModuleError { message, .. }) => message, - _ => Some("No module error Info"), + // `0` is reserved for `Ok` + let error_code = match input { + InvalidVmId => 1, + SameVmCallNotAllowed => 2, + InvalidTarget => 3, + InputTooLarge => 4, + ExecutionFailed(_) => 5, }; + Self::Err(error_code) + } +} - // TODO: expand this with concrete XVM errors (see dapps-staking types for example) - Ok(XvmExecutionResult::UnknownError) +impl From for u32 { + fn from(input: XvmExecutionResult) -> Self { + match input { + XvmExecutionResult::Ok => 0, + XvmExecutionResult::Err(code) => code, + } } } @@ -55,6 +65,3 @@ pub struct XvmCallArgs { /// Encoded call params pub input: Vec, } - -pub const FRONTIER_VM_ID: u8 = 0x0F; -pub const PARITY_WASM_VM_ID: u8 = 0x1F; diff --git a/chain-extensions/xvm/src/lib.rs b/chain-extensions/xvm/src/lib.rs index 5f419fe23..2fb0504ca 100644 --- a/chain-extensions/xvm/src/lib.rs +++ b/chain-extensions/xvm/src/lib.rs @@ -84,12 +84,12 @@ where }; let vm_id = { - let result = vm_id.try_into(); - match result { + match TryInto::::try_into(vm_id) { Ok(id) => id, - Err(_) => { + Err(err) => { // TODO: Propagate error - return Ok(RetVal::Converging(XvmExecutionResult::UnknownError as u32)); + let result = Into::::into(err); + return Ok(RetVal::Converging(result.into())); } } }; @@ -103,25 +103,26 @@ where env.adjust_weight(charged_weight, actual_weight); match call_result { - Ok(success) => { + Ok(info) => { log::trace!( target: "xvm-extension::xvm_call", - "success: {:?}", success + "info: {:?}", info ); - let buffer: sp_std::vec::Vec<_> = success.output.encode(); + let buffer: sp_std::vec::Vec<_> = info.output.encode(); env.write(&buffer, false, None)?; - Ok(RetVal::Converging(XvmExecutionResult::Success as u32)) + Ok(RetVal::Converging(XvmExecutionResult::Ok.into())) } - Err(failure) => { + Err(err) => { log::trace!( target: "xvm-extension::xvm_call", - "failure: {:?}", failure + "err: {:?}", err ); // TODO Propagate error - Ok(RetVal::Converging(XvmExecutionResult::UnknownError as u32)) + let result = Into::::into(err.error); + Ok(RetVal::Converging(result.into())) } } } diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml index 0f0c1576e..8d5213d22 100644 --- a/pallets/xvm/Cargo.toml +++ b/pallets/xvm/Cargo.toml @@ -44,13 +44,12 @@ std = [ "pallet-contracts/std", "pallet-evm/std", "scale-info/std", - "serde/std", + "serde", "sp-core/std", "sp-runtime/std", "sp-std/std", "astar-primitives/std", "pallet-ethereum-checked/std", - "frame-benchmarking?/std", ] runtime-benchmarks = [ diff --git a/precompiles/xvm/Cargo.toml b/precompiles/xvm/Cargo.toml index 3f28053fe..70b7fb997 100644 --- a/precompiles/xvm/Cargo.toml +++ b/precompiles/xvm/Cargo.toml @@ -39,10 +39,10 @@ precompile-utils = { workspace = true, features = ["testing"] } pallet-balances = { workspace = true } pallet-contracts = { workspace = true } -pallet-timestamp = { workspace = true } pallet-ethereum = { workspace = true } pallet-ethereum-checked = { workspace = true } pallet-insecure-randomness-collective-flip = { workspace = true } +pallet-timestamp = { workspace = true } sp-runtime = { workspace = true } [features] @@ -60,6 +60,6 @@ std = [ "sp-runtime/std", "pallet-xvm/std", "astar-primitives/std", - "pallet-balances/std", - "pallet-ethereum/std", + "pallet-balances/std", + "pallet-ethereum/std", ] diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs index 9a8c444a4..168e1c1fe 100644 --- a/primitives/src/xvm.rs +++ b/primitives/src/xvm.rs @@ -58,14 +58,14 @@ pub struct CallInfo { pub enum CallError { /// Invalid VM id. InvalidVmId, - /// The call failed on EVM or WASM execution. - ExecutionFailed(Vec), - /// Input is too large. - InputTooLarge, - /// Target contract address is invalid. - InvalidTarget, /// Calling the contracts in the same VM is not allowed. SameVmCallNotAllowed, + /// Target contract address is invalid. + InvalidTarget, + /// Input is too large. + InputTooLarge, + /// The call failed on EVM or WASM execution. + ExecutionFailed(Vec), } /// XVM call error with used weight info. From e4106316a73cbc2d531f32483cc6c074b404f439 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Wed, 26 Jul 2023 17:16:32 +1200 Subject: [PATCH 09/26] Update CE & precompile. --- Cargo.lock | 5 -- chain-extensions/xvm/Cargo.toml | 2 - chain-extensions/xvm/src/lib.rs | 12 +-- precompiles/xvm/Cargo.toml | 11 +-- precompiles/xvm/evm_sdk/flipper.sol | 4 +- precompiles/xvm/src/lib.rs | 14 +-- precompiles/xvm/src/mock.rs | 115 +++++++++--------------- runtime/local/src/chain_extensions.rs | 7 +- runtime/local/src/lib.rs | 2 +- runtime/local/src/precompiles.rs | 6 +- runtime/shibuya/src/chain_extensions.rs | 7 +- runtime/shibuya/src/lib.rs | 2 +- runtime/shibuya/src/precompiles.rs | 6 +- 13 files changed, 76 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b3762d4..d7e28f03a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6744,7 +6744,6 @@ dependencies = [ "num-traits", "pallet-contracts", "pallet-contracts-primitives", - "pallet-xvm", "parity-scale-codec", "scale-info", "sp-core", @@ -7304,12 +7303,8 @@ dependencies = [ "num_enum", "pallet-balances", "pallet-contracts", - "pallet-ethereum", - "pallet-ethereum-checked", "pallet-evm", - "pallet-insecure-randomness-collective-flip", "pallet-timestamp", - "pallet-xvm", "parity-scale-codec", "precompile-utils", "scale-info", diff --git a/chain-extensions/xvm/Cargo.toml b/chain-extensions/xvm/Cargo.toml index 333e22d8a..ef28b90db 100644 --- a/chain-extensions/xvm/Cargo.toml +++ b/chain-extensions/xvm/Cargo.toml @@ -23,7 +23,6 @@ sp-std = { workspace = true } # Astar astar-primitives = { workspace = true } -pallet-xvm = { workspace = true } xvm-chain-extension-types = { workspace = true } [features] @@ -40,6 +39,5 @@ std = [ "sp-core/std", "sp-runtime/std", # Astar - "pallet-xvm/std", "astar-primitives/std", ] diff --git a/chain-extensions/xvm/src/lib.rs b/chain-extensions/xvm/src/lib.rs index 2fb0504ca..7f9231ac8 100644 --- a/chain-extensions/xvm/src/lib.rs +++ b/chain-extensions/xvm/src/lib.rs @@ -44,17 +44,18 @@ impl TryFrom for XvmFuncId { } /// XVM chain extension. -pub struct XvmExtension(PhantomData); +pub struct XvmExtension(PhantomData<(T, XC)>); -impl Default for XvmExtension { +impl Default for XvmExtension { fn default() -> Self { XvmExtension(PhantomData) } } -impl ChainExtension for XvmExtension +impl ChainExtension for XvmExtension where - T: pallet_contracts::Config + pallet_xvm::Config, + T: pallet_contracts::Config, + XC: XvmCall, { fn call(&mut self, env: Environment) -> Result where @@ -93,8 +94,7 @@ where } } }; - let call_result = - pallet_xvm::Pallet::::call(xvm_context, vm_id, caller, to, input); + let call_result = XC::call(xvm_context, vm_id, caller, to, input); let actual_weight = match call_result { Ok(ref info) => info.used_weight, diff --git a/precompiles/xvm/Cargo.toml b/precompiles/xvm/Cargo.toml index 70b7fb997..e88c0d5b3 100644 --- a/precompiles/xvm/Cargo.toml +++ b/precompiles/xvm/Cargo.toml @@ -27,7 +27,6 @@ pallet-evm = { workspace = true } # Astar astar-primitives = { workspace = true } -pallet-xvm = { workspace = true } [dev-dependencies] derive_more = { workspace = true } @@ -37,11 +36,8 @@ serde = { workspace = true } precompile-utils = { workspace = true, features = ["testing"] } -pallet-balances = { workspace = true } -pallet-contracts = { workspace = true } -pallet-ethereum = { workspace = true } -pallet-ethereum-checked = { workspace = true } -pallet-insecure-randomness-collective-flip = { workspace = true } +pallet-balances = { workspace = true, features = ["std"] } +pallet-contracts = { workspace = true, features = ["std"] } pallet-timestamp = { workspace = true } sp-runtime = { workspace = true } @@ -58,8 +54,5 @@ std = [ "sp-std/std", "sp-io/std", "sp-runtime/std", - "pallet-xvm/std", "astar-primitives/std", - "pallet-balances/std", - "pallet-ethereum/std", ] diff --git a/precompiles/xvm/evm_sdk/flipper.sol b/precompiles/xvm/evm_sdk/flipper.sol index a15eaefd9..fcbfdd3d4 100644 --- a/precompiles/xvm/evm_sdk/flipper.sol +++ b/precompiles/xvm/evm_sdk/flipper.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; interface XVM { function xvm_call( - bytes calldata context, + uint8 calldata vm_id, bytes calldata to, bytes calldata input, ) external; @@ -13,6 +13,6 @@ library Flipper { function flip(bytes to) { bytes input = "0xcafecafe"; - XVM_PRECOMPILE.xvm_call(0x1f00, to, input); + XVM_PRECOMPILE.xvm_call(0x1F, to, input); } } diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs index 349b5f3c3..231ebf8b0 100644 --- a/precompiles/xvm/src/lib.rs +++ b/precompiles/xvm/src/lib.rs @@ -43,13 +43,14 @@ pub enum Action { } /// A precompile that expose XVM related functions. -pub struct XvmPrecompile(PhantomData); +pub struct XvmPrecompile(PhantomData<(T, XC)>); -impl Precompile for XvmPrecompile +impl Precompile for XvmPrecompile where - R: pallet_evm::Config + pallet_xvm::Config, + R: pallet_evm::Config, <::RuntimeCall as Dispatchable>::RuntimeOrigin: From>, + XC: XvmCall, { fn execute(handle: &mut impl PrecompileHandle) -> EvmResult { log::trace!(target: "xvm-precompile", "In XVM precompile"); @@ -65,11 +66,12 @@ where } } -impl XvmPrecompile +impl XvmPrecompile where - R: pallet_evm::Config + pallet_xvm::Config, + R: pallet_evm::Config, <::RuntimeCall as Dispatchable>::RuntimeOrigin: From>, + XC: XvmCall, { fn xvm_call(handle: &mut impl PrecompileHandle) -> EvmResult { let mut input = handle.read_input()?; @@ -91,7 +93,7 @@ where let call_input = input.read::()?.0; let from = R::AddressMapping::into_account_id(handle.context().caller); - match pallet_xvm::Pallet::::call(xvm_context, vm_id, from, call_to, call_input) { + match XC::call(xvm_context, vm_id, from, call_to, call_input) { Ok(success) => { log::trace!( target: "xvm-precompile::xvm_call", diff --git a/precompiles/xvm/src/mock.rs b/precompiles/xvm/src/mock.rs index 217903057..4c9fe078f 100644 --- a/precompiles/xvm/src/mock.rs +++ b/precompiles/xvm/src/mock.rs @@ -22,9 +22,7 @@ use super::*; use fp_evm::IsPrecompileResult; use frame_support::{ - construct_runtime, parameter_types, - traits::{ConstBool, ConstU32, Everything, Nothing}, - weights::Weight, + construct_runtime, ensure, parameter_types, traits::Everything, weights::Weight, }; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -39,6 +37,8 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, }; +use astar_primitives::xvm::{CallError::*, CallErrorWithWeight, CallInfo, XvmCallResult}; + pub type AccountId = TestAccount; pub type Balance = u128; pub type BlockNumber = u64; @@ -154,12 +154,14 @@ pub struct TestPrecompileSet(PhantomData); impl PrecompileSet for TestPrecompileSet where - R: pallet_evm::Config + pallet_xvm::Config, - XvmPrecompile: Precompile, + 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)), + a if a == PRECOMPILE_ADDRESS => { + Some(XvmPrecompile::::execute(handle)) + } _ => None, } } @@ -227,71 +229,43 @@ impl pallet_evm::Config for Runtime { type WeightInfo = (); } -impl pallet_ethereum::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type StateRoot = pallet_ethereum::IntermediateStateRoot; - type PostLogContent = (); - type ExtraDataLength = ConstU32<30>; -} - -impl pallet_insecure_randomness_collective_flip::Config for Runtime {} - -parameter_types! { - pub const DepositPerItem: Balance = 1_000; - pub const DepositPerByte: Balance = 1_000; - pub DeletionWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX); - pub Schedule: pallet_contracts::Schedule = Default::default(); -} - -impl pallet_contracts::Config for Runtime { - type Time = Timestamp; - type Randomness = RandomnessCollectiveFlip; - type Currency = Balances; - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type CallFilter = Nothing; - type DepositPerItem = DepositPerItem; - type DepositPerByte = DepositPerByte; - type CallStack = [pallet_contracts::Frame; 5]; - type WeightPrice = (); - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = (); - type DeletionQueueDepth = ConstU32<128>; - type DeletionWeightLimit = DeletionWeightLimit; - type Schedule = Schedule; - type AddressGenerator = pallet_contracts::DefaultAddressGenerator; - type MaxCodeLen = ConstU32<{ 123 * 1024 }>; - type MaxStorageKeyLen = ConstU32<128>; - type UnsafeUnstableInterface = ConstBool; - type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; -} - -pub struct HashedAccountMapping; -impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { - fn into_h160(account_id: AccountId) -> H160 { - let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); +struct MockXvmWithArgsCheck; +impl XvmCall for MockXvmWithArgsCheck { + fn call( + _context: Context, + vm_id: VmId, + _source: AccountId, + target: Vec, + input: Vec, + ) -> XvmCallResult { + ensure!( + vm_id != VmId::Evm, + CallErrorWithWeight { + error: SameVmCallNotAllowed, + used_weight: Weight::zero() + } + ); + ensure!( + target.len() == 20, + CallErrorWithWeight { + error: InvalidTarget, + used_weight: Weight::zero() + } + ); + ensure!( + input.len() <= 1024, + CallErrorWithWeight { + error: InputTooLarge, + used_weight: Weight::zero() + } + ); + Ok(CallInfo { + output: vec![], + used_weight: Weight::zero(), + }) } } -parameter_types! { - pub XvmTxWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX); -} - -impl pallet_ethereum_checked::Config for Runtime { - type ReservedXcmpWeight = XvmTxWeightLimit; - type XvmTxWeightLimit = XvmTxWeightLimit; - type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; - type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; - type AccountMapping = HashedAccountMapping; - type XcmTransactOrigin = pallet_ethereum_checked::EnsureXcmEthereumTx; - type WeightInfo = (); -} - -impl pallet_xvm::Config for Runtime { - type EthereumTransact = EthereumChecked; -} - // Configure a mock runtime to test the pallet. construct_runtime!( pub enum Runtime where @@ -303,11 +277,6 @@ construct_runtime!( Balances: pallet_balances, Evm: pallet_evm, Timestamp: pallet_timestamp, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, - Contracts: pallet_contracts, - Ethereum: pallet_ethereum, - EthereumChecked: pallet_ethereum_checked, - Xvm: pallet_xvm, } ); diff --git a/runtime/local/src/chain_extensions.rs b/runtime/local/src/chain_extensions.rs index e42df76c4..9bd7609c5 100644 --- a/runtime/local/src/chain_extensions.rs +++ b/runtime/local/src/chain_extensions.rs @@ -16,10 +16,9 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -//! -use super::Runtime; +use super::{Runtime, Xvm}; + /// Registered WASM contracts chain extensions. -/// pub use pallet_chain_extension_assets::AssetsExtension; use pallet_contracts::chain_extension::RegisteredChainExtension; @@ -32,7 +31,7 @@ impl RegisteredChainExtension for DappsStakingExtension { const ID: u16 = 00; } -impl RegisteredChainExtension for XvmExtension { +impl RegisteredChainExtension for XvmExtension { const ID: u16 = 01; } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index dc01e5708..0e4ba1ce1 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -813,7 +813,7 @@ impl pallet_contracts::Config for Runtime { type WeightInfo = pallet_contracts::weights::SubstrateWeight; type ChainExtension = ( DappsStakingExtension, - XvmExtension, + XvmExtension, AssetsExtension>, ); type DeletionQueueDepth = ConstU32<128>; diff --git a/runtime/local/src/precompiles.rs b/runtime/local/src/precompiles.rs index 6eddf6629..9e0bf989d 100644 --- a/runtime/local/src/precompiles.rs +++ b/runtime/local/src/precompiles.rs @@ -67,7 +67,7 @@ impl PrecompileSet for LocalNetworkPrecompiles where Erc20AssetsPrecompileSet: PrecompileSet, DappsStakingWrapper: Precompile, - XvmPrecompile: Precompile, + XvmPrecompile>: Precompile, Dispatch: Precompile, R: pallet_evm::Config + pallet_xvm::Config @@ -110,7 +110,9 @@ where // SubstrateEcdsa 0x5003 a if a == hash(20483) => Some(SubstrateEcdsaPrecompile::::execute(handle)), // Xvm 0x5005 - a if a == hash(20485) => Some(XvmPrecompile::::execute(handle)), + a if a == hash(20485) => { + Some(XvmPrecompile::>::execute(handle)) + } // If the address matches asset prefix, the we route through the asset precompile set a if &a.to_fixed_bytes()[0..4] == ASSET_PRECOMPILE_ADDRESS_PREFIX => { Erc20AssetsPrecompileSet::::new().execute(handle) diff --git a/runtime/shibuya/src/chain_extensions.rs b/runtime/shibuya/src/chain_extensions.rs index e42df76c4..9bd7609c5 100644 --- a/runtime/shibuya/src/chain_extensions.rs +++ b/runtime/shibuya/src/chain_extensions.rs @@ -16,10 +16,9 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -//! -use super::Runtime; +use super::{Runtime, Xvm}; + /// Registered WASM contracts chain extensions. -/// pub use pallet_chain_extension_assets::AssetsExtension; use pallet_contracts::chain_extension::RegisteredChainExtension; @@ -32,7 +31,7 @@ impl RegisteredChainExtension for DappsStakingExtension { const ID: u16 = 00; } -impl RegisteredChainExtension for XvmExtension { +impl RegisteredChainExtension for XvmExtension { const ID: u16 = 01; } diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 8eb90e297..16ae014b0 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -678,7 +678,7 @@ impl pallet_contracts::Config for Runtime { type WeightInfo = pallet_contracts::weights::SubstrateWeight; type ChainExtension = ( DappsStakingExtension, - XvmExtension, + XvmExtension, AssetsExtension>, ); type DeletionQueueDepth = ConstU32<128>; diff --git a/runtime/shibuya/src/precompiles.rs b/runtime/shibuya/src/precompiles.rs index bd8d1714c..d84839aa4 100644 --- a/runtime/shibuya/src/precompiles.rs +++ b/runtime/shibuya/src/precompiles.rs @@ -73,7 +73,7 @@ where Erc20AssetsPrecompileSet: PrecompileSet, DappsStakingWrapper: Precompile, XcmPrecompile: Precompile, - XvmPrecompile: Precompile, + XvmPrecompile>: Precompile, Dispatch: Precompile, R: pallet_evm::Config + pallet_assets::Config @@ -120,7 +120,9 @@ where // Xcm 0x5004 a if a == hash(20484) => Some(XcmPrecompile::::execute(handle)), // Xvm 0x5005 - a if a == hash(20485) => Some(XvmPrecompile::::execute(handle)), + a if a == hash(20485) => { + Some(XvmPrecompile::>::execute(handle)) + } // If the address matches asset prefix, the we route through the asset precompile set a if &a.to_fixed_bytes()[0..4] == ASSET_PRECOMPILE_ADDRESS_PREFIX => { Erc20AssetsPrecompileSet::::new().execute(handle) From 819c7f8e17f794a6d7fcd763643fa52f5ff1333a Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Wed, 26 Jul 2023 17:30:52 +1200 Subject: [PATCH 10/26] Clean up. --- Cargo.lock | 1 - pallets/xvm/src/lib.rs | 11 ++++++----- precompiles/xvm/Cargo.toml | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7e28f03a..41d2040ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7302,7 +7302,6 @@ dependencies = [ "log", "num_enum", "pallet-balances", - "pallet-contracts", "pallet-evm", "pallet-timestamp", "parity-scale-codec", diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 04d578c5b..789d5b482 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -31,7 +31,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::{pallet_prelude::*, traits::ConstU32, BoundedVec}; +use frame_support::{ensure, pallet_prelude::*, traits::ConstU32, BoundedVec}; use pallet_evm::GasWeightMapping; use parity_scale_codec::Decode; use sp_core::U256; @@ -90,12 +90,13 @@ impl Pallet { input: Vec, skip_execution: bool, ) -> XvmCallResult { - if context.source_vm_id == vm_id { - return Err(CallErrorWithWeight { + ensure!( + context.source_vm_id != vm_id, + CallErrorWithWeight { error: CallError::SameVmCallNotAllowed, used_weight: PLACEHOLDER_WEIGHT, - }); - } + } + ); match context.source_vm_id { VmId::Evm => Pallet::::evm_call(context, source, target, input, skip_execution), diff --git a/precompiles/xvm/Cargo.toml b/precompiles/xvm/Cargo.toml index e88c0d5b3..397a41237 100644 --- a/precompiles/xvm/Cargo.toml +++ b/precompiles/xvm/Cargo.toml @@ -37,7 +37,6 @@ serde = { workspace = true } precompile-utils = { workspace = true, features = ["testing"] } pallet-balances = { workspace = true, features = ["std"] } -pallet-contracts = { workspace = true, features = ["std"] } pallet-timestamp = { workspace = true } sp-runtime = { workspace = true } From 50c04b265ca331086e3370bcd15fca3a6f891cde Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Wed, 26 Jul 2023 21:17:27 +1200 Subject: [PATCH 11/26] Benchmarks and mock. --- Cargo.lock | 6 +- pallets/ethereum-checked/src/lib.rs | 2 +- pallets/xvm/Cargo.toml | 10 +- pallets/xvm/src/benchmarking.rs | 78 +++++++++++ pallets/xvm/src/lib.rs | 33 +++-- pallets/xvm/src/mock.rs | 207 ++++++++++++++++++++++++++++ precompiles/xvm/src/mock.rs | 4 +- primitives/src/xvm.rs | 4 +- runtime/local/src/lib.rs | 2 + runtime/shibuya/Cargo.toml | 1 + runtime/shibuya/src/lib.rs | 3 + 11 files changed, 326 insertions(+), 24 deletions(-) create mode 100644 pallets/xvm/src/benchmarking.rs create mode 100644 pallets/xvm/src/mock.rs diff --git a/Cargo.lock b/Cargo.lock index 41d2040ba..dedb95240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8045,17 +8045,21 @@ name = "pallet-xvm" version = "0.2.2" dependencies = [ "astar-primitives", + "fp-evm", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "pallet-contracts", - "pallet-ethereum-checked", "pallet-evm", + "pallet-insecure-randomness-collective-flip", + "pallet-timestamp", "parity-scale-codec", "scale-info", "serde", "sp-core", + "sp-io", "sp-runtime", "sp-std", ] diff --git a/pallets/ethereum-checked/src/lib.rs b/pallets/ethereum-checked/src/lib.rs index 7ac4f0320..c627f141b 100644 --- a/pallets/ethereum-checked/src/lib.rs +++ b/pallets/ethereum-checked/src/lib.rs @@ -20,7 +20,7 @@ //! //! ## Overview //! -//! A `pallet-ethererum` like pallet that execute transactions from checked source, +//! A `pallet-ethereum like pallet that execute transactions from checked source, //! like XCM remote call, cross-VM call, etc. Only `Call` transactions are supported //! (no `Create`). //! diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml index 8d5213d22..6121f5657 100644 --- a/pallets/xvm/Cargo.toml +++ b/pallets/xvm/Cargo.toml @@ -30,9 +30,13 @@ pallet-contracts = { workspace = true } # Astar astar-primitives = { workspace = true } -pallet-ethereum-checked = { workspace = true } [dev-dependencies] +sp-io = { workspace = true } +fp-evm = { workspace = true } +pallet-timestamp = { workspace = true, features = ["std"] } +pallet-balances = { workspace = true, features = ["std"] } +pallet-insecure-randomness-collective-flip = { workspace = true, features = ["std"] } [features] default = ["std"] @@ -43,22 +47,20 @@ std = [ "frame-system/std", "pallet-contracts/std", "pallet-evm/std", + "pallet-insecure-randomness-collective-flip/std", "scale-info/std", "serde", "sp-core/std", "sp-runtime/std", "sp-std/std", "astar-primitives/std", - "pallet-ethereum-checked/std", ] runtime-benchmarks = [ "frame-benchmarking", - "pallet-ethereum-checked/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "pallet-contracts/try-runtime", "pallet-evm/try-runtime", - "pallet-ethereum-checked/try-runtime", ] diff --git a/pallets/xvm/src/benchmarking.rs b/pallets/xvm/src/benchmarking.rs new file mode 100644 index 000000000..e01342213 --- /dev/null +++ b/pallets/xvm/src/benchmarking.rs @@ -0,0 +1,78 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +use super::*; + +use frame_benchmarking::v2::*; +use parity_scale_codec::Encode; +use sp_core::H160; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn evm_call_without_execution() { + let context = Context { + source_vm_id: VmId::Wasm, + weight_limit: Weight::from_parts(1_000_000, 1_000_000), + }; + let vm_id = VmId::Evm; + let source = whitelisted_caller(); + let target = H160::repeat_byte(1).encode(); + let input = vec![1, 2, 3]; + + #[block] + { + Pallet::::call_without_execution(context, vm_id, source, target, input).unwrap(); + } + } + + #[benchmark] + fn wasm_call_without_execution() { + let context = Context { + source_vm_id: VmId::Evm, + weight_limit: Weight::from_parts(1_000_000, 1_000_000), + }; + let vm_id = VmId::Wasm; + let source = whitelisted_caller(); + let target = whitelisted_caller::().encode(); + let input = vec![1, 2, 3]; + + #[block] + { + Pallet::::call_without_execution(context, vm_id, source, target, input).unwrap(); + } + } + + impl_benchmark_test_suite!( + Pallet, + crate::benchmarking::tests::new_test_ext(), + crate::mock::TestRuntime, + ); +} + +#[cfg(test)] +mod tests { + use crate::mock; + use sp_io::TestExternalities; + + pub fn new_test_ext() -> TestExternalities { + mock::ExtBuilder::default().build() + } +} diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 789d5b482..e5927c264 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -42,9 +42,15 @@ use astar_primitives::{ ethereum_checked::{ AccountMapping, CheckedEthereumTransact, CheckedEthereumTx, MAX_ETHEREUM_TX_INPUT_SIZE, }, - xvm::{CallError, CallErrorWithWeight, CallInfo, Context, VmId, XvmCall, XvmCallResult}, + xvm::{CallError, CallErrorWithWeight, CallInfo, CallResult, Context, VmId, XvmCall}, }; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[cfg(test)] +mod mock; + pub use pallet::*; #[frame_support::pallet] @@ -55,12 +61,11 @@ pub mod pallet { pub struct Pallet(PhantomData); #[pallet::config] - pub trait Config: - frame_system::Config - + pallet_evm::Config - + pallet_ethereum_checked::Config - + pallet_contracts::Config - { + pub trait Config: frame_system::Config + pallet_contracts::Config { + /// Mapping from `Account` to `H160`. + type AccountMapping: AccountMapping; + /// Mapping from Ethereum gas to Substrate weight. + type GasWeightMapping: GasWeightMapping; /// `CheckedEthereumTransact` implementation. type EthereumTransact: CheckedEthereumTransact; } @@ -73,7 +78,7 @@ impl XvmCall for Pallet { source: T::AccountId, target: Vec, input: Vec, - ) -> XvmCallResult { + ) -> CallResult { Pallet::::do_call(context, vm_id, source, target, input, false) } } @@ -89,7 +94,7 @@ impl Pallet { target: Vec, input: Vec, skip_execution: bool, - ) -> XvmCallResult { + ) -> CallResult { ensure!( context.source_vm_id != vm_id, CallErrorWithWeight { @@ -98,7 +103,7 @@ impl Pallet { } ); - match context.source_vm_id { + match vm_id { VmId::Evm => Pallet::::evm_call(context, source, target, input, skip_execution), VmId::Wasm => Pallet::::wasm_call(context, source, target, input, skip_execution), } @@ -110,7 +115,7 @@ impl Pallet { target: Vec, input: Vec, skip_execution: bool, - ) -> XvmCallResult { + ) -> CallResult { log::trace!( target: "xvm::evm_call", "Calling EVM: {:?} {:?}, {:?}, {:?}", @@ -174,7 +179,7 @@ impl Pallet { target: Vec, input: Vec, skip_execution: bool, - ) -> XvmCallResult { + ) -> CallResult { log::trace!( target: "xvm::wasm_call", "Calling WASM: {:?} {:?}, {:?}, {:?}", @@ -226,13 +231,13 @@ impl Pallet { } #[cfg(feature = "runtime-benchmarks")] - pub fn xvm_call_without_execution( + pub fn call_without_execution( context: Context, vm_id: VmId, source: T::AccountId, target: Vec, input: Vec, - ) -> XvmCallResult { + ) -> CallResult { Self::do_call(context, vm_id, source, target, input, true) } } diff --git a/pallets/xvm/src/mock.rs b/pallets/xvm/src/mock.rs new file mode 100644 index 000000000..2c06bc4d6 --- /dev/null +++ b/pallets/xvm/src/mock.rs @@ -0,0 +1,207 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +#![cfg(test)] + +use super::*; +use crate as pallet_xvm; + +use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed}; +use frame_support::{ + construct_runtime, + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, + parameter_types, + sp_io::TestExternalities, + traits::{ConstBool, ConstU128, ConstU64, Nothing}, + weights::Weight, +}; +use sp_core::{H160, H256}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, +}; + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, 0)); +} + +impl frame_system::Config for TestRuntime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = BlockNumber; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for TestRuntime { + type MaxLocks = ConstU32<4>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU128<2>; + type AccountStore = System; + type WeightInfo = (); +} + +impl pallet_timestamp::Config for TestRuntime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3>; + type WeightInfo = (); +} + +impl pallet_insecure_randomness_collective_flip::Config for TestRuntime {} + +parameter_types! { + pub const DepositPerItem: Balance = 1_000; + pub const DepositPerByte: Balance = 1_000; + pub DeletionWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX); + pub Schedule: pallet_contracts::Schedule = Default::default(); +} + +impl pallet_contracts::Config for TestRuntime { + type Time = Timestamp; + type Randomness = RandomnessCollectiveFlip; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type CallStack = [pallet_contracts::Frame; 5]; + type WeightPrice = (); + type WeightInfo = pallet_contracts::weights::SubstrateWeight; + type ChainExtension = (); + type DeletionQueueDepth = ConstU32<128>; + type DeletionWeightLimit = DeletionWeightLimit; + type Schedule = Schedule; + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; +} + +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + } +} + +pub struct MockEthereumTransact; +impl CheckedEthereumTransact for MockEthereumTransact { + fn xvm_transact( + _source: H160, + _checked_tx: CheckedEthereumTx, + ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> { + Ok(( + PostDispatchInfo { + actual_weight: Default::default(), + pays_fee: Default::default(), + }, + EvmCallInfo { + exit_reason: ExitReason::Succeed(ExitSucceed::Returned), + value: Default::default(), + used_gas: Default::default(), + logs: Default::default(), + }, + )) + } +} + +pub struct MockGasWeightMapping; +impl GasWeightMapping for MockGasWeightMapping { + fn gas_to_weight(gas: u64, _without_base_weight: bool) -> Weight { + Weight::from_parts(gas, 0) + } + fn weight_to_gas(weight: Weight) -> u64 { + weight.ref_time() + } +} + +impl pallet_xvm::Config for TestRuntime { + type GasWeightMapping = MockGasWeightMapping; + type AccountMapping = HashedAccountMapping; + type EthereumTransact = MockEthereumTransact; +} + +pub(crate) type AccountId = AccountId32; +pub(crate) type BlockNumber = u64; +pub(crate) type Balance = u128; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub struct TestRuntime + where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, + Contracts: pallet_contracts, + Xvm: pallet_xvm, + } +); + +#[derive(Default)] +pub struct ExtBuilder; + +impl ExtBuilder { + #[allow(dead_code)] + pub fn build(self) -> TestExternalities { + let t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + let mut ext = TestExternalities::from(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext + } +} diff --git a/precompiles/xvm/src/mock.rs b/precompiles/xvm/src/mock.rs index 4c9fe078f..4e591f426 100644 --- a/precompiles/xvm/src/mock.rs +++ b/precompiles/xvm/src/mock.rs @@ -37,7 +37,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, }; -use astar_primitives::xvm::{CallError::*, CallErrorWithWeight, CallInfo, XvmCallResult}; +use astar_primitives::xvm::{CallError::*, CallErrorWithWeight, CallInfo, CallResult}; pub type AccountId = TestAccount; pub type Balance = u128; @@ -237,7 +237,7 @@ impl XvmCall for MockXvmWithArgsCheck { _source: AccountId, target: Vec, input: Vec, - ) -> XvmCallResult { + ) -> CallResult { ensure!( vm_id != VmId::Evm, CallErrorWithWeight { diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs index 168e1c1fe..50d4d472a 100644 --- a/primitives/src/xvm.rs +++ b/primitives/src/xvm.rs @@ -78,7 +78,7 @@ pub struct CallErrorWithWeight { } /// XVM call result. -pub type XvmCallResult = Result; +pub type CallResult = Result; /// XVM context. /// @@ -106,5 +106,5 @@ pub trait XvmCall { source: AccountId, target: Vec, input: Vec, - ) -> XvmCallResult; + ) -> CallResult; } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 0e4ba1ce1..99c166aee 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -471,6 +471,8 @@ parameter_types! { } impl pallet_xvm::Config for Runtime { + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type AccountMapping = HashedAccountMapping; type EthereumTransact = EthereumChecked; } diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index a1cb4ab9a..bfdcbf913 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -255,6 +255,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", + "pallet-xvm/runtime-benchmarks", "polkadot-runtime/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", "astar-primitives/runtime-benchmarks", diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 16ae014b0..d5ae642d1 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -784,6 +784,8 @@ impl pallet_ethereum_checked::Config for Runtime { } impl pallet_xvm::Config for Runtime { + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type AccountMapping = HashedAccountMapping; type EthereumTransact = EthereumChecked; } @@ -1423,6 +1425,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [pallet_xcm, PolkadotXcm] [pallet_ethereum_checked, EthereumChecked] + [pallet_xvm, Xvm] ); } From 6b22ce6bf4ceda52603c3f24b6a960e62ff92b77 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Wed, 26 Jul 2023 21:55:27 +1200 Subject: [PATCH 12/26] Updates for polkadot-v0.9.43. --- chain-extensions/types/xvm/src/lib.rs | 3 ++- chain-extensions/xvm/src/lib.rs | 12 ++++++++---- pallets/xvm/Cargo.toml | 6 +++--- pallets/xvm/src/lib.rs | 6 ++++-- pallets/xvm/src/mock.rs | 17 ++++++++++++----- precompiles/xvm/src/mock.rs | 4 +++- primitives/src/xvm.rs | 2 ++ runtime/shibuya/Cargo.toml | 2 +- 8 files changed, 35 insertions(+), 17 deletions(-) diff --git a/chain-extensions/types/xvm/src/lib.rs b/chain-extensions/types/xvm/src/lib.rs index c1cd231cd..d23ccd910 100644 --- a/chain-extensions/types/xvm/src/lib.rs +++ b/chain-extensions/types/xvm/src/lib.rs @@ -41,7 +41,8 @@ impl From for XvmExecutionResult { SameVmCallNotAllowed => 2, InvalidTarget => 3, InputTooLarge => 4, - ExecutionFailed(_) => 5, + BadOrigin => 5, + ExecutionFailed(_) => 6, }; Self::Err(error_code) } diff --git a/chain-extensions/xvm/src/lib.rs b/chain-extensions/xvm/src/lib.rs index 84b8dd299..9696fc6d7 100644 --- a/chain-extensions/xvm/src/lib.rs +++ b/chain-extensions/xvm/src/lib.rs @@ -18,9 +18,12 @@ #![cfg_attr(not(feature = "std"), no_std)] -use astar_primitives::xvm::{Context, VmId, XvmCall}; +use astar_primitives::xvm::{CallError, Context, VmId, XvmCall}; use frame_support::dispatch::Encode; -use pallet_contracts::{chain_extension::{ChainExtension, Environment, Ext, InitState, RetVal}, Origin}; +use pallet_contracts::{ + chain_extension::{ChainExtension, Environment, Ext, InitState, RetVal}, + Origin, +}; use sp_runtime::DispatchError; use sp_std::marker::PhantomData; use xvm_chain_extension_types::{XvmCallArgs, XvmExecutionResult}; @@ -80,8 +83,9 @@ where target: "xvm-extension::xvm_call", "root origin not supported" ); - // TODO: expand XvmErrors with BadOrigin - return Ok(RetVal::Converging(XvmExecutionResult::UnknownError as u32)); + return Ok(RetVal::Converging( + XvmExecutionResult::from(CallError::BadOrigin).into(), + )); } }; diff --git a/pallets/xvm/Cargo.toml b/pallets/xvm/Cargo.toml index 6121f5657..6f1022bf2 100644 --- a/pallets/xvm/Cargo.toml +++ b/pallets/xvm/Cargo.toml @@ -32,11 +32,11 @@ pallet-contracts = { workspace = true } astar-primitives = { workspace = true } [dev-dependencies] -sp-io = { workspace = true } fp-evm = { workspace = true } -pallet-timestamp = { workspace = true, features = ["std"] } pallet-balances = { workspace = true, features = ["std"] } pallet-insecure-randomness-collective-flip = { workspace = true, features = ["std"] } +pallet-timestamp = { workspace = true, features = ["std"] } +sp-io = { workspace = true } [features] default = ["std"] @@ -47,7 +47,7 @@ std = [ "frame-system/std", "pallet-contracts/std", "pallet-evm/std", - "pallet-insecure-randomness-collective-flip/std", + "pallet-insecure-randomness-collective-flip/std", "scale-info/std", "serde", "sp-core/std", diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index e5927c264..bcb451c14 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -32,6 +32,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::{ensure, pallet_prelude::*, traits::ConstU32, BoundedVec}; +use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; use pallet_evm::GasWeightMapping; use parity_scale_codec::Decode; use sp_core::U256; @@ -209,8 +210,9 @@ impl Pallet { context.weight_limit, None, input, - false, - pallet_contracts::Determinism::Deterministic, + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, ); log::trace!(target: "xvm::wasm_call", "WASM call result: {:?}", call_result); diff --git a/pallets/xvm/src/mock.rs b/pallets/xvm/src/mock.rs index 2c06bc4d6..f080bcb5e 100644 --- a/pallets/xvm/src/mock.rs +++ b/pallets/xvm/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_xvm; -use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed}; +use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; use frame_support::{ construct_runtime, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, @@ -79,6 +79,10 @@ impl pallet_balances::Config for TestRuntime { type ExistentialDeposit = ConstU128<2>; type AccountStore = System; type WeightInfo = (); + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; } impl pallet_timestamp::Config for TestRuntime { @@ -93,7 +97,7 @@ impl pallet_insecure_randomness_collective_flip::Config for TestRuntime {} parameter_types! { pub const DepositPerItem: Balance = 1_000; pub const DepositPerByte: Balance = 1_000; - pub DeletionWeightLimit: Weight = Weight::from_parts(u64::MAX, u64::MAX); + pub const DefaultDepositLimit: Balance = 1_000; pub Schedule: pallet_contracts::Schedule = Default::default(); } @@ -106,12 +110,11 @@ impl pallet_contracts::Config for TestRuntime { 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 DeletionQueueDepth = ConstU32<128>; - type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; type MaxCodeLen = ConstU32<{ 123 * 1024 }>; @@ -142,8 +145,12 @@ impl CheckedEthereumTransact for MockEthereumTransact { EvmCallInfo { exit_reason: ExitReason::Succeed(ExitSucceed::Returned), value: Default::default(), - used_gas: Default::default(), + used_gas: UsedGas { + standard: Default::default(), + effective: Default::default(), + }, logs: Default::default(), + weight_info: None, }, )) } diff --git a/precompiles/xvm/src/mock.rs b/precompiles/xvm/src/mock.rs index 6829093eb..bf209b748 100644 --- a/precompiles/xvm/src/mock.rs +++ b/precompiles/xvm/src/mock.rs @@ -22,7 +22,9 @@ use super::*; use fp_evm::IsPrecompileResult; use frame_support::{ - construct_runtime, ensure, parameter_types, traits::{ConstU32, ConstU64, Everything}, weights::Weight, + construct_runtime, ensure, parameter_types, + traits::{ConstU32, ConstU64, Everything}, + weights::Weight, }; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs index 50d4d472a..e3ae06c52 100644 --- a/primitives/src/xvm.rs +++ b/primitives/src/xvm.rs @@ -64,6 +64,8 @@ pub enum CallError { InvalidTarget, /// Input is too large. InputTooLarge, + /// Bad origin. + BadOrigin, /// The call failed on EVM or WASM execution. ExecutionFailed(Vec), } diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index b8c8d6843..6c0a7d745 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -253,7 +253,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", - "pallet-xvm/runtime-benchmarks", + "pallet-xvm/runtime-benchmarks", "polkadot-runtime/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", "astar-primitives/runtime-benchmarks", From 61220e6ff2d081c1ddcc81ad19f768d4e46d2cde Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 00:53:33 +1200 Subject: [PATCH 13/26] Fix benchmarks. --- pallets/xvm/src/benchmarking.rs | 3 ++- pallets/xvm/src/mock.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pallets/xvm/src/benchmarking.rs b/pallets/xvm/src/benchmarking.rs index e01342213..f416a4bc8 100644 --- a/pallets/xvm/src/benchmarking.rs +++ b/pallets/xvm/src/benchmarking.rs @@ -21,6 +21,7 @@ use super::*; use frame_benchmarking::v2::*; use parity_scale_codec::Encode; use sp_core::H160; +use sp_runtime::MultiAddress; #[benchmarks] mod benchmarks { @@ -51,7 +52,7 @@ mod benchmarks { }; let vm_id = VmId::Wasm; let source = whitelisted_caller(); - let target = whitelisted_caller::().encode(); + let target = MultiAddress::::Id(whitelisted_caller()).encode(); let input = vec![1, 2, 3]; #[block] diff --git a/pallets/xvm/src/mock.rs b/pallets/xvm/src/mock.rs index f080bcb5e..afc9898c1 100644 --- a/pallets/xvm/src/mock.rs +++ b/pallets/xvm/src/mock.rs @@ -33,7 +33,7 @@ use frame_support::{ use sp_core::{H160, H256}; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{AccountIdLookup, BlakeTwo256}, AccountId32, }; @@ -53,7 +53,7 @@ impl frame_system::Config for TestRuntime { type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; - type Lookup = IdentityLookup; + type Lookup = AccountIdLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; From 7b927054e9fb3f39e25b69cddc9f35c7fa8b783e Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 11:00:08 +1200 Subject: [PATCH 14/26] Add benchmarking result and weight info. --- pallets/xvm/src/benchmarking.rs | 1 + pallets/xvm/src/lib.rs | 47 +++++++++++++-------- pallets/xvm/src/mock.rs | 3 +- pallets/xvm/src/weights.rs | 73 +++++++++++++++++++++++++++++++++ runtime/local/src/lib.rs | 1 + runtime/shibuya/src/lib.rs | 1 + 6 files changed, 108 insertions(+), 18 deletions(-) create mode 100644 pallets/xvm/src/weights.rs diff --git a/pallets/xvm/src/benchmarking.rs b/pallets/xvm/src/benchmarking.rs index f416a4bc8..34aab46b6 100644 --- a/pallets/xvm/src/benchmarking.rs +++ b/pallets/xvm/src/benchmarking.rs @@ -19,6 +19,7 @@ use super::*; use frame_benchmarking::v2::*; +use frame_support::weights::Weight; use parity_scale_codec::Encode; use sp_core::H160; use sp_runtime::MultiAddress; diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index bcb451c14..006ce5884 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -31,7 +31,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::{ensure, pallet_prelude::*, traits::ConstU32, BoundedVec}; +use frame_support::{ensure, traits::ConstU32, BoundedVec}; use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; use pallet_evm::GasWeightMapping; use parity_scale_codec::Decode; @@ -49,11 +49,16 @@ use astar_primitives::{ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod weights; +pub use weights::WeightInfo; + #[cfg(test)] mod mock; pub use pallet::*; +pub type WeightInfoOf = ::WeightInfo; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -65,10 +70,15 @@ pub mod pallet { pub trait Config: frame_system::Config + pallet_contracts::Config { /// Mapping from `Account` to `H160`. type AccountMapping: AccountMapping; + /// Mapping from Ethereum gas to Substrate weight. type GasWeightMapping: GasWeightMapping; + /// `CheckedEthereumTransact` implementation. type EthereumTransact: CheckedEthereumTransact; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } } @@ -84,9 +94,6 @@ impl XvmCall for Pallet { } } -// TODO: benchmark XVM calls overhead -pub const PLACEHOLDER_WEIGHT: Weight = Weight::from_parts(1_000_000, 1024); - impl Pallet { fn do_call( context: Context, @@ -100,7 +107,7 @@ impl Pallet { context.source_vm_id != vm_id, CallErrorWithWeight { error: CallError::SameVmCallNotAllowed, - used_weight: PLACEHOLDER_WEIGHT, + used_weight: WeightInfoOf::::evm_call_without_execution(), } ); @@ -129,18 +136,18 @@ impl Pallet { let target_decoded = Decode::decode(&mut target.as_ref()).map_err(|_| CallErrorWithWeight { error: CallError::InvalidTarget, - used_weight: PLACEHOLDER_WEIGHT, + used_weight: WeightInfoOf::::evm_call_without_execution(), })?; let bounded_input = BoundedVec::>::try_from(input) .map_err(|_| CallErrorWithWeight { error: CallError::InputTooLarge, - used_weight: PLACEHOLDER_WEIGHT, + used_weight: WeightInfoOf::::evm_call_without_execution(), })?; if skip_execution { return Ok(CallInfo { output: vec![], - used_weight: PLACEHOLDER_WEIGHT, + used_weight: WeightInfoOf::::evm_call_without_execution(), }); } @@ -155,7 +162,11 @@ impl Pallet { }, ) .map_err(|e| { - let used_weight = e.post_info.actual_weight.unwrap_or_default(); + let used_weight = e + .post_info + .actual_weight + .unwrap_or_default() + .saturating_add(WeightInfoOf::::evm_call_without_execution()); CallErrorWithWeight { error: CallError::ExecutionFailed(Into::<&str>::into(e.error).into()), used_weight, @@ -167,10 +178,13 @@ impl Pallet { "EVM call result: exit_reason: {:?}, used_gas: {:?}", call_info.exit_reason, call_info.used_gas, ); - // TODO: add overhead to used weight + let used_weight = post_dispatch_info + .actual_weight + .unwrap_or_default() + .saturating_add(WeightInfoOf::::evm_call_without_execution()); Ok(CallInfo { output: call_info.value, - used_weight: post_dispatch_info.actual_weight.unwrap_or_default(), + used_weight, }) } @@ -190,7 +204,7 @@ impl Pallet { let dest = { let error = CallErrorWithWeight { error: CallError::InvalidTarget, - used_weight: PLACEHOLDER_WEIGHT, + used_weight: WeightInfoOf::::wasm_call_without_execution(), }; let decoded = Decode::decode(&mut target.as_ref()).map_err(|_| error.clone())?; T::Lookup::lookup(decoded).map_err(|_| error) @@ -199,7 +213,7 @@ impl Pallet { if skip_execution { return Ok(CallInfo { output: vec![], - used_weight: PLACEHOLDER_WEIGHT, + used_weight: WeightInfoOf::::wasm_call_without_execution(), }); } @@ -216,15 +230,14 @@ impl Pallet { ); log::trace!(target: "xvm::wasm_call", "WASM call result: {:?}", call_result); - // TODO: add overhead to used weight - let used_weight = call_result.gas_consumed; - + let used_weight = call_result + .gas_consumed + .saturating_add(WeightInfoOf::::wasm_call_without_execution()); match call_result.result { Ok(success) => Ok(CallInfo { output: success.data, used_weight, }), - Err(error) => Err(CallErrorWithWeight { error: CallError::ExecutionFailed(Into::<&str>::into(error).into()), used_weight, diff --git a/pallets/xvm/src/mock.rs b/pallets/xvm/src/mock.rs index afc9898c1..a02472c3b 100644 --- a/pallets/xvm/src/mock.rs +++ b/pallets/xvm/src/mock.rs @@ -25,10 +25,10 @@ use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; use frame_support::{ construct_runtime, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, + pallet_prelude::*, parameter_types, sp_io::TestExternalities, traits::{ConstBool, ConstU128, ConstU64, Nothing}, - weights::Weight, }; use sp_core::{H160, H256}; use sp_runtime::{ @@ -170,6 +170,7 @@ impl pallet_xvm::Config for TestRuntime { type GasWeightMapping = MockGasWeightMapping; type AccountMapping = HashedAccountMapping; type EthereumTransact = MockEthereumTransact; + type WeightInfo = (); } pub(crate) type AccountId = AccountId32; diff --git a/pallets/xvm/src/weights.rs b/pallets/xvm/src/weights.rs new file mode 100644 index 000000000..5a1995b64 --- /dev/null +++ b/pallets/xvm/src/weights.rs @@ -0,0 +1,73 @@ + +//! Autogenerated weights for pallet_xvm +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-26, 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_without_execution() -> Weight; + fn wasm_call_without_execution() -> Weight; +} + +/// Weights for pallet_xvm using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn evm_call_without_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 284_000 picoseconds. + Weight::from_parts(325_000, 0) + } + fn wasm_call_without_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 302_000 picoseconds. + Weight::from_parts(326_000, 0) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn evm_call_without_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 284_000 picoseconds. + Weight::from_parts(325_000, 0) + } + fn wasm_call_without_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 302_000 picoseconds. + Weight::from_parts(326_000, 0) + } +} diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 9b5cffbc0..765dc47b8 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -475,6 +475,7 @@ impl pallet_xvm::Config for Runtime { type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type AccountMapping = HashedAccountMapping; type EthereumTransact = EthereumChecked; + type WeightInfo = pallet_xvm::weights::SubstrateWeight; } parameter_types! { diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index af8fc1f2f..71547f470 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -790,6 +790,7 @@ impl pallet_xvm::Config for Runtime { type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type AccountMapping = HashedAccountMapping; type EthereumTransact = EthereumChecked; + type WeightInfo = pallet_xvm::weights::SubstrateWeight; } parameter_types! { From 8831ba9bba5d4cefb067ba3935bcbb20a8ef152b Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 11:11:47 +1200 Subject: [PATCH 15/26] Add license header to weight.rs. --- pallets/xvm/src/weights.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pallets/xvm/src/weights.rs b/pallets/xvm/src/weights.rs index 5a1995b64..887f362ca 100644 --- a/pallets/xvm/src/weights.rs +++ b/pallets/xvm/src/weights.rs @@ -1,3 +1,20 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . //! Autogenerated weights for pallet_xvm //! From 5666403f3dde08d7224763809447220599a86c58 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 14:21:19 +1200 Subject: [PATCH 16/26] Add pallet description docstring. --- pallets/xvm/src/lib.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 006ce5884..7bb71acab 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -18,15 +18,21 @@ //! # XVM pallet //! +//! A module to provide +//! //! ## Overview //! -//! ## Interface +//! 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. //! -//! ### Dispatchable Function +//! Together with other functionalities like Chain Extension and precompiles, +//! the XVM pallet enables the runtime to support cross-VM calls. //! +//! ## Interface //! -//! ### Other +//! ### Implementation //! +//! - Implements `XvmCall` trait. //! #![cfg_attr(not(feature = "std"), no_std)] From df8e0626931c1db9431a4330be479aa3386be85c Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 14:45:22 +1200 Subject: [PATCH 17/26] Record gas cost in XVM precompile. --- precompiles/xvm/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs index 2ee025be3..d63f84a47 100644 --- a/precompiles/xvm/src/lib.rs +++ b/precompiles/xvm/src/lib.rs @@ -99,6 +99,8 @@ where "success: {:?}", success ); + handle.record_cost(R::GasWeightMapping::weight_to_gas(success.used_weight)); + Ok(succeed( EvmDataWriter::new() .write(true) @@ -113,6 +115,8 @@ where "failure: {:?}", failure ); + handle.record_cost(R::GasWeightMapping::weight_to_gas(failure.used_weight)); + Ok(succeed( EvmDataWriter::new() .write(false) From 34a3942e12c671c6a5c6792187605484e41e4f9a Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 14:54:22 +1200 Subject: [PATCH 18/26] Less weight is available with overheads cost. --- pallets/xvm/src/benchmarking.rs | 4 ++-- pallets/xvm/src/lib.rs | 40 +++++++++++++++++++++------------ pallets/xvm/src/weights.rs | 12 +++++----- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/pallets/xvm/src/benchmarking.rs b/pallets/xvm/src/benchmarking.rs index 34aab46b6..97edd7d0d 100644 --- a/pallets/xvm/src/benchmarking.rs +++ b/pallets/xvm/src/benchmarking.rs @@ -29,7 +29,7 @@ mod benchmarks { use super::*; #[benchmark] - fn evm_call_without_execution() { + fn evm_call_overheads() { let context = Context { source_vm_id: VmId::Wasm, weight_limit: Weight::from_parts(1_000_000, 1_000_000), @@ -46,7 +46,7 @@ mod benchmarks { } #[benchmark] - fn wasm_call_without_execution() { + fn wasm_call_overheads() { let context = Context { source_vm_id: VmId::Evm, weight_limit: Weight::from_parts(1_000_000, 1_000_000), diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 7bb71acab..487341ec7 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -113,7 +113,10 @@ impl Pallet { context.source_vm_id != vm_id, CallErrorWithWeight { error: CallError::SameVmCallNotAllowed, - used_weight: WeightInfoOf::::evm_call_without_execution(), + used_weight: match vm_id { + VmId::Evm => WeightInfoOf::::evm_call_overheads(), + VmId::Wasm => WeightInfoOf::::wasm_call_overheads(), + }, } ); @@ -136,31 +139,35 @@ impl Pallet { context, source, target, input, ); - let value = U256::zero(); - let gas_limit = T::GasWeightMapping::weight_to_gas(context.weight_limit); - let target_decoded = Decode::decode(&mut target.as_ref()).map_err(|_| CallErrorWithWeight { error: CallError::InvalidTarget, - used_weight: WeightInfoOf::::evm_call_without_execution(), + used_weight: WeightInfoOf::::evm_call_overheads(), })?; let bounded_input = BoundedVec::>::try_from(input) .map_err(|_| CallErrorWithWeight { error: CallError::InputTooLarge, - used_weight: WeightInfoOf::::evm_call_without_execution(), + used_weight: WeightInfoOf::::evm_call_overheads(), })?; if skip_execution { return Ok(CallInfo { output: vec![], - used_weight: WeightInfoOf::::evm_call_without_execution(), + used_weight: WeightInfoOf::::evm_call_overheads(), }); } + let value = U256::zero(); + // With overheads, less weight is available. + let weight_limit = context + .weight_limit + .saturating_sub(WeightInfoOf::::evm_call_overheads()); + let gas_limit = U256::from(T::GasWeightMapping::weight_to_gas(weight_limit)); + let (post_dispatch_info, call_info) = T::EthereumTransact::xvm_transact( T::AccountMapping::into_h160(source), CheckedEthereumTx { - gas_limit: U256::from(gas_limit), + gas_limit, target: target_decoded, value, input: bounded_input, @@ -172,7 +179,7 @@ impl Pallet { .post_info .actual_weight .unwrap_or_default() - .saturating_add(WeightInfoOf::::evm_call_without_execution()); + .saturating_add(WeightInfoOf::::evm_call_overheads()); CallErrorWithWeight { error: CallError::ExecutionFailed(Into::<&str>::into(e.error).into()), used_weight, @@ -187,7 +194,7 @@ impl Pallet { let used_weight = post_dispatch_info .actual_weight .unwrap_or_default() - .saturating_add(WeightInfoOf::::evm_call_without_execution()); + .saturating_add(WeightInfoOf::::evm_call_overheads()); Ok(CallInfo { output: call_info.value, used_weight, @@ -210,7 +217,7 @@ impl Pallet { let dest = { let error = CallErrorWithWeight { error: CallError::InvalidTarget, - used_weight: WeightInfoOf::::wasm_call_without_execution(), + used_weight: WeightInfoOf::::wasm_call_overheads(), }; let decoded = Decode::decode(&mut target.as_ref()).map_err(|_| error.clone())?; T::Lookup::lookup(decoded).map_err(|_| error) @@ -219,15 +226,20 @@ impl Pallet { if skip_execution { return Ok(CallInfo { output: vec![], - used_weight: WeightInfoOf::::wasm_call_without_execution(), + used_weight: WeightInfoOf::::wasm_call_overheads(), }); } + // With overheads, less weight is available. + let weight_limit = context + .weight_limit + .saturating_sub(WeightInfoOf::::wasm_call_overheads()); + let call_result = pallet_contracts::Pallet::::bare_call( source, dest, Default::default(), - context.weight_limit, + weight_limit, None, input, DebugInfo::Skip, @@ -238,7 +250,7 @@ impl Pallet { let used_weight = call_result .gas_consumed - .saturating_add(WeightInfoOf::::wasm_call_without_execution()); + .saturating_add(WeightInfoOf::::wasm_call_overheads()); match call_result.result { Ok(success) => Ok(CallInfo { output: success.data, diff --git a/pallets/xvm/src/weights.rs b/pallets/xvm/src/weights.rs index 887f362ca..aa54337d0 100644 --- a/pallets/xvm/src/weights.rs +++ b/pallets/xvm/src/weights.rs @@ -48,21 +48,21 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_xvm. pub trait WeightInfo { - fn evm_call_without_execution() -> Weight; - fn wasm_call_without_execution() -> Weight; + 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_without_execution() -> Weight { + fn evm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 284_000 picoseconds. Weight::from_parts(325_000, 0) } - fn wasm_call_without_execution() -> Weight { + fn wasm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` @@ -73,14 +73,14 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - fn evm_call_without_execution() -> Weight { + fn evm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` // Minimum execution time: 284_000 picoseconds. Weight::from_parts(325_000, 0) } - fn wasm_call_without_execution() -> Weight { + fn wasm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` From e9ccd4b2a50a80094a39fa2e0a4794e1c72e829e Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 15:00:12 +1200 Subject: [PATCH 19/26] Trace Ethereum transact result. --- pallets/xvm/src/lib.rs | 48 ++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 487341ec7..f0acfa99b 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -164,7 +164,7 @@ impl Pallet { .saturating_sub(WeightInfoOf::::evm_call_overheads()); let gas_limit = U256::from(T::GasWeightMapping::weight_to_gas(weight_limit)); - let (post_dispatch_info, call_info) = T::EthereumTransact::xvm_transact( + let transact_result = T::EthereumTransact::xvm_transact( T::AccountMapping::into_h160(source), CheckedEthereumTx { gas_limit, @@ -173,32 +173,34 @@ impl Pallet { input: bounded_input, maybe_access_list: None, }, - ) - .map_err(|e| { - let used_weight = e - .post_info - .actual_weight - .unwrap_or_default() - .saturating_add(WeightInfoOf::::evm_call_overheads()); - CallErrorWithWeight { - error: CallError::ExecutionFailed(Into::<&str>::into(e.error).into()), - used_weight, - } - })?; - + ); log::trace!( target: "xvm::evm_call", - "EVM call result: exit_reason: {:?}, used_gas: {:?}", call_info.exit_reason, call_info.used_gas, + "EVM call result: {:?}", transact_result, ); - let used_weight = post_dispatch_info - .actual_weight - .unwrap_or_default() - .saturating_add(WeightInfoOf::::evm_call_overheads()); - Ok(CallInfo { - output: call_info.value, - used_weight, - }) + transact_result + .map(|(post_dispatch_info, call_info)| { + let used_weight = post_dispatch_info + .actual_weight + .unwrap_or_default() + .saturating_add(WeightInfoOf::::evm_call_overheads()); + CallInfo { + output: call_info.value, + used_weight, + } + }) + .map_err(|e| { + let used_weight = e + .post_info + .actual_weight + .unwrap_or_default() + .saturating_add(WeightInfoOf::::evm_call_overheads()); + CallErrorWithWeight { + error: CallError::ExecutionFailed(Into::<&str>::into(e.error).into()), + used_weight, + } + }) } fn wasm_call( From cd5d2af6a8f5fd7d25d1668c10254a7c1579bd22 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 15:04:16 +1200 Subject: [PATCH 20/26] Handle record cost result. --- precompiles/xvm/src/lib.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs index d63f84a47..2a18b0788 100644 --- a/precompiles/xvm/src/lib.rs +++ b/precompiles/xvm/src/lib.rs @@ -90,17 +90,23 @@ where let call_to = input.read::()?.0; let call_input = input.read::()?.0; - let from = R::AddressMapping::into_account_id(handle.context().caller); - match XC::call(xvm_context, vm_id, from, call_to, call_input) { + + let call_result = XC::call(xvm_context, vm_id, from, call_to, call_input); + + 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))?; + + match call_result { Ok(success) => { log::trace!( target: "xvm-precompile::xvm_call", "success: {:?}", success ); - handle.record_cost(R::GasWeightMapping::weight_to_gas(success.used_weight)); - Ok(succeed( EvmDataWriter::new() .write(true) @@ -115,8 +121,6 @@ where "failure: {:?}", failure ); - handle.record_cost(R::GasWeightMapping::weight_to_gas(failure.used_weight)); - Ok(succeed( EvmDataWriter::new() .write(false) From 8d4f62e867d5d3d5cae3effcb306ff603795d361 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 15:24:44 +1200 Subject: [PATCH 21/26] Bump Shibuya semver and spec versoin. --- Cargo.lock | 2 +- runtime/shibuya/Cargo.toml | 2 +- runtime/shibuya/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a67441785..513808112 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12299,7 +12299,7 @@ dependencies = [ [[package]] name = "shibuya-runtime" -version = "5.15.0" +version = "5.16.0" dependencies = [ "array-bytes 6.1.0", "astar-primitives", diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index 6c0a7d745..ddb340dbe 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shibuya-runtime" -version = "5.15.0" +version = "5.16.0" build = "build.rs" authors.workspace = true edition.workspace = true diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 71547f470..bc94244c6 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -166,7 +166,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("shibuya"), impl_name: create_runtime_str!("shibuya"), authoring_version: 1, - spec_version: 105, + spec_version: 106, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, From 7482e7bf050c165c27f6875388646b2574c9f21a Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 22:22:37 +1200 Subject: [PATCH 22/26] Apply review suggestions. --- pallets/xvm/src/lib.rs | 14 +++++++------- precompiles/xvm/src/lib.rs | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index f0acfa99b..7ebc6acbd 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -150,13 +150,6 @@ impl Pallet { used_weight: WeightInfoOf::::evm_call_overheads(), })?; - if skip_execution { - return Ok(CallInfo { - output: vec![], - used_weight: WeightInfoOf::::evm_call_overheads(), - }); - } - let value = U256::zero(); // With overheads, less weight is available. let weight_limit = context @@ -164,6 +157,13 @@ impl Pallet { .saturating_sub(WeightInfoOf::::evm_call_overheads()); let gas_limit = U256::from(T::GasWeightMapping::weight_to_gas(weight_limit)); + if skip_execution { + return Ok(CallInfo { + output: vec![], + used_weight: WeightInfoOf::::evm_call_overheads(), + }); + } + let transact_result = T::EthereumTransact::xvm_transact( T::AccountMapping::into_h160(source), CheckedEthereumTx { diff --git a/precompiles/xvm/src/lib.rs b/precompiles/xvm/src/lib.rs index 2a18b0788..78772c524 100644 --- a/precompiles/xvm/src/lib.rs +++ b/precompiles/xvm/src/lib.rs @@ -99,6 +99,8 @@ where 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()))?; match call_result { Ok(success) => { From 3fa315e2b0205884f7ed740d41de5f5b42048604 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 23:30:57 +1200 Subject: [PATCH 23/26] Update with new benchmarking result. --- pallets/xvm/src/weights.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/xvm/src/weights.rs b/pallets/xvm/src/weights.rs index aa54337d0..0479864d9 100644 --- a/pallets/xvm/src/weights.rs +++ b/pallets/xvm/src/weights.rs @@ -19,7 +19,7 @@ //! Autogenerated weights for pallet_xvm //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-27, 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 @@ -59,15 +59,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 284_000 picoseconds. - Weight::from_parts(325_000, 0) + // Minimum execution time: 267_000 picoseconds. + Weight::from_parts(289_000, 0) } fn wasm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 302_000 picoseconds. - Weight::from_parts(326_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(339_000, 0) } } @@ -77,14 +77,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 284_000 picoseconds. - Weight::from_parts(325_000, 0) + // Minimum execution time: 267_000 picoseconds. + Weight::from_parts(289_000, 0) } fn wasm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 302_000 picoseconds. - Weight::from_parts(326_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(339_000, 0) } } From 931117ccd4bc083819faf529789fdc95b2e635ca Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 23:37:43 +1200 Subject: [PATCH 24/26] Improve XVM call benchmarking. --- pallets/xvm/src/lib.rs | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/pallets/xvm/src/lib.rs b/pallets/xvm/src/lib.rs index 7ebc6acbd..5da16856f 100644 --- a/pallets/xvm/src/lib.rs +++ b/pallets/xvm/src/lib.rs @@ -157,6 +157,17 @@ impl Pallet { .saturating_sub(WeightInfoOf::::evm_call_overheads()); let gas_limit = U256::from(T::GasWeightMapping::weight_to_gas(weight_limit)); + let source = T::AccountMapping::into_h160(source); + let tx = CheckedEthereumTx { + gas_limit, + target: target_decoded, + value, + 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(CallInfo { output: vec![], @@ -164,16 +175,7 @@ impl Pallet { }); } - let transact_result = T::EthereumTransact::xvm_transact( - T::AccountMapping::into_h160(source), - CheckedEthereumTx { - gas_limit, - target: target_decoded, - value, - input: bounded_input, - maybe_access_list: None, - }, - ); + let transact_result = T::EthereumTransact::xvm_transact(source, tx); log::trace!( target: "xvm::evm_call", "EVM call result: {:?}", transact_result, @@ -225,6 +227,14 @@ impl Pallet { T::Lookup::lookup(decoded).map_err(|_| error) }?; + // With overheads, less weight is available. + let weight_limit = context + .weight_limit + .saturating_sub(WeightInfoOf::::wasm_call_overheads()); + let value = Default::default(); + + // Note the skip execution check should be exactly before `pallet_contracts::bare_call` + // to benchmark the correct overheads. if skip_execution { return Ok(CallInfo { output: vec![], @@ -232,15 +242,10 @@ impl Pallet { }); } - // With overheads, less weight is available. - let weight_limit = context - .weight_limit - .saturating_sub(WeightInfoOf::::wasm_call_overheads()); - let call_result = pallet_contracts::Pallet::::bare_call( source, dest, - Default::default(), + value, weight_limit, None, input, From ff3b41fd401daf5de5cd42e99b0f57e0ee5ddd83 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Thu, 27 Jul 2023 23:45:53 +1200 Subject: [PATCH 25/26] Make local/shibuya/shiden/astar runtimes and client have the same semver. --- Cargo.lock | 8 ++++---- bin/collator/Cargo.toml | 2 +- runtime/astar/Cargo.toml | 2 +- runtime/local/Cargo.toml | 2 +- runtime/shiden/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 513808112..004fee0ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,7 +404,7 @@ dependencies = [ [[package]] name = "astar-collator" -version = "5.15.0" +version = "5.16.0" dependencies = [ "astar-primitives", "astar-runtime", @@ -529,7 +529,7 @@ dependencies = [ [[package]] name = "astar-runtime" -version = "5.15.0" +version = "5.16.0" dependencies = [ "array-bytes 6.1.0", "astar-primitives", @@ -5475,7 +5475,7 @@ checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "local-runtime" -version = "5.15.0" +version = "5.16.0" dependencies = [ "array-bytes 6.1.0", "astar-primitives", @@ -12407,7 +12407,7 @@ dependencies = [ [[package]] name = "shiden-runtime" -version = "5.15.0" +version = "5.16.0" dependencies = [ "array-bytes 6.1.0", "astar-primitives", diff --git a/bin/collator/Cargo.toml b/bin/collator/Cargo.toml index 9584fc136..d459cc8ba 100644 --- a/bin/collator/Cargo.toml +++ b/bin/collator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "astar-collator" -version = "5.15.0" +version = "5.16.0" description = "Astar collator implementation in Rust." build = "build.rs" default-run = "astar-collator" diff --git a/runtime/astar/Cargo.toml b/runtime/astar/Cargo.toml index 96c4b8ff1..6a585846f 100644 --- a/runtime/astar/Cargo.toml +++ b/runtime/astar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "astar-runtime" -version = "5.15.0" +version = "5.16.0" build = "build.rs" authors.workspace = true edition.workspace = true diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index d17e7d55a..5a5d1de6d 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "local-runtime" -version = "5.15.0" +version = "5.16.0" build = "build.rs" authors.workspace = true edition.workspace = true diff --git a/runtime/shiden/Cargo.toml b/runtime/shiden/Cargo.toml index efcc9d3f0..0268ef47e 100644 --- a/runtime/shiden/Cargo.toml +++ b/runtime/shiden/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shiden-runtime" -version = "5.15.0" +version = "5.16.0" build = "build.rs" authors.workspace = true edition.workspace = true From f6a81fac8347c0b361d9142f34999f332b5b2c64 Mon Sep 17 00:00:00 2001 From: Shaun Wang Date: Fri, 28 Jul 2023 00:52:36 +1200 Subject: [PATCH 26/26] Update with new benchmarking result. --- pallets/xvm/src/weights.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pallets/xvm/src/weights.rs b/pallets/xvm/src/weights.rs index 0479864d9..0d458675c 100644 --- a/pallets/xvm/src/weights.rs +++ b/pallets/xvm/src/weights.rs @@ -59,15 +59,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 267_000 picoseconds. - Weight::from_parts(289_000, 0) + // Minimum execution time: 771_000 picoseconds. + Weight::from_parts(818_000, 0) } fn wasm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 285_000 picoseconds. - Weight::from_parts(339_000, 0) + // Minimum execution time: 304_000 picoseconds. + Weight::from_parts(337_000, 0) } } @@ -77,14 +77,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 267_000 picoseconds. - Weight::from_parts(289_000, 0) + // Minimum execution time: 771_000 picoseconds. + Weight::from_parts(818_000, 0) } fn wasm_call_overheads() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 285_000 picoseconds. - Weight::from_parts(339_000, 0) + // Minimum execution time: 304_000 picoseconds. + Weight::from_parts(337_000, 0) } }