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