Skip to main content

reth_rpc_eth_types/
pending_block.rs

1//! Helper types for `reth_rpc_eth_api::EthApiServer` implementation.
2//!
3//! Types used in block building.
4
5use std::{sync::Arc, time::Instant};
6
7use crate::block::BlockAndReceipts;
8use alloy_consensus::BlockHeader;
9use alloy_eips::{BlockId, BlockNumberOrTag};
10use alloy_primitives::{BlockHash, TxHash, B256};
11use derive_more::Constructor;
12use reth_chain_state::{BlockState, ExecutedBlock};
13use reth_ethereum_primitives::Receipt;
14use reth_evm::{ConfigureEvm, EvmEnvFor};
15use reth_primitives_traits::{
16    Block, BlockTy, IndexedTx, NodePrimitives, ReceiptTy, RecoveredBlock, SealedHeader,
17};
18use reth_rpc_convert::{RpcConvert, RpcTypes};
19
20/// Configured [`reth_evm::EvmEnv`] for a pending block.
21#[derive(Debug, Clone, Constructor)]
22pub struct PendingBlockEnv<Evm: ConfigureEvm> {
23    /// Configured [`reth_evm::EvmEnv`] for the pending block.
24    pub evm_env: EvmEnvFor<Evm>,
25    /// Origin block for the config
26    pub origin: PendingBlockEnvOrigin<BlockTy<Evm::Primitives>, ReceiptTy<Evm::Primitives>>,
27}
28
29/// The origin for a configured [`PendingBlockEnv`]
30#[derive(Clone, Debug)]
31pub enum PendingBlockEnvOrigin<B: Block = reth_ethereum_primitives::Block, R = Receipt> {
32    /// The pending block as received from the CL.
33    ActualPending(Arc<RecoveredBlock<B>>, Arc<Vec<R>>),
34    /// The _modified_ header of the latest block.
35    ///
36    /// This derives the pending state based on the latest header by modifying:
37    ///  - the timestamp
38    ///  - the block number
39    ///  - fees
40    DerivedFromLatest(SealedHeader<B::Header>),
41}
42
43impl<B: Block, R> PendingBlockEnvOrigin<B, R> {
44    /// Returns true if the origin is the actual pending block as received from the CL.
45    pub const fn is_actual_pending(&self) -> bool {
46        matches!(self, Self::ActualPending(_, _))
47    }
48
49    /// Consumes the type and returns the actual pending block.
50    pub fn into_actual_pending(self) -> Option<Arc<RecoveredBlock<B>>> {
51        match self {
52            Self::ActualPending(block, _) => Some(block),
53            _ => None,
54        }
55    }
56
57    /// Returns the [`BlockId`] that represents the state of the block.
58    ///
59    /// If this is the actual pending block, the state is the "Pending" tag, otherwise we can safely
60    /// identify the block by its hash (latest block).
61    pub fn state_block_id(&self) -> BlockId {
62        match self {
63            Self::ActualPending(_, _) => BlockNumberOrTag::Pending.into(),
64            Self::DerivedFromLatest(latest) => BlockId::Hash(latest.hash().into()),
65        }
66    }
67
68    /// Returns the hash of the block the pending block should be built on.
69    ///
70    /// For the [`PendingBlockEnvOrigin::ActualPending`] this is the parent hash of the block.
71    /// For the [`PendingBlockEnvOrigin::DerivedFromLatest`] this is the hash of the _latest_
72    /// header.
73    pub fn build_target_hash(&self) -> B256 {
74        match self {
75            Self::ActualPending(block, _) => block.header().parent_hash(),
76            Self::DerivedFromLatest(latest) => latest.hash(),
77        }
78    }
79}
80
81/// A type alias for a pair of an [`Arc`] wrapped [`RecoveredBlock`] and a vector of
82/// [`NodePrimitives::Receipt`].
83pub type PendingBlockAndReceipts<N> = BlockAndReceipts<N>;
84
85/// Locally built pending block for `pending` tag.
86#[derive(Debug, Clone, Constructor)]
87pub struct PendingBlock<N: NodePrimitives> {
88    /// Timestamp when the pending block is considered outdated.
89    pub expires_at: Instant,
90    /// The receipts for the pending block
91    pub receipts: Arc<Vec<ReceiptTy<N>>>,
92    /// The locally built pending block with execution output.
93    pub executed_block: ExecutedBlock<N>,
94}
95
96impl<N: NodePrimitives> PendingBlock<N> {
97    /// Creates a new instance of [`PendingBlock`] with `executed_block` as its output that should
98    /// not be used past `expires_at`.
99    pub fn with_executed_block(expires_at: Instant, executed_block: ExecutedBlock<N>) -> Self {
100        Self {
101            expires_at,
102            receipts: Arc::new(executed_block.execution_output.receipts.clone()),
103            executed_block,
104        }
105    }
106
107    /// Returns the locally built pending [`RecoveredBlock`].
108    pub const fn block(&self) -> &Arc<RecoveredBlock<BlockTy<N>>> {
109        &self.executed_block.recovered_block
110    }
111
112    /// Converts this [`PendingBlock`] into a pair of [`RecoveredBlock`] and a vector of
113    /// [`NodePrimitives::Receipt`]s, taking self.
114    pub fn into_block_and_receipts(self) -> PendingBlockAndReceipts<N> {
115        BlockAndReceipts { block: self.executed_block.recovered_block, receipts: self.receipts }
116    }
117
118    /// Returns a pair of [`RecoveredBlock`] and a vector of  [`NodePrimitives::Receipt`]s by
119    /// cloning from borrowed self.
120    pub fn to_block_and_receipts(&self) -> PendingBlockAndReceipts<N> {
121        BlockAndReceipts {
122            block: self.executed_block.recovered_block.clone(),
123            receipts: self.receipts.clone(),
124        }
125    }
126
127    /// Returns a hash of the parent block for this `executed_block`.
128    pub fn parent_hash(&self) -> BlockHash {
129        self.executed_block.recovered_block().parent_hash()
130    }
131
132    /// Finds a transaction by hash and returns it along with its corresponding receipt.
133    ///
134    /// Returns `None` if the transaction is not found in this block.
135    pub fn find_transaction_and_receipt_by_hash(
136        &self,
137        tx_hash: TxHash,
138    ) -> Option<(IndexedTx<'_, N::Block>, &N::Receipt)> {
139        let indexed_tx = self.executed_block.recovered_block().find_indexed(tx_hash)?;
140        let receipt = self.receipts.get(indexed_tx.index())?;
141        Some((indexed_tx, receipt))
142    }
143
144    /// Returns the rpc transaction receipt for the given transaction hash if it exists.
145    ///
146    /// This uses the given converter to turn [`Self::find_transaction_and_receipt_by_hash`] into
147    /// the rpc format.
148    pub fn find_and_convert_transaction_receipt<C>(
149        &self,
150        tx_hash: TxHash,
151        converter: &C,
152    ) -> Option<Result<<C::Network as RpcTypes>::Receipt, C::Error>>
153    where
154        C: RpcConvert<Primitives = N>,
155    {
156        self.to_block_and_receipts().find_and_convert_transaction_receipt(tx_hash, converter)
157    }
158}
159
160impl<N: NodePrimitives> From<PendingBlock<N>> for BlockState<N> {
161    fn from(pending_block: PendingBlock<N>) -> Self {
162        Self::new(pending_block.executed_block)
163    }
164}