diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 7e170d3419ea..0b330171a8ae 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -28,7 +28,7 @@ use reth_primitives::{ }; use reth_provider::{ BlockReader, ExecutionOutcome, ProviderError, StateProviderBox, StateProviderFactory, - StateRootProvider, + StateReader, StateRootProvider, TransactionVariant, }; use reth_revm::database::StateProviderDatabase; use reth_rpc_types::{ @@ -109,6 +109,11 @@ impl TreeState { self.blocks_by_hash.len() } + /// Returns the [`ExecutedBlock`] by hash. + fn executed_block_by_hash(&self, hash: B256) -> Option<&ExecutedBlock> { + self.blocks_by_hash.get(&hash) + } + /// Returns the block by hash. fn block_by_hash(&self, hash: B256) -> Option> { self.blocks_by_hash.get(&hash).map(|b| b.block.clone()) @@ -547,7 +552,7 @@ impl std::fmt::Debug for EngineApiTr impl EngineApiTreeHandler where - P: BlockReader + StateProviderFactory + Clone + 'static, + P: BlockReader + StateProviderFactory + StateReader + Clone + 'static, E: BlockExecutorProvider, T: EngineTypes, { @@ -1337,6 +1342,45 @@ where .remove_persisted_blocks(self.persistence_state.last_persisted_block_number); } + /// Return an [`ExecutedBlock`] from database or in-memory state by hash. + /// + /// NOTE: This cannot fetch [`ExecutedBlock`]s for _finalized_ blocks, instead it can only + /// fetch [`ExecutedBlock`]s for _canonical_ blocks, or blocks from sidechains that the node + /// has in memory. + /// + /// For finalized blocks, this will return `None`. + #[allow(unused)] + fn executed_block_by_hash(&self, hash: B256) -> ProviderResult> { + // check memory first + let block = self.state.tree_state.executed_block_by_hash(hash).cloned(); + + if block.is_some() { + return Ok(block) + } + + let Some((_, updates)) = self.state.tree_state.persisted_trie_updates.get(&hash) else { + return Ok(None) + }; + + let SealedBlockWithSenders { block, senders } = self + .provider + .sealed_block_with_senders(hash.into(), TransactionVariant::WithHash)? + .ok_or_else(|| ProviderError::HeaderNotFound(hash.into()))?; + let execution_output = self + .provider + .get_state(block.number)? + .ok_or_else(|| ProviderError::StateForNumberNotFound(block.number))?; + let hashed_state = execution_output.hash_state_slow(); + + Ok(Some(ExecutedBlock { + block: Arc::new(block), + senders: Arc::new(senders), + trie: updates.clone(), + execution_output: Arc::new(execution_output), + hashed_state: Arc::new(hashed_state), + })) + } + /// Return sealed block from database or in-memory state by hash. fn sealed_header_by_hash(&self, hash: B256) -> ProviderResult> { // check memory first @@ -1705,7 +1749,7 @@ where /// /// This is invoked on a valid forkchoice update, or if we can make the target block canonical. fn on_canonical_chain_update(&mut self, chain_update: NewCanonicalChain) { - trace!(target: "engine", new_blocks = %chain_update.new_block_count(), reorged_blocks = %chain_update.reorged_block_count() ,"applying new chain update"); + trace!(target: "engine", new_blocks = %chain_update.new_block_count(), reorged_blocks = %chain_update.reorged_block_count(), "applying new chain update"); let start = Instant::now(); // update the tracked canonical head diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index e6ab835d62bb..9dd43e8fa3a7 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -1,14 +1,16 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, - AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, - ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, ReceiptProviderIdExt, - RequestsProvider, StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, - TransactionVariant, TransactionsProvider, WithdrawalsProvider, + AccountReader, BlockExecutionReader, BlockHashReader, BlockIdReader, BlockNumReader, + BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, + HeaderProvider, ReceiptProviderIdExt, RequestsProvider, StateProvider, StateProviderBox, + StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, TransactionsProvider, + WithdrawalsProvider, }; use parking_lot::Mutex; use reth_chainspec::{ChainInfo, ChainSpec}; use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; +use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ keccak256, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, BlockNumberOrTag, BlockWithSenders, Bytecode, Bytes, Header, Receipt, SealedBlock, @@ -787,3 +789,18 @@ impl ChangeSetReader for MockEthProvider { Ok(Vec::default()) } } + +impl BlockExecutionReader for MockEthProvider { + fn get_block_and_execution_range( + &self, + _range: RangeInclusive, + ) -> ProviderResult { + Ok(Chain::default()) + } +} + +impl StateReader for MockEthProvider { + fn get_state(&self, _block: BlockNumber) -> ProviderResult> { + Ok(None) + } +}