refactor: use BlockExecutorProvider in InvalidBlockWitnessHook (#14594)

This commit is contained in:
Arsenii Kulikov
2025-02-19 21:41:32 +04:00
committed by GitHub
parent 465af6e0f3
commit 1bf46848a6
2 changed files with 20 additions and 53 deletions

View File

@ -4,15 +4,10 @@ use alloy_rpc_types_debug::ExecutionWitness;
use pretty_assertions::Comparison;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_engine_primitives::InvalidBlockHook;
use reth_evm::{
state_change::post_block_balance_increments, system_calls::SystemCaller, ConfigureEvmFor, Evm,
};
use reth_evm::execute::{BlockExecutorProvider, Executor};
use reth_primitives::{NodePrimitives, RecoveredBlock, SealedHeader};
use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory};
use reth_revm::{
database::StateProviderDatabase,
db::{states::bundle_state::BundleRetention, StateBuilder},
};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_api::DebugApiClient;
use reth_tracing::tracing::warn;
use reth_trie::{updates::TrieUpdates, HashedStorage};
@ -21,11 +16,11 @@ use std::{collections::HashMap, fmt::Debug, fs::File, io::Write, path::PathBuf};
/// Generates a witness for the given block and saves it to a file.
#[derive(Debug)]
pub struct InvalidBlockWitnessHook<P, EvmConfig> {
pub struct InvalidBlockWitnessHook<P, E> {
/// The provider to read the historical state and do the EVM execution.
provider: P,
/// The EVM configuration to use for the execution.
evm_config: EvmConfig,
executor: E,
/// The directory to write the witness to. Additionally, diff files will be written to this
/// directory in case of failed sanity checks.
output_directory: PathBuf,
@ -33,27 +28,29 @@ pub struct InvalidBlockWitnessHook<P, EvmConfig> {
healthy_node_client: Option<jsonrpsee::http_client::HttpClient>,
}
impl<P, EvmConfig> InvalidBlockWitnessHook<P, EvmConfig> {
impl<P, E> InvalidBlockWitnessHook<P, E> {
/// Creates a new witness hook.
pub const fn new(
provider: P,
evm_config: EvmConfig,
executor: E,
output_directory: PathBuf,
healthy_node_client: Option<jsonrpsee::http_client::HttpClient>,
) -> Self {
Self { provider, evm_config, output_directory, healthy_node_client }
Self { provider, executor, output_directory, healthy_node_client }
}
}
impl<P, EvmConfig> InvalidBlockWitnessHook<P, EvmConfig>
impl<P, E, N> InvalidBlockWitnessHook<P, E>
where
P: StateProviderFactory
+ ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ Send
+ Sync
+ 'static,
E: BlockExecutorProvider<Primitives = N>,
N: NodePrimitives,
{
fn on_invalid_block<N>(
fn on_invalid_block(
&self,
parent_header: &SealedHeader<N::BlockHeader>,
block: &RecoveredBlock<N::Block>,
@ -62,46 +59,17 @@ where
) -> eyre::Result<()>
where
N: NodePrimitives,
EvmConfig: ConfigureEvmFor<N>,
{
// TODO(alexey): unify with `DebugApi::debug_execution_witness`
// Setup database.
let mut db = StateBuilder::new()
.with_database(StateProviderDatabase::new(
self.provider.state_by_block_hash(parent_header.hash())?,
))
.with_bundle_update()
.build();
let mut executor = self.executor.executor(StateProviderDatabase::new(
self.provider.state_by_block_hash(parent_header.hash())?,
));
// Setup EVM
let mut evm = self.evm_config.evm_for_block(&mut db, block.header());
let mut system_caller = SystemCaller::new(self.provider.chain_spec());
// Apply pre-block system contract calls.
system_caller.apply_pre_execution_changes(block.header(), &mut evm)?;
// Re-execute all of the transactions in the block to load all touched accounts into
// the cache DB.
for tx in block.transactions_recovered() {
evm.transact_commit(self.evm_config.tx_env(tx))?;
}
drop(evm);
// use U256::MAX here for difficulty, because fetching it is annoying
// NOTE: This is not mut because we are not doing the DAO irregular state change here
let balance_increments =
post_block_balance_increments(self.provider.chain_spec().as_ref(), block);
// increment balances
db.increment_balances(balance_increments)?;
// Merge all state transitions
db.merge_transitions(BundleRetention::Reverts);
executor.execute_one(block)?;
// Take the bundle state
let mut db = executor.into_state();
let mut bundle_state = db.take_bundle();
// Initialize a map of preimages.
@ -278,15 +246,14 @@ where
}
}
impl<P, EvmConfig, N> InvalidBlockHook<N> for InvalidBlockWitnessHook<P, EvmConfig>
impl<P, E, N: NodePrimitives> InvalidBlockHook<N> for InvalidBlockWitnessHook<P, E>
where
N: NodePrimitives,
P: StateProviderFactory
+ ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ Send
+ Sync
+ 'static,
EvmConfig: ConfigureEvmFor<N>,
E: BlockExecutorProvider<Primitives = N>,
{
fn on_invalid_block(
&self,
@ -295,7 +262,7 @@ where
output: &BlockExecutionOutput<N::Receipt>,
trie_updates: Option<(&TrieUpdates, B256)>,
) {
if let Err(err) = self.on_invalid_block::<N>(parent_header, block, output, trie_updates) {
if let Err(err) = self.on_invalid_block(parent_header, block, output, trie_updates) {
warn!(target: "engine::invalid_block_hooks::witness", %err, "Failed to invoke hook");
}
}