From e04292247fff14ea93b4b0f6cf427bc9e4365c75 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 11 Oct 2023 05:06:53 +0200 Subject: [PATCH] fix: use pending block tag for actual pending block (#4966) --- crates/rpc/rpc/src/eth/api/mod.rs | 5 +++-- crates/rpc/rpc/src/eth/api/pending_block.rs | 17 ++++++++++++++--- crates/rpc/rpc/src/eth/api/transactions.rs | 6 ++++-- crates/storage/provider/src/providers/mod.rs | 12 +++++++++--- crates/storage/provider/src/traits/state.rs | 3 ++- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 5a653c72457d..635f3016b83f 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -263,8 +263,9 @@ where let mut cfg = CfgEnv::default(); let mut block_env = BlockEnv::default(); - self.provider().fill_block_env_with_header(&mut block_env, origin.header())?; - self.provider().fill_cfg_env_with_header(&mut cfg, origin.header())?; + // Note: for the PENDING block we assume it is past the known merge block and thus this will + // not fail when looking up the total difficulty value for the blockenv. + self.provider().fill_env_with_header(&mut cfg, &mut block_env, origin.header())?; Ok(PendingBlockEnv { cfg, block_env, origin }) } diff --git a/crates/rpc/rpc/src/eth/api/pending_block.rs b/crates/rpc/rpc/src/eth/api/pending_block.rs index 27cd2e2d34af..3476155a721b 100644 --- a/crates/rpc/rpc/src/eth/api/pending_block.rs +++ b/crates/rpc/rpc/src/eth/api/pending_block.rs @@ -4,8 +4,8 @@ use crate::eth::error::{EthApiError, EthResult}; use core::fmt::Debug; use reth_primitives::{ constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, - proofs, Block, ChainSpec, Header, IntoRecoveredTransaction, Receipt, Receipts, SealedBlock, - SealedHeader, B256, EMPTY_OMMER_ROOT, U256, + proofs, Block, BlockId, BlockNumberOrTag, ChainSpec, Header, IntoRecoveredTransaction, Receipt, + Receipts, SealedBlock, SealedHeader, B256, EMPTY_OMMER_ROOT, U256, }; use reth_provider::{BundleStateWithReceipts, ChainSpecProvider, StateProviderFactory}; use reth_revm::{ @@ -305,7 +305,18 @@ impl PendingBlockEnvOrigin { } } - /// Returns the hash of the pending block should be built on + /// Returns the [BlockId] that represents the state of the block. + /// + /// If this is the actual pending block, the state is the "Pending" tag, otherwise we can safely + /// identify the block by its hash. + pub(crate) fn state_block_id(&self) -> BlockId { + match self { + PendingBlockEnvOrigin::ActualPending(_) => BlockNumberOrTag::Pending.into(), + PendingBlockEnvOrigin::DerivedFromLatest(header) => BlockId::Hash(header.hash.into()), + } + } + + /// Returns the hash of the block the pending block should be built on. fn build_target_hash(&self) -> B256 { match self { PendingBlockEnvOrigin::ActualPending(block) => block.parent_hash, diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index d0d200a28774..94cc63527d9a 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -69,8 +69,10 @@ pub trait EthTransactions: Send + Sync { /// Returns the revm evm env for the requested [BlockId] /// - /// If the [BlockId] this will return the [BlockId::Hash] of the block the env was configured + /// If the [BlockId] this will return the [BlockId] of the block the env was configured /// for. + /// If the [BlockId] is pending, this will return the "Pending" tag, otherwise this returns the + /// hash of the exact block. async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnv, BlockEnv, BlockId)>; /// Returns the revm evm env for the raw block header @@ -279,7 +281,7 @@ where async fn evm_env_at(&self, at: BlockId) -> EthResult<(CfgEnv, BlockEnv, BlockId)> { if at.is_pending() { let PendingBlockEnv { cfg, block_env, origin } = self.pending_block_env_and_cfg()?; - Ok((cfg, block_env, origin.header().hash.into())) + Ok((cfg, block_env, origin.state_block_id())) } else { // Use cached values if there is no pending block let block_hash = self diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 14beaae6a800..a865f5a636d2 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -521,14 +521,20 @@ where state } - /// Storage provider for pending state. + /// Returns the state provider for pending state. + /// + /// If there's no pending block available then the latest state provider is returned: + /// [Self::latest] fn pending(&self) -> RethResult> { trace!(target: "providers::blockchain", "Getting provider for pending state"); if let Some(block) = self.tree.pending_block_num_hash() { - let pending = self.tree.pending_state_provider(block.hash)?; - return self.pending_with_provider(pending) + if let Ok(pending) = self.tree.pending_state_provider(block.hash) { + return self.pending_with_provider(pending) + } } + + // fallback to latest state if the pending block is not available self.latest() } diff --git a/crates/storage/provider/src/traits/state.rs b/crates/storage/provider/src/traits/state.rs index e7e572b3442b..9d1b5a0f6643 100644 --- a/crates/storage/provider/src/traits/state.rs +++ b/crates/storage/provider/src/traits/state.rs @@ -107,7 +107,8 @@ pub trait StateProviderFactory: BlockIdReader + Send + Sync { /// Returns a [StateProvider] indexed by the given [BlockId]. /// - /// Note: if a number or hash is provided this will only look at historical(canonical) state. + /// Note: if a number or hash is provided this will __only__ look at historical(canonical) + /// state. fn state_by_block_id(&self, block_id: BlockId) -> RethResult> { match block_id { BlockId::Number(block_number) => self.state_by_block_number_or_tag(block_number),