reth_rpc_eth_types/
receipt.rs

1//! RPC receipt response builder, extends a layer one receipt with layer two data.
2
3use crate::EthApiError;
4use alloy_consensus::{ReceiptEnvelope, Transaction};
5use alloy_eips::eip7840::BlobParams;
6use alloy_primitives::{Address, TxKind};
7use alloy_rpc_types_eth::{Log, TransactionReceipt};
8use reth_chainspec::EthChainSpec;
9use reth_ethereum_primitives::Receipt;
10use reth_primitives_traits::{NodePrimitives, TransactionMeta};
11use reth_rpc_convert::transaction::{ConvertReceiptInput, ReceiptConverter};
12use std::sync::Arc;
13
14/// Builds an [`TransactionReceipt`] obtaining the inner receipt envelope from the given closure.
15pub fn build_receipt<N, E>(
16    input: ConvertReceiptInput<'_, N>,
17    blob_params: Option<BlobParams>,
18    build_rpc_receipt: impl FnOnce(N::Receipt, usize, TransactionMeta) -> E,
19) -> TransactionReceipt<E>
20where
21    N: NodePrimitives,
22{
23    let ConvertReceiptInput { tx, meta, receipt, gas_used, next_log_index } = input;
24    let from = tx.signer();
25
26    let blob_gas_used = tx.blob_gas_used();
27    // Blob gas price should only be present if the transaction is a blob transaction
28    let blob_gas_price =
29        blob_gas_used.and_then(|_| Some(blob_params?.calc_blob_fee(meta.excess_blob_gas?)));
30
31    let (contract_address, to) = match tx.kind() {
32        TxKind::Create => (Some(from.create(tx.nonce())), None),
33        TxKind::Call(addr) => (None, Some(Address(*addr))),
34    };
35
36    TransactionReceipt {
37        inner: build_rpc_receipt(receipt, next_log_index, meta),
38        transaction_hash: meta.tx_hash,
39        transaction_index: Some(meta.index),
40        block_hash: Some(meta.block_hash),
41        block_number: Some(meta.block_number),
42        from,
43        to,
44        gas_used,
45        contract_address,
46        effective_gas_price: tx.effective_gas_price(meta.base_fee),
47        // EIP-4844 fields
48        blob_gas_price,
49        blob_gas_used,
50    }
51}
52
53/// Converter for Ethereum receipts.
54#[derive(derive_more::Debug)]
55pub struct EthReceiptConverter<
56    ChainSpec,
57    Builder = fn(Receipt, usize, TransactionMeta) -> ReceiptEnvelope<Log>,
58> {
59    chain_spec: Arc<ChainSpec>,
60    #[debug(skip)]
61    build_rpc_receipt: Builder,
62}
63
64impl<ChainSpec, Builder> Clone for EthReceiptConverter<ChainSpec, Builder>
65where
66    Builder: Clone,
67{
68    fn clone(&self) -> Self {
69        Self {
70            chain_spec: self.chain_spec.clone(),
71            build_rpc_receipt: self.build_rpc_receipt.clone(),
72        }
73    }
74}
75
76impl<ChainSpec> EthReceiptConverter<ChainSpec> {
77    /// Creates a new converter with the given chain spec.
78    pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
79        Self {
80            chain_spec,
81            build_rpc_receipt: |receipt, next_log_index, meta| {
82                receipt.into_rpc(next_log_index, meta).into()
83            },
84        }
85    }
86
87    /// Sets new builder for the converter.
88    pub fn with_builder<Builder>(
89        self,
90        build_rpc_receipt: Builder,
91    ) -> EthReceiptConverter<ChainSpec, Builder> {
92        EthReceiptConverter { chain_spec: self.chain_spec, build_rpc_receipt }
93    }
94}
95
96impl<N, ChainSpec, Builder, Rpc> ReceiptConverter<N> for EthReceiptConverter<ChainSpec, Builder>
97where
98    N: NodePrimitives,
99    ChainSpec: EthChainSpec + 'static,
100    Builder: Fn(N::Receipt, usize, TransactionMeta) -> Rpc + 'static,
101{
102    type RpcReceipt = TransactionReceipt<Rpc>;
103    type Error = EthApiError;
104
105    fn convert_receipts(
106        &self,
107        inputs: Vec<ConvertReceiptInput<'_, N>>,
108    ) -> Result<Vec<Self::RpcReceipt>, Self::Error> {
109        let mut receipts = Vec::with_capacity(inputs.len());
110
111        for input in inputs {
112            let blob_params = self.chain_spec.blob_params_at_timestamp(input.meta.timestamp);
113            receipts.push(build_receipt(input, blob_params, &self.build_rpc_receipt));
114        }
115
116        Ok(receipts)
117    }
118}