reth_rpc/eth/helpers/
types.rs
1use alloy_consensus::{Transaction as _, TxEnvelope};
4use alloy_network::{Ethereum, Network};
5use alloy_primitives::Signature;
6use alloy_rpc_types::TransactionRequest;
7use alloy_rpc_types_eth::{Transaction, TransactionInfo};
8use reth_ethereum_primitives::TransactionSigned;
9use reth_primitives_traits::Recovered;
10use reth_rpc_eth_api::EthApiTypes;
11use reth_rpc_eth_types::EthApiError;
12use reth_rpc_types_compat::TransactionCompat;
13
14#[derive(Debug, Clone, Copy, Default)]
16pub struct EthereumEthApiTypes(EthTxBuilder);
17
18impl EthApiTypes for EthereumEthApiTypes {
19 type Error = EthApiError;
20 type NetworkTypes = Ethereum;
21 type TransactionCompat = EthTxBuilder;
22
23 fn tx_resp_builder(&self) -> &Self::TransactionCompat {
24 &self.0
25 }
26}
27
28#[derive(Debug, Clone, Copy, Default)]
30#[non_exhaustive]
31pub struct EthTxBuilder;
32
33impl TransactionCompat<TransactionSigned> for EthTxBuilder
34where
35 Self: Send + Sync,
36{
37 type Transaction = <Ethereum as Network>::TransactionResponse;
38
39 type Error = EthApiError;
40
41 fn fill(
42 &self,
43 tx: Recovered<TransactionSigned>,
44 tx_info: TransactionInfo,
45 ) -> Result<Self::Transaction, Self::Error> {
46 let tx = tx.convert::<TxEnvelope>();
47
48 let TransactionInfo {
49 block_hash, block_number, index: transaction_index, base_fee, ..
50 } = tx_info;
51
52 let effective_gas_price = base_fee
53 .map(|base_fee| {
54 tx.effective_tip_per_gas(base_fee).unwrap_or_default() + base_fee as u128
55 })
56 .unwrap_or_else(|| tx.max_fee_per_gas());
57
58 Ok(Transaction {
59 inner: tx,
60 block_hash,
61 block_number,
62 transaction_index,
63 effective_gas_price: Some(effective_gas_price),
64 })
65 }
66
67 fn build_simulate_v1_transaction(
68 &self,
69 request: TransactionRequest,
70 ) -> Result<TransactionSigned, Self::Error> {
71 let Ok(tx) = request.build_typed_tx() else {
72 return Err(EthApiError::TransactionConversionError)
73 };
74
75 let signature = Signature::new(Default::default(), Default::default(), false);
77 Ok(TransactionSigned::new_unhashed(tx.into(), signature))
78 }
79
80 fn otterscan_api_truncate_input(tx: &mut Self::Transaction) {
81 let input = tx.inner.inner_mut().input_mut();
82 *input = input.slice(..4);
83 }
84}
85
86#[cfg(test)]
88mod tests {
89 use super::*;
90 use alloy_consensus::TxType;
91 use reth_rpc_eth_types::simulate::resolve_transaction;
92 use revm::database::CacheDB;
93
94 #[test]
95 fn test_resolve_transaction_empty_request() {
96 let builder = EthTxBuilder::default();
97 let mut db = CacheDB::<reth_revm::db::EmptyDBTyped<reth_errors::ProviderError>>::default();
98 let tx = TransactionRequest::default();
99 let result = resolve_transaction(tx, 21000, 0, 1, &mut db, &builder).unwrap();
100
101 let tx = result.into_inner();
103 assert_eq!(tx.max_fee_per_gas(), 0);
104 assert_eq!(tx.max_priority_fee_per_gas(), Some(0));
105 assert_eq!(tx.gas_price(), None);
106 }
107
108 #[test]
109 fn test_resolve_transaction_legacy() {
110 let mut db = CacheDB::<reth_revm::db::EmptyDBTyped<reth_errors::ProviderError>>::default();
111 let builder = EthTxBuilder::default();
112
113 let tx = TransactionRequest { gas_price: Some(100), ..Default::default() };
114
115 let tx = resolve_transaction(tx, 21000, 0, 1, &mut db, &builder).unwrap();
116
117 assert_eq!(tx.tx_type(), TxType::Legacy);
118
119 let tx = tx.into_inner();
120 assert_eq!(tx.gas_price(), Some(100));
121 assert_eq!(tx.max_priority_fee_per_gas(), None);
122 }
123
124 #[test]
125 fn test_resolve_transaction_partial_eip1559() {
126 let mut db = CacheDB::<reth_revm::db::EmptyDBTyped<reth_errors::ProviderError>>::default();
127 let builder = EthTxBuilder::default();
128
129 let tx = TransactionRequest {
130 max_fee_per_gas: Some(200),
131 max_priority_fee_per_gas: Some(10),
132 ..Default::default()
133 };
134
135 let result = resolve_transaction(tx, 21000, 0, 1, &mut db, &builder).unwrap();
136
137 assert_eq!(result.tx_type(), TxType::Eip1559);
138 let tx = result.into_inner();
139 assert_eq!(tx.max_fee_per_gas(), 200);
140 assert_eq!(tx.max_priority_fee_per_gas(), Some(10));
141 assert_eq!(tx.gas_price(), None);
142 }
143}