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 alloy_consensus::BlockHeader;
8use alloy_eips::{BlockId, BlockNumberOrTag};
9use alloy_primitives::{BlockHash, B256};
10use derive_more::Constructor;
11use reth_chain_state::{
12    BlockState, ExecutedBlock, ExecutedBlockWithTrieUpdates, ExecutedTrieUpdates,
13};
14use reth_ethereum_primitives::Receipt;
15use reth_evm::EvmEnv;
16use reth_primitives_traits::{Block, NodePrimitives, RecoveredBlock, SealedHeader};
17
18/// Configured [`EvmEnv`] for a pending block.
19#[derive(Debug, Clone, Constructor)]
20pub struct PendingBlockEnv<B: Block, R, Spec> {
21    /// Configured [`EvmEnv`] for the pending block.
22    pub evm_env: EvmEnv<Spec>,
23    /// Origin block for the config
24    pub origin: PendingBlockEnvOrigin<B, R>,
25}
26
27/// The origin for a configured [`PendingBlockEnv`]
28#[derive(Clone, Debug)]
29pub enum PendingBlockEnvOrigin<B: Block = reth_ethereum_primitives::Block, R = Receipt> {
30    /// The pending block as received from the CL.
31    ActualPending(Arc<RecoveredBlock<B>>, Arc<Vec<R>>),
32    /// The _modified_ header of the latest block.
33    ///
34    /// This derives the pending state based on the latest header by modifying:
35    ///  - the timestamp
36    ///  - the block number
37    ///  - fees
38    DerivedFromLatest(SealedHeader<B::Header>),
39}
40
41impl<B: Block, R> PendingBlockEnvOrigin<B, R> {
42    /// Returns true if the origin is the actual pending block as received from the CL.
43    pub const fn is_actual_pending(&self) -> bool {
44        matches!(self, Self::ActualPending(_, _))
45    }
46
47    /// Consumes the type and returns the actual pending block.
48    pub fn into_actual_pending(self) -> Option<Arc<RecoveredBlock<B>>> {
49        match self {
50            Self::ActualPending(block, _) => Some(block),
51            _ => None,
52        }
53    }
54
55    /// Returns the [`BlockId`] that represents the state of the block.
56    ///
57    /// If this is the actual pending block, the state is the "Pending" tag, otherwise we can safely
58    /// identify the block by its hash (latest block).
59    pub fn state_block_id(&self) -> BlockId {
60        match self {
61            Self::ActualPending(_, _) => BlockNumberOrTag::Pending.into(),
62            Self::DerivedFromLatest(latest) => BlockId::Hash(latest.hash().into()),
63        }
64    }
65
66    /// Returns the hash of the block the pending block should be built on.
67    ///
68    /// For the [`PendingBlockEnvOrigin::ActualPending`] this is the parent hash of the block.
69    /// For the [`PendingBlockEnvOrigin::DerivedFromLatest`] this is the hash of the _latest_
70    /// header.
71    pub fn build_target_hash(&self) -> B256 {
72        match self {
73            Self::ActualPending(block, _) => block.header().parent_hash(),
74            Self::DerivedFromLatest(latest) => latest.hash(),
75        }
76    }
77}
78
79/// A type alias for an [`Arc`] wrapped [`RecoveredBlock`].
80pub type PendingRecoveredBlock<N> = Arc<RecoveredBlock<<N as NodePrimitives>::Block>>;
81
82/// A type alias for an [`Arc`] wrapped vector of [`NodePrimitives::Receipt`].
83pub type PendingBlockReceipts<N> = Arc<Vec<<N as NodePrimitives>::Receipt>>;
84
85/// A type alias for a pair of an [`Arc`] wrapped [`RecoveredBlock`] and a vector of
86/// [`NodePrimitives::Receipt`].
87pub type PendingBlockAndReceipts<N> = (PendingRecoveredBlock<N>, PendingBlockReceipts<N>);
88
89/// Locally built pending block for `pending` tag.
90#[derive(Debug, Clone, Constructor)]
91pub struct PendingBlock<N: NodePrimitives> {
92    /// Timestamp when the pending block is considered outdated.
93    pub expires_at: Instant,
94    /// The receipts for the pending block
95    pub receipts: PendingBlockReceipts<N>,
96    /// The locally built pending block with execution output.
97    pub executed_block: ExecutedBlock<N>,
98}
99
100impl<N: NodePrimitives> PendingBlock<N> {
101    /// Creates a new instance of [`PendingBlock`] with `executed_block` as its output that should
102    /// not be used past `expires_at`.
103    pub fn with_executed_block(expires_at: Instant, executed_block: ExecutedBlock<N>) -> Self {
104        Self {
105            expires_at,
106            receipts: Arc::new(
107                executed_block.execution_output.receipts.iter().flatten().cloned().collect(),
108            ),
109            executed_block,
110        }
111    }
112
113    /// Returns the locally built pending [`RecoveredBlock`].
114    pub const fn block(&self) -> &PendingRecoveredBlock<N> {
115        &self.executed_block.recovered_block
116    }
117
118    /// Converts this [`PendingBlock`] into a pair of [`RecoveredBlock`] and a vector of
119    /// [`NodePrimitives::Receipt`]s, taking self.
120    pub fn into_block_and_receipts(self) -> PendingBlockAndReceipts<N> {
121        (self.executed_block.recovered_block, self.receipts)
122    }
123
124    /// Returns a pair of [`RecoveredBlock`] and a vector of  [`NodePrimitives::Receipt`]s by
125    /// cloning from borrowed self.
126    pub fn to_block_and_receipts(&self) -> PendingBlockAndReceipts<N> {
127        (self.executed_block.recovered_block.clone(), self.receipts.clone())
128    }
129
130    /// Returns a hash of the parent block for this `executed_block`.
131    pub fn parent_hash(&self) -> BlockHash {
132        self.executed_block.recovered_block().parent_hash()
133    }
134}
135
136impl<N: NodePrimitives> From<PendingBlock<N>> for BlockState<N> {
137    fn from(pending_block: PendingBlock<N>) -> Self {
138        Self::new(ExecutedBlockWithTrieUpdates::<N>::new(
139            pending_block.executed_block.recovered_block,
140            pending_block.executed_block.execution_output,
141            pending_block.executed_block.hashed_state,
142            ExecutedTrieUpdates::Missing,
143        ))
144    }
145}