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 crate::{EthApiTypes, RpcNodeCoreExt, RpcReceipt};
5use alloy_consensus::{transaction::TransactionMeta, TxReceipt};
6use futures::Future;
7use reth_primitives_traits::SignerRecoverable;
8use reth_rpc_convert::{transaction::ConvertReceiptInput, RpcConvert};
9use reth_rpc_eth_types::{error::FromEthApiError, EthApiError};
10use reth_storage_api::{ProviderReceipt, ProviderTx};
11
12/// Calculates the gas used and next log index for a transaction at the given index
13pub fn calculate_gas_used_and_next_log_index(
14    tx_index: u64,
15    all_receipts: &[impl TxReceipt],
16) -> (u64, usize) {
17    let mut gas_used = 0;
18    let mut next_log_index = 0;
19
20    if tx_index > 0 {
21        for receipt in all_receipts.iter().take(tx_index as usize) {
22            gas_used = receipt.cumulative_gas_used();
23            next_log_index += receipt.logs().len();
24        }
25    }
26
27    (gas_used, next_log_index)
28}
29
30/// Assembles transaction receipt data w.r.t to network.
31///
32/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods.
33pub trait LoadReceipt:
34    EthApiTypes<
35        RpcConvert: RpcConvert<
36            Primitives = Self::Primitives,
37            Error = Self::Error,
38            Network = Self::NetworkTypes,
39        >,
40        Error: FromEthApiError,
41    > + RpcNodeCoreExt
42    + Send
43    + Sync
44{
45    /// Helper method for `eth_getBlockReceipts` and `eth_getTransactionReceipt`.
46    fn build_transaction_receipt(
47        &self,
48        tx: ProviderTx<Self::Provider>,
49        meta: TransactionMeta,
50        receipt: ProviderReceipt<Self::Provider>,
51    ) -> impl Future<Output = Result<RpcReceipt<Self::NetworkTypes>, Self::Error>> + Send {
52        async move {
53            let hash = meta.block_hash;
54            // get all receipts for the block
55            let all_receipts = self
56                .cache()
57                .get_receipts(hash)
58                .await
59                .map_err(Self::Error::from_eth_err)?
60                .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
61
62            let (gas_used, next_log_index) =
63                calculate_gas_used_and_next_log_index(meta.index, &all_receipts);
64
65            Ok(self
66                .tx_resp_builder()
67                .convert_receipts(vec![ConvertReceiptInput {
68                    tx: tx
69                        .try_into_recovered_unchecked()
70                        .map_err(Self::Error::from_eth_err)?
71                        .as_recovered_ref(),
72                    gas_used: receipt.cumulative_gas_used() - gas_used,
73                    receipt,
74                    next_log_index,
75                    meta,
76                }])?
77                .pop()
78                .unwrap())
79        }
80    }
81}