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