reth_optimism_rpc/eth/
pending_block.rs

1//! Loads OP pending block for a RPC response.
2
3use crate::{OpEthApi, OpEthApiError};
4use alloy_consensus::BlockHeader;
5use alloy_eips::BlockNumberOrTag;
6use reth_chain_state::BlockState;
7use reth_rpc_eth_api::{
8    helpers::{pending_block::PendingEnvBuilder, LoadPendingBlock, SpawnBlocking},
9    FromEvmError, RpcConvert, RpcNodeCore, RpcNodeCoreExt,
10};
11use reth_rpc_eth_types::{
12    block::BlockAndReceipts, builder::config::PendingBlockKind, error::FromEthApiError,
13    EthApiError, PendingBlock,
14};
15use reth_storage_api::{BlockReaderIdExt, StateProviderBox, StateProviderFactory};
16
17impl<N, Rpc> LoadPendingBlock for OpEthApi<N, Rpc>
18where
19    N: RpcNodeCore,
20    OpEthApiError: FromEvmError<N::Evm>,
21    Rpc: RpcConvert<Primitives = N::Primitives, Error = OpEthApiError>,
22{
23    #[inline]
24    fn pending_block(&self) -> &tokio::sync::Mutex<Option<PendingBlock<N::Primitives>>> {
25        self.inner.eth_api.pending_block()
26    }
27
28    #[inline]
29    fn pending_env_builder(&self) -> &dyn PendingEnvBuilder<Self::Evm> {
30        self.inner.eth_api.pending_env_builder()
31    }
32
33    #[inline]
34    fn pending_block_kind(&self) -> PendingBlockKind {
35        self.inner.eth_api.pending_block_kind()
36    }
37
38    /// Returns a [`StateProviderBox`] on a mem-pool built pending block overlaying latest.
39    async fn local_pending_state(&self) -> Result<Option<StateProviderBox>, Self::Error>
40    where
41        Self: SpawnBlocking,
42    {
43        let Ok(Some(pending_block)) = self.pending_flashblock().await else {
44            return Ok(None);
45        };
46
47        let latest_historical = self
48            .provider()
49            .history_by_block_hash(pending_block.block().parent_hash())
50            .map_err(Self::Error::from_eth_err)?;
51
52        let state = BlockState::from(pending_block);
53
54        Ok(Some(Box::new(state.state_provider(latest_historical)) as StateProviderBox))
55    }
56
57    /// Returns the locally built pending block
58    async fn local_pending_block(
59        &self,
60    ) -> Result<Option<BlockAndReceipts<Self::Primitives>>, Self::Error> {
61        if let Ok(Some(pending)) = self.pending_flashblock().await {
62            return Ok(Some(pending.into_block_and_receipts()));
63        }
64
65        // See: <https://github.com/ethereum-optimism/op-geth/blob/f2e69450c6eec9c35d56af91389a1c47737206ca/miner/worker.go#L367-L375>
66        let latest = self
67            .provider()
68            .latest_header()?
69            .ok_or(EthApiError::HeaderNotFound(BlockNumberOrTag::Latest.into()))?;
70
71        let latest = self
72            .cache()
73            .get_block_and_receipts(latest.hash())
74            .await
75            .map_err(Self::Error::from_eth_err)?
76            .map(|(block, receipts)| BlockAndReceipts { block, receipts });
77        Ok(latest)
78    }
79}