reth_rpc_eth_types/
receipt.rs1use super::{EthApiError, EthResult};
4use alloy_consensus::{ReceiptEnvelope, Transaction};
5use alloy_primitives::{Address, TxKind};
6use alloy_rpc_types_eth::{Log, ReceiptWithBloom, TransactionReceipt};
7use reth_primitives::{Receipt, TransactionMeta, TransactionSigned, TxType};
8use reth_primitives_traits::SignedTransaction;
9use revm_primitives::calc_blob_gasprice;
10
11pub fn build_receipt<T>(
13 transaction: &TransactionSigned,
14 meta: TransactionMeta,
15 receipt: &Receipt,
16 all_receipts: &[Receipt],
17 build_envelope: impl FnOnce(ReceiptWithBloom<alloy_consensus::Receipt<Log>>) -> T,
18) -> EthResult<TransactionReceipt<T>> {
19 let from =
22 transaction.recover_signer_unchecked().ok_or(EthApiError::InvalidTransactionSignature)?;
23
24 let gas_used = if meta.index == 0 {
26 receipt.cumulative_gas_used
27 } else {
28 let prev_tx_idx = (meta.index - 1) as usize;
29 all_receipts
30 .get(prev_tx_idx)
31 .map(|prev_receipt| receipt.cumulative_gas_used - prev_receipt.cumulative_gas_used)
32 .unwrap_or_default()
33 };
34
35 let blob_gas_used = transaction.transaction.blob_gas_used();
36 let blob_gas_price = blob_gas_used.and_then(|_| meta.excess_blob_gas.map(calc_blob_gasprice));
38 let logs_bloom = receipt.bloom_slow();
39
40 let mut num_logs = 0;
42 for prev_receipt in all_receipts.iter().take(meta.index as usize) {
43 num_logs += prev_receipt.logs.len();
44 }
45
46 let logs: Vec<Log> = receipt
47 .logs
48 .iter()
49 .enumerate()
50 .map(|(tx_log_idx, log)| Log {
51 inner: log.clone(),
52 block_hash: Some(meta.block_hash),
53 block_number: Some(meta.block_number),
54 block_timestamp: Some(meta.timestamp),
55 transaction_hash: Some(meta.tx_hash),
56 transaction_index: Some(meta.index),
57 log_index: Some((num_logs + tx_log_idx) as u64),
58 removed: false,
59 })
60 .collect();
61
62 let rpc_receipt = alloy_rpc_types_eth::Receipt {
63 status: receipt.success.into(),
64 cumulative_gas_used: receipt.cumulative_gas_used as u128,
65 logs,
66 };
67
68 let (contract_address, to) = match transaction.transaction.kind() {
69 TxKind::Create => (Some(from.create(transaction.transaction.nonce())), None),
70 TxKind::Call(addr) => (None, Some(Address(*addr))),
71 };
72
73 Ok(TransactionReceipt {
74 inner: build_envelope(ReceiptWithBloom { receipt: rpc_receipt, logs_bloom }),
75 transaction_hash: meta.tx_hash,
76 transaction_index: Some(meta.index),
77 block_hash: Some(meta.block_hash),
78 block_number: Some(meta.block_number),
79 from,
80 to,
81 gas_used: gas_used as u128,
82 contract_address,
83 effective_gas_price: transaction.effective_gas_price(meta.base_fee),
84 blob_gas_price,
86 blob_gas_used: blob_gas_used.map(u128::from),
87 authorization_list: transaction.authorization_list().map(|l| l.to_vec()),
88 })
89}
90
91#[derive(Debug)]
93pub struct EthReceiptBuilder {
94 pub base: TransactionReceipt,
96}
97
98impl EthReceiptBuilder {
99 pub fn new(
104 transaction: &TransactionSigned,
105 meta: TransactionMeta,
106 receipt: &Receipt,
107 all_receipts: &[Receipt],
108 ) -> EthResult<Self> {
109 let base = build_receipt(transaction, meta, receipt, all_receipts, |receipt_with_bloom| {
110 match receipt.tx_type {
111 TxType::Legacy => ReceiptEnvelope::Legacy(receipt_with_bloom),
112 TxType::Eip2930 => ReceiptEnvelope::Eip2930(receipt_with_bloom),
113 TxType::Eip1559 => ReceiptEnvelope::Eip1559(receipt_with_bloom),
114 TxType::Eip4844 => ReceiptEnvelope::Eip4844(receipt_with_bloom),
115 TxType::Eip7702 => ReceiptEnvelope::Eip7702(receipt_with_bloom),
116 TxType::Seismic => ReceiptEnvelope::Seismic(receipt_with_bloom),
117 #[allow(unreachable_patterns)]
118 _ => unreachable!(),
119 }
120 })?;
121
122 Ok(Self { base })
123 }
124
125 pub fn build(self) -> TransactionReceipt {
127 self.base
128 }
129}