reth_rpc_eth_types/
receipt.rs1use 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
14pub 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 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 blob_gas_price,
49 blob_gas_used,
50 }
51}
52
53#[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 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 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}