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

@ -48,7 +48,7 @@ use reth_revm::database::StateProviderDatabase;
use reth_stages_api::ControlFlow; use reth_stages_api::ControlFlow;
use reth_trie::{updates::TrieUpdates, HashedPostState, TrieInput}; use reth_trie::{updates::TrieUpdates, HashedPostState, TrieInput};
use reth_trie_parallel::root::{ParallelStateRoot, ParallelStateRootError}; use reth_trie_parallel::root::{ParallelStateRoot, ParallelStateRootError};
use revm_primitives::ResultAndState; use revm_primitives::EvmState;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{btree_map, hash_map, BTreeMap, VecDeque}, collections::{btree_map, hash_map, BTreeMap, VecDeque},
@ -2212,7 +2212,7 @@ where
// TODO: create StateRootTask with the receiving end of a channel and // TODO: create StateRootTask with the receiving end of a channel and
// pass the sending end of the channel to the state hook. // pass the sending end of the channel to the state hook.
let noop_state_hook = |_result_and_state: &ResultAndState| {}; let noop_state_hook = |_state: &EvmState| {};
let output = self.metrics.executor.execute_metered( let output = self.metrics.executor.execute_metered(
executor, executor,
(&block, U256::MAX).into(), (&block, U256::MAX).into(),

View File

@ -193,7 +193,7 @@ where
error: Box::new(new_err), error: Box::new(new_err),
} }
})?; })?;
self.system_caller.on_state(&result_and_state); self.system_caller.on_state(&result_and_state.state);
let ResultAndState { result, state } = result_and_state; let ResultAndState { result, state } = result_and_state;
evm.db_mut().commit(state); evm.db_mut().commit(state);

View File

@ -8,7 +8,7 @@ use metrics::{Counter, Gauge, Histogram};
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput}; use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput};
use reth_metrics::Metrics; use reth_metrics::Metrics;
use reth_primitives::BlockWithSenders; use reth_primitives::BlockWithSenders;
use revm_primitives::ResultAndState; use revm_primitives::EvmState;
use std::time::Instant; use std::time::Instant;
/// Wrapper struct that combines metrics and state hook /// Wrapper struct that combines metrics and state hook
@ -18,13 +18,11 @@ struct MeteredStateHook {
} }
impl OnStateHook for 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 // Update the metrics for the number of accounts, storage slots and bytecodes loaded
let accounts = result_and_state.state.keys().len(); let accounts = state.keys().len();
let storage_slots = let storage_slots = state.values().map(|account| account.storage.len()).sum::<usize>();
result_and_state.state.values().map(|account| account.storage.len()).sum::<usize>(); let bytecodes = state
let bytecodes = result_and_state
.state
.values() .values()
.filter(|account| !account.info.is_empty_code_hash()) .filter(|account| !account.info.is_empty_code_hash())
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -35,7 +33,7 @@ impl OnStateHook for MeteredStateHook {
self.metrics.bytecodes_loaded_histogram.record(bytecodes as f64); self.metrics.bytecodes_loaded_histogram.record(bytecodes as f64);
// Call the original state hook // 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 metrics_util::debugging::{DebugValue, DebuggingRecorder, Snapshotter};
use revm::db::BundleState; use revm::db::BundleState;
use revm_primitives::{ use revm_primitives::{
Account, AccountInfo, AccountStatus, Bytes, EvmState, EvmStorage, EvmStorageSlot, Account, AccountInfo, AccountStatus, EvmState, EvmStorage, EvmStorageSlot, B256, U256,
ExecutionResult, Output, SuccessReason, B256, U256,
}; };
use std::sync::mpsc; use std::sync::mpsc;
/// A mock executor that simulates state changes /// A mock executor that simulates state changes
struct MockExecutor { struct MockExecutor {
result_and_state: ResultAndState, state: EvmState,
} }
impl Executor<()> for MockExecutor { impl Executor<()> for MockExecutor {
@ -206,7 +203,7 @@ mod tests {
F: OnStateHook + 'static, F: OnStateHook + 'static,
{ {
// Call hook with our mock state // Call hook with our mock state
hook.on_state(&self.result_and_state); hook.on_state(&self.state);
Ok(BlockExecutionOutput { Ok(BlockExecutionOutput {
state: BundleState::default(), state: BundleState::default(),
@ -223,7 +220,7 @@ mod tests {
} }
impl OnStateHook for ChannelStateHook { 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); let _ = self.sender.send(self.output);
} }
} }
@ -249,35 +246,26 @@ mod tests {
let expected_output = 42; let expected_output = 42;
let state_hook = Box::new(ChannelStateHook { sender: tx, output: expected_output }); let state_hook = Box::new(ChannelStateHook { sender: tx, output: expected_output });
let result_and_state = ResultAndState { let state = {
result: ExecutionResult::Success { let mut state = EvmState::default();
reason: SuccessReason::Stop, let storage =
gas_used: 100, EvmStorage::from_iter([(U256::from(1), EvmStorageSlot::new(U256::from(2)))]);
output: Output::Call(Bytes::default()), state.insert(
logs: vec![], Default::default(),
gas_refunded: 0, Account {
}, info: AccountInfo {
state: { balance: U256::from(100),
let mut state = EvmState::default(); nonce: 10,
let storage = code_hash: B256::random(),
EvmStorage::from_iter([(U256::from(1), EvmStorageSlot::new(U256::from(2)))]); code: Default::default(),
state.insert(
Default::default(),
Account {
info: AccountInfo {
balance: U256::from(100),
nonce: 10,
code_hash: B256::random(),
code: Default::default(),
},
storage,
status: AccountStatus::Loaded,
}, },
); storage,
state 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 _result = metrics.execute_metered(executor, input, state_hook).unwrap();
let snapshot = snapshotter.snapshot().into_vec(); let snapshot = snapshotter.snapshot().into_vec();
@ -311,11 +299,9 @@ mod tests {
let expected_output = 42; let expected_output = 42;
let state_hook = Box::new(ChannelStateHook { sender: tx, output: expected_output }); let state_hook = Box::new(ChannelStateHook { sender: tx, output: expected_output });
let result_and_state = ResultAndState { let state = EvmState::default();
result: ExecutionResult::Revert { gas_used: 0, output: Default::default() },
state: EvmState::default(), let executor = MockExecutor { state };
};
let executor = MockExecutor { result_and_state };
let _result = metrics.execute_metered(executor, input, state_hook).unwrap(); let _result = metrics.execute_metered(executor, input, state_hook).unwrap();
let actual_output = rx.try_recv().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_execution_errors::BlockExecutionError;
use reth_primitives::Block; use reth_primitives::Block;
use revm::{Database, DatabaseCommit, Evm}; use revm::{Database, DatabaseCommit, Evm};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, B256}; use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, B256};
mod eip2935; mod eip2935;
mod eip4788; mod eip4788;
@ -19,15 +19,15 @@ mod eip7251;
/// A hook that is called after each state change. /// A hook that is called after each state change.
pub trait OnStateHook { pub trait OnStateHook {
/// Invoked with the result and state after each system call. /// Invoked with the state after each system call.
fn on_state(&mut self, state: &ResultAndState); fn on_state(&mut self, state: &EvmState);
} }
impl<F> OnStateHook for F impl<F> OnStateHook for F
where where
F: FnMut(&ResultAndState), F: FnMut(&EvmState),
{ {
fn on_state(&mut self, state: &ResultAndState) { fn on_state(&mut self, state: &EvmState) {
self(state) self(state)
} }
} }
@ -38,7 +38,7 @@ where
pub struct NoopHook; pub struct NoopHook;
impl OnStateHook for 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. /// An ephemeral helper type for executing system calls.
@ -182,7 +182,7 @@ where
if let Some(res) = result_and_state { if let Some(res) = result_and_state {
if let Some(ref mut hook) = self.hook { if let Some(ref mut hook) = self.hook {
hook.on_state(&res); hook.on_state(&res.state);
} }
evm.context.evm.db.commit(res.state); evm.context.evm.db.commit(res.state);
} }
@ -237,7 +237,7 @@ where
if let Some(res) = result_and_state { if let Some(res) = result_and_state {
if let Some(ref mut hook) = self.hook { if let Some(ref mut hook) = self.hook {
hook.on_state(&res); hook.on_state(&res.state);
} }
evm.context.evm.db.commit(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)?; eip7002::transact_withdrawal_requests_contract_call(&self.evm_config.clone(), evm)?;
if let Some(ref mut hook) = self.hook { 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); 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)?; eip7251::transact_consolidation_requests_contract_call(&self.evm_config.clone(), evm)?;
if let Some(ref mut hook) = self.hook { 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); evm.context.evm.db.commit(result_and_state.state);
@ -322,7 +322,7 @@ where
} }
/// Delegate to stored `OnStateHook`, noop if hook is `None`. /// 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 { if let Some(ref mut hook) = &mut self.hook {
hook.on_state(state); hook.on_state(state);
} }

View File

@ -221,7 +221,7 @@ where
?transaction, ?transaction,
"Executed transaction" "Executed transaction"
); );
self.system_caller.on_state(&result_and_state); self.system_caller.on_state(&result_and_state.state);
let ResultAndState { result, state } = result_and_state; let ResultAndState { result, state } = result_and_state;
evm.db_mut().commit(state); evm.db_mut().commit(state);