diff --git a/Cargo.lock b/Cargo.lock index 46bb1dda62..36d44bfd40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1942,9 +1942,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm" -version = "0.37.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4448c65b71e8e2b9718232d84d09045eeaaccb2320494e6bd6dbf7e58fec8ff" +checksum = "1099df1dac16f32a136452ad98ee0f1ff42acd3e12ce65bea4462b61d656608a" dependencies = [ "auto_impl", "environmental", @@ -1963,9 +1963,9 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.37.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c51bec0eb68a891c2575c758eaaa1d61373fc51f7caaf216b1fb5c3fea3b5d" +checksum = "4f1f13264b044cb66f0602180f0bc781c29accb41ff560669a3ec15858d5b606" dependencies = [ "parity-scale-codec", "primitive-types", @@ -1975,9 +1975,9 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.37.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b93c59c54fc26522d842f0e0d3f8e8be331c776df18ff3e540b53c2f64d509" +checksum = "8d43eadc395bd1a52990787ca1495c26b0248165444912be075c28909a853b8c" dependencies = [ "environmental", "evm-core", @@ -1987,9 +1987,9 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.37.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79b9459ce64f1a28688397c4013764ce53cd57bb84efc16b5187fa9b05b13ad" +checksum = "2aa5b32f59ec582a5651978004e5c784920291263b7dcb6de418047438e37f4f" dependencies = [ "auto_impl", "environmental", @@ -9514,7 +9514,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.6", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index 0970754595..6767780a4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ bn = { package = "substrate-bn", version = "0.6", default-features = false } environmental = { version = "1.1.4", default-features = false } ethereum = { version = "0.14.0", default-features = false } ethereum-types = { version = "0.14.1", default-features = false } -evm = { version = "0.37.0", default-features = false } +evm = { version = "0.39.0", default-features = false } hex-literal = { version = "0.3.4" } impl-serde = { version = "0.4.0", default-features = false } jsonrpsee = "0.16.2" diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index a7b0a65680..f46d0e4e8e 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -91,8 +91,8 @@ use fp_account::AccountId20; use fp_evm::GenesisAccount; pub use fp_evm::{ Account, CallInfo, CreateInfo, ExecutionInfo, FeeCalculator, InvalidEvmTransactionError, - LinearCostPrecompile, Log, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, - PrecompileResult, PrecompileSet, Vicinity, + IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure, PrecompileHandle, + PrecompileOutput, PrecompileResult, PrecompileSet, Vicinity, }; pub use self::{ diff --git a/frame/evm/src/mock.rs b/frame/evm/src/mock.rs index 083d3fa33d..10df7514b2 100644 --- a/frame/evm/src/mock.rs +++ b/frame/evm/src/mock.rs @@ -17,7 +17,7 @@ //! Test mock for unit tests and benchmarking -use fp_evm::Precompile; +use fp_evm::{IsPrecompileResult, Precompile}; use frame_support::{ parameter_types, traits::{ConstU32, FindAuthor}, @@ -175,7 +175,10 @@ impl PrecompileSet for MockPrecompileSet { /// Check if the given address is a precompile. Should only be called to /// perform the check while not executing the precompile afterward, since /// `execute` already performs a check internally. - fn is_precompile(&self, address: H160) -> bool { - address == H160::from_low_u64_be(1) + fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { + IsPrecompileResult::Answer { + is_precompile: address == H160::from_low_u64_be(1), + extra_cost: 0, + } } } diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index 68d5c0d8c3..2c9f66c45f 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -27,7 +27,9 @@ use evm::{ executor::stack::{Accessed, StackExecutor, StackState as StackStateT, StackSubstateMetadata}, ExitError, ExitReason, Transfer, }; -use fp_evm::{CallInfo, CreateInfo, ExecutionInfo, Log, PrecompileSet, Vicinity}; +use fp_evm::{ + CallInfo, CreateInfo, ExecutionInfo, IsPrecompileResult, Log, PrecompileSet, Vicinity, +}; use frame_support::traits::{Currency, ExistenceRequirement, Get, Time}; use sp_core::{H160, H256, U256}; use sp_runtime::traits::UniqueSaturatedInto; @@ -73,6 +75,7 @@ where T::PrecompilesType, >, ) -> (ExitReason, R), + R: Default, { let (base_fee, weight) = T::FeeCalculator::min_gas_price(); @@ -110,7 +113,7 @@ where fn execute_inner<'config, 'precompiles, F, R>( source: H160, value: U256, - gas_limit: u64, + mut gas_limit: u64, max_fee_per_gas: Option, max_priority_fee_per_gas: Option, config: &'config evm::Config, @@ -129,7 +132,28 @@ where T::PrecompilesType, >, ) -> (ExitReason, R), + R: Default, { + // The precompile check is only used for transactional invocations. However, here we always + // execute the check, because the check has side effects. + let is_precompile = match precompiles.is_precompile(source, gas_limit) { + IsPrecompileResult::Answer { + is_precompile, + extra_cost, + } => { + gas_limit = gas_limit.saturating_sub(extra_cost); + is_precompile + } + IsPrecompileResult::OutOfGas => { + return Ok(ExecutionInfo { + exit_reason: ExitError::OutOfGas.into(), + value: Default::default(), + used_gas: gas_limit.into(), + logs: Default::default(), + }) + } + }; + // Only check the restrictions of EIP-3607 if the source of the EVM operation is from an external transaction. // If the source of this EVM operation is from an internal call, like from `eth_call` or `eth_estimateGas` RPC, // we will skip the checks for the EIP-3607. @@ -141,9 +165,7 @@ where // of a precompile. While mainnet Ethereum currently only has stateless precompiles, // projects using Frontier can have stateful precompiles that can manage funds or // which calls other contracts that expects this precompile address to be trustworthy. - if is_transactional - && (!>::get(source).is_empty() || precompiles.is_precompile(source)) - { + if is_transactional && (!>::get(source).is_empty() || is_precompile) { return Err(RunnerError { error: Error::::TransactionMustComeFromEOA, weight, @@ -616,6 +638,10 @@ impl<'vicinity, 'config, T: Config> BackendT for SubstrateStackState<'vicinity, self.vicinity.origin } + fn block_randomness(&self) -> Option { + None + } + fn block_hash(&self, number: U256) -> H256 { if number > U256::from(u32::MAX) { H256::default() @@ -725,9 +751,10 @@ where self.substate.deleted(address) } - fn inc_nonce(&mut self, address: H160) { + fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError> { let account_id = T::AddressMapping::into_account_id(address); frame_system::Pallet::::inc_account_nonce(&account_id); + Ok(()) } fn set_storage(&mut self, address: H160, index: H256, value: H256) { diff --git a/primitives/evm/src/lib.rs b/primitives/evm/src/lib.rs index b7e8e38741..a0fcce9cd6 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -31,6 +31,7 @@ use sp_std::vec::Vec; pub use evm::{ backend::{Basic as Account, Log}, + executor::stack::IsPrecompileResult, Config, ExitReason, }; diff --git a/template/runtime/src/precompiles.rs b/template/runtime/src/precompiles.rs index 3395dcf144..c563f8e1f2 100644 --- a/template/runtime/src/precompiles.rs +++ b/template/runtime/src/precompiles.rs @@ -1,4 +1,6 @@ -use pallet_evm::{Precompile, PrecompileHandle, PrecompileResult, PrecompileSet}; +use pallet_evm::{ + IsPrecompileResult, Precompile, PrecompileHandle, PrecompileResult, PrecompileSet, +}; use sp_core::H160; use sp_std::marker::PhantomData; @@ -46,8 +48,11 @@ where } } - fn is_precompile(&self, address: H160) -> bool { - Self::used_addresses().contains(&address) + fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { + IsPrecompileResult::Answer { + is_precompile: Self::used_addresses().contains(&address), + extra_cost: 0, + } } }