From 8a5dbb9005512a1d8597efad3d532c6cad68f4b7 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 18 Jan 2024 18:28:36 +0800 Subject: [PATCH] record external cost ref: https://github.com/rust-ethereum/evm/pull/170 --- Cargo.lock | 16 +++---- modules/evm-utility/Cargo.toml | 6 +-- modules/evm/src/lib.rs | 2 +- modules/evm/src/precompiles/mod.rs | 8 ++++ modules/evm/src/runner/state.rs | 71 ++++++++++++++++++++++++++++-- 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8b672f52..b97fdc9e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3605,8 +3605,8 @@ dependencies = [ [[package]] name = "evm" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.1" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "auto_impl", "environmental", @@ -3625,8 +3625,8 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.0" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3636,8 +3636,8 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.0" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "environmental", "evm-core", @@ -3683,8 +3683,8 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.0" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 86644538c..7e3fb8208 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 99c21838a..c801fc43c 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -49,7 +49,7 @@ pub use module_evm_utility::{ evm::{ self, executor::stack::{IsPrecompileResult, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet}, - Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, + Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, ExternalOperation, }, Account, }; diff --git a/modules/evm/src/precompiles/mod.rs b/modules/evm/src/precompiles/mod.rs index 7d90a0a6c..32de1f73e 100644 --- a/modules/evm/src/precompiles/mod.rs +++ b/modules/evm/src/precompiles/mod.rs @@ -147,6 +147,14 @@ pub mod tests { } } + fn record_external_cost(&mut self, _ref_time: Option, _proof_size: Option) -> Result<(), ExitError> { + unimplemented!() + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) { + unimplemented!() + } + fn remaining_gas(&self) -> u64 { unimplemented!() } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 4d291ba9a..690ef9f2a 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -349,6 +349,21 @@ pub trait StackState<'config>: Backend { fn code_hash(&self, address: H160) -> H256 { H256::from_slice(Keccak256::digest(self.code(address)).as_slice()) } + + fn record_external_dynamic_opcode_cost( + &mut self, + _opcode: Opcode, + _gas_cost: gasometer::GasCost, + _target: StorageTarget, + ) -> Result<(), ExitError> { + Ok(()) + } + + fn record_external_cost(&mut self, _ref_time: Option, _proof_size: Option) -> Result<(), ExitError> { + Ok(()) + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} } /// A precompile result. @@ -725,6 +740,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu self.initialize_with_access_list(access_list); } + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + return (e.into(), Vec::new()); + } + let context = Context { caller, address, @@ -876,6 +895,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu return Capture::Exit((ExitError::OutOfFund.into(), None, Vec::new())); } + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + return Capture::Exit((ExitReason::Error(e), None, Vec::new())); + } + if let Err(e) = self.state.inc_nonce(caller) { return Capture::Exit((e.into(), None, Vec::new())); } @@ -901,7 +924,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu self.enter_substate(gas_limit, false); { - if self.code_size(address) != U256::zero() { + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AddressCodeRead(address)) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), None, Vec::new())); + } + let code_size = self.code_size(address); + if code_size != U256::zero() { let _ = self.exit_substate(StackExitKind::Failed); return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new())); } @@ -935,6 +963,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } if self.config.create_increase_nonce { + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), None, Vec::new())); + } if let Err(e) = self.state.inc_nonce(address) { return Capture::Exit((e.into(), None, Vec::new())); } @@ -1015,11 +1047,15 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } } - let code = self.code(code_address); - self.enter_substate(gas_limit, is_static); self.state.touch(context.address); + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AddressCodeRead(code_address)) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), Vec::new())); + } + let code = self.code(code_address); + if let Some(depth) = self.state.metadata().depth { if depth > self.config.call_stack_limit { let _ = self.exit_substate(StackExitKind::Reverted); @@ -1028,6 +1064,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } if let Some(transfer) = transfer { + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), Vec::new())); + } match self.state.transfer(transfer) { Ok(()) => (), Err(e) => { @@ -1125,6 +1165,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu Ok(()) => { self.state.set_code(address, out); let exit_result = self.exit_substate(StackExitKind::Succeeded); + if let Err(e) = self.record_external_operation(crate::ExternalOperation::Write) { + return (e.into(), None, Vec::new()); + } if let Err(e) = exit_result { return (e.into(), None, Vec::new()); } @@ -1438,6 +1481,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler let gasometer = &mut self.state.metadata_mut().gasometer; gasometer.record_dynamic_cost(gas_cost, memory_cost)?; + + self.state + .record_external_dynamic_opcode_cost(opcode, gas_cost, target)?; + match target { StorageTarget::Address(address) => self.state.metadata_mut().access_address(address), StorageTarget::Slot(address, key) => self.state.metadata_mut().access_storage(address, key), @@ -1447,6 +1494,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler Ok(()) } + + fn record_external_operation(&mut self, op: crate::ExternalOperation) -> Result<(), ExitError> { + self.state.record_external_operation(op) + } } struct StackExecutorHandle<'inner, 'config, 'precompiles, S, P> { @@ -1481,11 +1532,13 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr Err(err) => return (ExitReason::Error(err), Vec::new()), }; + let target_exists = self.executor.exists(code_address); + let gas_cost = gasometer::GasCost::Call { value: transfer.clone().map(|x| x.value).unwrap_or_else(U256::zero), gas: U256::from(gas_limit.unwrap_or(u64::MAX)), target_is_cold, - target_exists: self.executor.exists(code_address), + target_exists, }; // We record the length of the input. @@ -1543,6 +1596,16 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr self.executor.state.metadata_mut().gasometer.record_cost(cost) } + /// Record Substrate specific cost. + fn record_external_cost(&mut self, ref_time: Option, proof_size: Option) -> Result<(), ExitError> { + self.executor.state.record_external_cost(ref_time, proof_size) + } + + /// Refund Substrate specific cost. + fn refund_external_cost(&mut self, ref_time: Option, proof_size: Option) { + self.executor.state.refund_external_cost(ref_time, proof_size); + } + /// Retreive the remaining gas. fn remaining_gas(&self) -> u64 { self.executor.state.metadata().gasometer.gas()