feat(eecutor): send EvmState in state hook (#13025)

This commit is contained in:
Federico Gimenez
2024-11-30 13:37:05 +01:00
committed by GitHub
parent 0ff2827a79
commit 489d4e8595
5 changed files with 46 additions and 60 deletions

View File

@ -8,7 +8,7 @@ use metrics::{Counter, Gauge, Histogram};
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput};
use reth_metrics::Metrics;
use reth_primitives::BlockWithSenders;
use revm_primitives::ResultAndState;
use revm_primitives::EvmState;
use std::time::Instant;
/// Wrapper struct that combines metrics and state hook
@ -18,13 +18,11 @@ struct MeteredStateHook {
}
impl OnStateHook for MeteredStateHook {
fn on_state(&mut self, result_and_state: &ResultAndState) {
fn on_state(&mut self, state: &EvmState) {
// Update the metrics for the number of accounts, storage slots and bytecodes loaded
let accounts = result_and_state.state.keys().len();
let storage_slots =
result_and_state.state.values().map(|account| account.storage.len()).sum::<usize>();
let bytecodes = result_and_state
.state
let accounts = state.keys().len();
let storage_slots = state.values().map(|account| account.storage.len()).sum::<usize>();
let bytecodes = state
.values()
.filter(|account| !account.info.is_empty_code_hash())
.collect::<Vec<_>>()
@ -35,7 +33,7 @@ impl OnStateHook for MeteredStateHook {
self.metrics.bytecodes_loaded_histogram.record(bytecodes as f64);
// Call the original state hook
self.inner_hook.on_state(result_and_state);
self.inner_hook.on_state(state);
}
}
@ -156,14 +154,13 @@ mod tests {
use metrics_util::debugging::{DebugValue, DebuggingRecorder, Snapshotter};
use revm::db::BundleState;
use revm_primitives::{
Account, AccountInfo, AccountStatus, Bytes, EvmState, EvmStorage, EvmStorageSlot,
ExecutionResult, Output, SuccessReason, B256, U256,
Account, AccountInfo, AccountStatus, EvmState, EvmStorage, EvmStorageSlot, B256, U256,
};
use std::sync::mpsc;
/// A mock executor that simulates state changes
struct MockExecutor {
result_and_state: ResultAndState,
state: EvmState,
}
impl Executor<()> for MockExecutor {
@ -206,7 +203,7 @@ mod tests {
F: OnStateHook + 'static,
{
// Call hook with our mock state
hook.on_state(&self.result_and_state);
hook.on_state(&self.state);
Ok(BlockExecutionOutput {
state: BundleState::default(),
@ -223,7 +220,7 @@ mod tests {
}
impl OnStateHook for ChannelStateHook {
fn on_state(&mut self, _result_and_state: &ResultAndState) {
fn on_state(&mut self, _state: &EvmState) {
let _ = self.sender.send(self.output);
}
}
@ -249,35 +246,26 @@ mod tests {
let expected_output = 42;
let state_hook = Box::new(ChannelStateHook { sender: tx, output: expected_output });
let result_and_state = ResultAndState {
result: ExecutionResult::Success {
reason: SuccessReason::Stop,
gas_used: 100,
output: Output::Call(Bytes::default()),
logs: vec![],
gas_refunded: 0,
},
state: {
let mut state = EvmState::default();
let storage =
EvmStorage::from_iter([(U256::from(1), EvmStorageSlot::new(U256::from(2)))]);
state.insert(
Default::default(),
Account {
info: AccountInfo {
balance: U256::from(100),
nonce: 10,
code_hash: B256::random(),
code: Default::default(),
},
storage,
status: AccountStatus::Loaded,
let state = {
let mut state = EvmState::default();
let storage =
EvmStorage::from_iter([(U256::from(1), EvmStorageSlot::new(U256::from(2)))]);
state.insert(
Default::default(),
Account {
info: AccountInfo {
balance: U256::from(100),
nonce: 10,
code_hash: B256::random(),
code: Default::default(),
},
);
state
},
storage,
status: AccountStatus::Loaded,
},
);
state
};
let executor = MockExecutor { result_and_state };
let executor = MockExecutor { state };
let _result = metrics.execute_metered(executor, input, state_hook).unwrap();
let snapshot = snapshotter.snapshot().into_vec();
@ -311,11 +299,9 @@ mod tests {
let expected_output = 42;
let state_hook = Box::new(ChannelStateHook { sender: tx, output: expected_output });
let result_and_state = ResultAndState {
result: ExecutionResult::Revert { gas_used: 0, output: Default::default() },
state: EvmState::default(),
};
let executor = MockExecutor { result_and_state };
let state = EvmState::default();
let executor = MockExecutor { state };
let _result = metrics.execute_metered(executor, input, state_hook).unwrap();
let actual_output = rx.try_recv().unwrap();

View File

@ -10,7 +10,7 @@ use reth_chainspec::EthereumHardforks;
use reth_execution_errors::BlockExecutionError;
use reth_primitives::Block;
use revm::{Database, DatabaseCommit, Evm};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, B256};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, B256};
mod eip2935;
mod eip4788;
@ -19,15 +19,15 @@ mod eip7251;
/// A hook that is called after each state change.
pub trait OnStateHook {
/// Invoked with the result and state after each system call.
fn on_state(&mut self, state: &ResultAndState);
/// Invoked with the state after each system call.
fn on_state(&mut self, state: &EvmState);
}
impl<F> OnStateHook for F
where
F: FnMut(&ResultAndState),
F: FnMut(&EvmState),
{
fn on_state(&mut self, state: &ResultAndState) {
fn on_state(&mut self, state: &EvmState) {
self(state)
}
}
@ -38,7 +38,7 @@ where
pub struct NoopHook;
impl OnStateHook for NoopHook {
fn on_state(&mut self, _state: &ResultAndState) {}
fn on_state(&mut self, _state: &EvmState) {}
}
/// An ephemeral helper type for executing system calls.
@ -182,7 +182,7 @@ where
if let Some(res) = result_and_state {
if let Some(ref mut hook) = self.hook {
hook.on_state(&res);
hook.on_state(&res.state);
}
evm.context.evm.db.commit(res.state);
}
@ -237,7 +237,7 @@ where
if let Some(res) = result_and_state {
if let Some(ref mut hook) = self.hook {
hook.on_state(&res);
hook.on_state(&res.state);
}
evm.context.evm.db.commit(res.state);
}
@ -276,7 +276,7 @@ where
eip7002::transact_withdrawal_requests_contract_call(&self.evm_config.clone(), evm)?;
if let Some(ref mut hook) = self.hook {
hook.on_state(&result_and_state);
hook.on_state(&result_and_state.state);
}
evm.context.evm.db.commit(result_and_state.state);
@ -314,7 +314,7 @@ where
eip7251::transact_consolidation_requests_contract_call(&self.evm_config.clone(), evm)?;
if let Some(ref mut hook) = self.hook {
hook.on_state(&result_and_state);
hook.on_state(&result_and_state.state);
}
evm.context.evm.db.commit(result_and_state.state);
@ -322,7 +322,7 @@ where
}
/// Delegate to stored `OnStateHook`, noop if hook is `None`.
pub fn on_state(&mut self, state: &ResultAndState) {
pub fn on_state(&mut self, state: &EvmState) {
if let Some(ref mut hook) = &mut self.hook {
hook.on_state(state);
}