Skip to main content

reth_rpc_eth_api/helpers/
receipt.rs

1//! Loads a receipt from database. Helper trait for `eth_` block and transaction RPC methods, that
2//! loads receipt data w.r.t. network.
3
4use std::sync::Arc;
5
6use crate::{EthApiTypes, RpcNodeCoreExt, RpcReceipt};
7use alloy_consensus::{transaction::TransactionMeta, TxReceipt};
8use futures::Future;
9use reth_primitives_traits::{Recovered, RecoveredBlock};
10use reth_rpc_convert::{transaction::ConvertReceiptInput, RpcConvert};
11use reth_rpc_eth_types::{
12    error::FromEthApiError, utils::calculate_gas_used_and_next_log_index, EthApiError,
13};
14use reth_storage_api::{ProviderBlock, ProviderReceipt, ProviderTx};
15
16/// Assembles transaction receipt data w.r.t to network.
17///
18/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods.
19pub trait LoadReceipt:
20    EthApiTypes<RpcConvert: RpcConvert<Primitives = Self::Primitives>> + RpcNodeCoreExt + Send + Sync
21{
22    /// Helper method for `eth_getBlockReceipts` and `eth_getTransactionReceipt`.
23    ///
24    /// If a value is `Some`, skips the corresponding cache lookup entirely.
25    fn build_transaction_receipt(
26        &self,
27        tx: Recovered<ProviderTx<Self::Provider>>,
28        meta: TransactionMeta,
29        receipt: ProviderReceipt<Self::Provider>,
30        all_receipts: Option<Arc<Vec<ProviderReceipt<Self::Provider>>>>,
31        block: Option<Arc<RecoveredBlock<ProviderBlock<Self::Provider>>>>,
32    ) -> impl Future<Output = Result<RpcReceipt<Self::NetworkTypes>, Self::Error>> + Send {
33        async move {
34            let hash = meta.block_hash;
35            let (block, all_receipts) = match (block, all_receipts) {
36                (Some(block), Some(all_receipts)) => (Some(block), all_receipts),
37                (Some(block), None) => {
38                    let all_receipts = self
39                        .cache()
40                        .get_receipts(hash)
41                        .await
42                        .map_err(Self::Error::from_eth_err)?
43                        .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
44                    (Some(block), all_receipts)
45                }
46                (None, Some(all_receipts)) => {
47                    let block = self
48                        .cache()
49                        .get_maybe_block(hash)
50                        .await
51                        .map_err(Self::Error::from_eth_err)?;
52                    (block, all_receipts)
53                }
54                (None, None) => {
55                    let (all_receipts, block) = self
56                        .cache()
57                        .get_receipts_and_maybe_block(hash)
58                        .await
59                        .map_err(Self::Error::from_eth_err)?
60                        .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
61                    (block, all_receipts)
62                }
63            };
64
65            let (gas_used, next_log_index) =
66                calculate_gas_used_and_next_log_index(meta.index, &all_receipts);
67
68            let inputs = vec![ConvertReceiptInput {
69                tx: tx.as_recovered_ref(),
70                gas_used: receipt.cumulative_gas_used() - gas_used,
71                receipt,
72                next_log_index,
73                meta,
74            }];
75            let mut receipts = match block {
76                Some(block) => {
77                    self.converter().convert_receipts_with_block(inputs, block.sealed_block())
78                }
79                None => self.converter().convert_receipts(inputs),
80            }?;
81
82            Ok(receipts.pop().unwrap())
83        }
84    }
85}