reth_rpc_eth_types/
pending_block.rs1use std::{sync::Arc, time::Instant};
6
7use crate::{block::BlockAndReceipts, utils::calculate_gas_used_and_next_log_index};
8use alloy_consensus::{BlockHeader, TxReceipt};
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::{transaction::ConvertReceiptInput, RpcConvert, RpcTypes};
19
20#[derive(Debug, Clone, Constructor)]
22pub struct PendingBlockEnv<Evm: ConfigureEvm> {
23 pub evm_env: EvmEnvFor<Evm>,
25 pub origin: PendingBlockEnvOrigin<BlockTy<Evm::Primitives>, ReceiptTy<Evm::Primitives>>,
27}
28
29#[derive(Clone, Debug)]
31pub enum PendingBlockEnvOrigin<B: Block = reth_ethereum_primitives::Block, R = Receipt> {
32 ActualPending(Arc<RecoveredBlock<B>>, Arc<Vec<R>>),
34 DerivedFromLatest(SealedHeader<B::Header>),
41}
42
43impl<B: Block, R> PendingBlockEnvOrigin<B, R> {
44 pub const fn is_actual_pending(&self) -> bool {
46 matches!(self, Self::ActualPending(_, _))
47 }
48
49 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 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 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
81pub type PendingBlockAndReceipts<N> = BlockAndReceipts<N>;
84
85#[derive(Debug, Clone, Constructor)]
87pub struct PendingBlock<N: NodePrimitives> {
88 pub expires_at: Instant,
90 pub receipts: Arc<Vec<ReceiptTy<N>>>,
92 pub executed_block: ExecutedBlock<N>,
94}
95
96impl<N: NodePrimitives> PendingBlock<N> {
97 pub fn with_executed_block(expires_at: Instant, executed_block: ExecutedBlock<N>) -> Self {
100 Self {
101 expires_at,
102 receipts: Arc::new(
103 executed_block.execution_output.receipts.iter().flatten().cloned().collect(),
104 ),
105 executed_block,
106 }
107 }
108
109 pub const fn block(&self) -> &Arc<RecoveredBlock<BlockTy<N>>> {
111 &self.executed_block.recovered_block
112 }
113
114 pub fn into_block_and_receipts(self) -> PendingBlockAndReceipts<N> {
117 BlockAndReceipts { block: self.executed_block.recovered_block, receipts: self.receipts }
118 }
119
120 pub fn to_block_and_receipts(&self) -> PendingBlockAndReceipts<N> {
123 BlockAndReceipts {
124 block: self.executed_block.recovered_block.clone(),
125 receipts: self.receipts.clone(),
126 }
127 }
128
129 pub fn parent_hash(&self) -> BlockHash {
131 self.executed_block.recovered_block().parent_hash()
132 }
133
134 pub fn find_transaction_and_receipt_by_hash(
138 &self,
139 tx_hash: TxHash,
140 ) -> Option<(IndexedTx<'_, N::Block>, &N::Receipt)> {
141 let indexed_tx = self.executed_block.recovered_block().find_indexed(tx_hash)?;
142 let receipt = self.receipts.get(indexed_tx.index())?;
143 Some((indexed_tx, receipt))
144 }
145
146 pub fn find_and_convert_transaction_receipt<C>(
151 &self,
152 tx_hash: TxHash,
153 converter: &C,
154 ) -> Option<Result<<C::Network as RpcTypes>::Receipt, C::Error>>
155 where
156 C: RpcConvert<Primitives = N>,
157 {
158 let (tx, receipt) = self.find_transaction_and_receipt_by_hash(tx_hash)?;
159 let meta = tx.meta();
160 let all_receipts = &self.receipts;
161
162 let (gas_used, next_log_index) =
163 calculate_gas_used_and_next_log_index(meta.index, all_receipts);
164
165 converter
166 .convert_receipts_with_block(
167 vec![ConvertReceiptInput {
168 tx: tx.recovered_tx(),
169 gas_used: receipt.cumulative_gas_used() - gas_used,
170 receipt: receipt.clone(),
171 next_log_index,
172 meta,
173 }],
174 self.executed_block.sealed_block(),
175 )
176 .map(|mut receipts| receipts.pop())
177 .transpose()
178 }
179}
180
181impl<N: NodePrimitives> From<PendingBlock<N>> for BlockState<N> {
182 fn from(pending_block: PendingBlock<N>) -> Self {
183 Self::new(pending_block.executed_block)
184 }
185}