Skip to main content

reth_rpc_eth_types/
block.rs

1//! Block related types for RPC API.
2
3use std::sync::Arc;
4
5use alloy_consensus::{transaction::TxHashRef, TxReceipt};
6use alloy_primitives::TxHash;
7use reth_primitives_traits::{
8    Block, BlockBody, BlockTy, IndexedTx, NodePrimitives, ReceiptTy, Recovered, RecoveredBlock,
9    SealedBlock,
10};
11use reth_rpc_convert::{transaction::ConvertReceiptInput, RpcConvert, RpcTypes};
12
13use crate::utils::calculate_gas_used_and_next_log_index;
14
15/// Cached data for a transaction lookup.
16#[derive(Debug, Clone)]
17pub struct CachedTransaction<B: Block, R> {
18    /// The block containing this transaction.
19    pub block: Arc<RecoveredBlock<B>>,
20    /// Index of the transaction within the block.
21    pub tx_index: usize,
22    /// Receipts for the block, if available.
23    pub receipts: Option<Arc<Vec<R>>>,
24}
25
26impl<B: Block, R> CachedTransaction<B, R> {
27    /// Creates a new cached transaction entry.
28    pub const fn new(
29        block: Arc<RecoveredBlock<B>>,
30        tx_index: usize,
31        receipts: Option<Arc<Vec<R>>>,
32    ) -> Self {
33        Self { block, tx_index, receipts }
34    }
35
36    /// Returns the `Recovered<&T>` transaction at the cached index.
37    pub fn recovered_transaction(&self) -> Option<Recovered<&<B::Body as BlockBody>::Transaction>> {
38        self.block.recovered_transaction(self.tx_index)
39    }
40
41    /// Converts this cached transaction into an RPC receipt using the given converter.
42    ///
43    /// Returns `None` if receipts are not available or the transaction index is out of bounds.
44    pub fn into_receipt<N, C>(
45        self,
46        converter: &C,
47    ) -> Option<Result<<C::Network as RpcTypes>::Receipt, C::Error>>
48    where
49        N: NodePrimitives<Block = B, Receipt = R>,
50        R: TxReceipt + Clone,
51        C: RpcConvert<Primitives = N>,
52    {
53        let receipts = self.receipts?;
54        let receipt = receipts.get(self.tx_index)?;
55        let tx_hash = *self.block.body().transactions().get(self.tx_index)?.tx_hash();
56        let tx = self.block.find_indexed(tx_hash)?;
57        convert_transaction_receipt::<N, C>(
58            self.block.as_ref(),
59            receipts.as_ref(),
60            tx,
61            receipt,
62            converter,
63        )
64    }
65}
66
67/// A pair of an [`Arc`] wrapped [`RecoveredBlock`] and its corresponding receipts.
68///
69/// This type is used throughout the RPC layer to efficiently pass around
70/// blocks with their execution receipts, avoiding unnecessary cloning.
71#[derive(Debug, Clone)]
72pub struct BlockAndReceipts<N: NodePrimitives> {
73    /// The recovered block.
74    pub block: Arc<RecoveredBlock<BlockTy<N>>>,
75    /// The receipts for the block.
76    pub receipts: Arc<Vec<ReceiptTy<N>>>,
77}
78
79impl<N: NodePrimitives> BlockAndReceipts<N> {
80    /// Creates a new [`BlockAndReceipts`] instance.
81    pub const fn new(
82        block: Arc<RecoveredBlock<BlockTy<N>>>,
83        receipts: Arc<Vec<ReceiptTy<N>>>,
84    ) -> Self {
85        Self { block, receipts }
86    }
87
88    /// Finds a transaction by hash and returns it along with its corresponding receipt.
89    ///
90    /// Returns `None` if the transaction is not found in this block.
91    pub fn find_transaction_and_receipt_by_hash(
92        &self,
93        tx_hash: TxHash,
94    ) -> Option<(IndexedTx<'_, N::Block>, &N::Receipt)> {
95        let indexed_tx = self.block.find_indexed(tx_hash)?;
96        let receipt = self.receipts.get(indexed_tx.index())?;
97        Some((indexed_tx, receipt))
98    }
99
100    /// Returns the underlying sealed block.
101    pub fn sealed_block(&self) -> &SealedBlock<BlockTy<N>> {
102        self.block.sealed_block()
103    }
104
105    /// Returns the rpc transaction receipt for the given transaction hash if it exists.
106    ///
107    /// This uses the given converter to turn [`Self::find_transaction_and_receipt_by_hash`] into
108    /// the rpc format.
109    pub fn find_and_convert_transaction_receipt<C>(
110        &self,
111        tx_hash: TxHash,
112        converter: &C,
113    ) -> Option<Result<<C::Network as RpcTypes>::Receipt, C::Error>>
114    where
115        C: RpcConvert<Primitives = N>,
116    {
117        let (tx, receipt) = self.find_transaction_and_receipt_by_hash(tx_hash)?;
118        convert_transaction_receipt(
119            self.block.as_ref(),
120            self.receipts.as_ref(),
121            tx,
122            receipt,
123            converter,
124        )
125    }
126}
127
128/// Converts a transaction and its receipt into the rpc receipt format using the given converter.
129pub fn convert_transaction_receipt<N, C>(
130    block: &RecoveredBlock<BlockTy<N>>,
131    all_receipts: &[ReceiptTy<N>],
132    tx: IndexedTx<'_, BlockTy<N>>,
133    receipt: &ReceiptTy<N>,
134    converter: &C,
135) -> Option<Result<<C::Network as RpcTypes>::Receipt, C::Error>>
136where
137    N: NodePrimitives,
138    C: RpcConvert<Primitives = N>,
139{
140    let meta = tx.meta();
141    let (gas_used, next_log_index) =
142        calculate_gas_used_and_next_log_index(meta.index, all_receipts);
143
144    converter
145        .convert_receipts_with_block(
146            vec![ConvertReceiptInput {
147                tx: tx.recovered_tx(),
148                gas_used: receipt.cumulative_gas_used() - gas_used,
149                receipt: receipt.clone(),
150                next_log_index,
151                meta,
152            }],
153            block.sealed_block(),
154        )
155        .map(|mut receipts| receipts.pop())
156        .transpose()
157}