reth_rpc_eth_types/
receipt.rs1use crate::EthApiError;
4use alloy_consensus::{ReceiptEnvelope, Transaction, TxReceipt};
5use alloy_eips::eip7840::BlobParams;
6use alloy_primitives::{Address, TxKind};
7use alloy_rpc_types_eth::{Log, ReceiptWithBloom, TransactionReceipt};
8use reth_chainspec::EthChainSpec;
9use reth_ethereum_primitives::Receipt;
10use reth_primitives_traits::NodePrimitives;
11use reth_rpc_convert::transaction::{ConvertReceiptInput, ReceiptConverter};
12use std::{borrow::Cow, sync::Arc};
13
14pub fn build_receipt<N, E>(
16 input: &ConvertReceiptInput<'_, N>,
17 blob_params: Option<BlobParams>,
18 build_envelope: impl FnOnce(ReceiptWithBloom<alloy_consensus::Receipt<Log>>) -> 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 let blob_gas_price =
29 blob_gas_used.and_then(|_| Some(blob_params?.calc_blob_fee(meta.excess_blob_gas?)));
30
31 let status = receipt.status_or_post_state();
32 let cumulative_gas_used = receipt.cumulative_gas_used();
33 let logs_bloom = receipt.bloom();
34
35 let logs = match receipt {
36 Cow::Borrowed(r) => {
37 Log::collect_for_receipt(*next_log_index, *meta, r.logs().iter().cloned())
38 }
39 Cow::Owned(r) => Log::collect_for_receipt(*next_log_index, *meta, r.into_logs()),
40 };
41
42 let rpc_receipt = alloy_rpc_types_eth::Receipt { status, cumulative_gas_used, logs };
43
44 let (contract_address, to) = match tx.kind() {
45 TxKind::Create => (Some(from.create(tx.nonce())), None),
46 TxKind::Call(addr) => (None, Some(Address(*addr))),
47 };
48
49 TransactionReceipt {
50 inner: build_envelope(ReceiptWithBloom { receipt: rpc_receipt, logs_bloom }),
51 transaction_hash: meta.tx_hash,
52 transaction_index: Some(meta.index),
53 block_hash: Some(meta.block_hash),
54 block_number: Some(meta.block_number),
55 from,
56 to,
57 gas_used: *gas_used,
58 contract_address,
59 effective_gas_price: tx.effective_gas_price(meta.base_fee),
60 blob_gas_price,
62 blob_gas_used,
63 }
64}
65
66#[derive(Debug)]
68pub struct EthReceiptConverter<ChainSpec> {
69 chain_spec: Arc<ChainSpec>,
70}
71
72impl<ChainSpec> Clone for EthReceiptConverter<ChainSpec> {
73 fn clone(&self) -> Self {
74 Self { chain_spec: self.chain_spec.clone() }
75 }
76}
77
78impl<ChainSpec> EthReceiptConverter<ChainSpec> {
79 pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
81 Self { chain_spec }
82 }
83}
84
85impl<N, ChainSpec> ReceiptConverter<N> for EthReceiptConverter<ChainSpec>
86where
87 N: NodePrimitives<Receipt = Receipt>,
88 ChainSpec: EthChainSpec + 'static,
89{
90 type RpcReceipt = TransactionReceipt;
91 type Error = EthApiError;
92
93 fn convert_receipts(
94 &self,
95 inputs: Vec<ConvertReceiptInput<'_, N>>,
96 ) -> Result<Vec<Self::RpcReceipt>, Self::Error> {
97 let mut receipts = Vec::with_capacity(inputs.len());
98
99 for input in inputs {
100 let tx_type = input.receipt.tx_type;
101 let blob_params = self.chain_spec.blob_params_at_timestamp(input.meta.timestamp);
102 receipts.push(build_receipt(&input, blob_params, |receipt_with_bloom| {
103 ReceiptEnvelope::from_typed(tx_type, receipt_with_bloom)
104 }));
105 }
106
107 Ok(receipts)
108 }
109}