From e4b553563b9ce5469db783ab92d22fbbb07dffd8 Mon Sep 17 00:00:00 2001 From: stevencartavia <112043913+stevencartavia@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:18:24 -0600 Subject: [PATCH] perf(rpc): deduplicate `pending_block_env_and_cfg` in `local_pending_block` (#22825) --- .../rpc-eth-api/src/helpers/pending_block.rs | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index a000183216..850c195f15 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -13,7 +13,7 @@ use reth_chainspec::{ChainSpecProvider, EthChainSpec}; use reth_errors::{BlockExecutionError, BlockValidationError, ProviderError, RethError}; use reth_evm::{ execute::{BlockBuilder, BlockBuilderOutcome, BlockExecutionOutput}, - ConfigureEvm, Evm, NextBlockEnvAttributes, + ConfigureEvm, Evm, EvmEnvFor, NextBlockEnvAttributes, }; use reth_primitives_traits::{transaction::error::InvalidTransactionError, HeaderTy, SealedHeader}; use reth_revm::{database::StateProviderDatabase, db::State}; @@ -145,6 +145,23 @@ pub trait LoadPendingBlock: PendingBlockEnvOrigin::DerivedFromLatest(parent) => parent, }; + self.build_pool_pending_block(parent, pending.evm_env).await + } + } + + /// Builds or returns a cached pending block from the transaction pool. + /// + /// This is the shared implementation used by both [`Self::pool_pending_block`] and + /// [`Self::local_pending_block`] to avoid resolving the pending block environment twice. + fn build_pool_pending_block( + &self, + parent: SealedHeader>, + evm_env: EvmEnvFor, + ) -> impl Future>, Self::Error>> + Send + where + Self: SpawnBlocking, + { + async move { // we couldn't find the real pending block, so we need to build it ourselves let mut lock = self.pending_block().lock().await; @@ -153,7 +170,7 @@ pub trait LoadPendingBlock: // Is the pending block cached? if let Some(pending_block) = lock.as_ref() { // Is the cached block not expired and latest is its parent? - if pending.evm_env.block_env.number() == U256::from(pending_block.block().number()) && + if evm_env.block_env.number() == U256::from(pending_block.block().number()) && parent.hash() == pending_block.block().parent_hash() && now <= pending_block.expires_at { @@ -206,9 +223,10 @@ pub trait LoadPendingBlock: PendingBlockEnvOrigin::ActualPending(block, receipts) => { Some(BlockAndReceipts { block, receipts }) } - PendingBlockEnvOrigin::DerivedFromLatest(..) => { - self.pool_pending_block().await?.map(PendingBlock::into_block_and_receipts) - } + PendingBlockEnvOrigin::DerivedFromLatest(parent) => self + .build_pool_pending_block(parent, pending.evm_env) + .await? + .map(PendingBlock::into_block_and_receipts), }) } }