reth_optimism_rpc/eth/
transaction.rs1use crate::{OpEthApi, OpEthApiError, SequencerClient};
4use alloy_primitives::{Bytes, B256};
5use alloy_rpc_types_eth::TransactionInfo;
6use op_alloy_consensus::{transaction::OpTransactionInfo, OpTransaction};
7use reth_optimism_primitives::DepositReceipt;
8use reth_primitives_traits::SignedTransaction;
9use reth_rpc_eth_api::{
10 helpers::{spec::SignersForRpc, EthTransactions, LoadTransaction},
11 try_into_op_tx_info, FromEthApiError, RpcConvert, RpcNodeCore, TxInfoMapper,
12};
13use reth_rpc_eth_types::utils::recover_raw_transaction;
14use reth_storage_api::{errors::ProviderError, ReceiptProvider};
15use reth_transaction_pool::{
16 AddedTransactionOutcome, PoolTransaction, TransactionOrigin, TransactionPool,
17};
18use std::fmt::{Debug, Formatter};
19
20impl<N, Rpc> EthTransactions for OpEthApi<N, Rpc>
21where
22 N: RpcNodeCore,
23 Rpc: RpcConvert<Primitives = N::Primitives, Error = OpEthApiError>,
24{
25 fn signers(&self) -> &SignersForRpc<Self::Provider, Self::NetworkTypes> {
26 self.inner.eth_api.signers()
27 }
28
29 async fn send_raw_transaction(&self, tx: Bytes) -> Result<B256, Self::Error> {
33 let recovered = recover_raw_transaction(&tx)?;
34
35 self.eth_api().broadcast_raw_transaction(tx.clone());
37
38 let pool_transaction = <Self::Pool as TransactionPool>::Transaction::from_pooled(recovered);
39
40 if let Some(client) = self.raw_tx_forwarder().as_ref() {
43 tracing::debug!(target: "rpc::eth", hash = %pool_transaction.hash(), "forwarding raw transaction to sequencer");
44 let hash = client.forward_raw_transaction(&tx).await.inspect_err(|err| {
45 tracing::debug!(target: "rpc::eth", %err, hash=% *pool_transaction.hash(), "failed to forward raw transaction");
46 })?;
47
48 let _ = self.inner.eth_api.add_pool_transaction(pool_transaction).await.inspect_err(|err| {
50 tracing::warn!(target: "rpc::eth", %err, %hash, "successfully sent tx to sequencer, but failed to persist in local tx pool");
51 });
52
53 return Ok(hash)
54 }
55
56 let AddedTransactionOutcome { hash, .. } = self
58 .pool()
59 .add_transaction(TransactionOrigin::Local, pool_transaction)
60 .await
61 .map_err(Self::Error::from_eth_err)?;
62
63 Ok(hash)
64 }
65}
66
67impl<N, Rpc> LoadTransaction for OpEthApi<N, Rpc>
68where
69 N: RpcNodeCore,
70 Rpc: RpcConvert<Primitives = N::Primitives, Error = OpEthApiError>,
71{
72}
73
74impl<N, Rpc> OpEthApi<N, Rpc>
75where
76 N: RpcNodeCore,
77 Rpc: RpcConvert<Primitives = N::Primitives>,
78{
79 pub fn raw_tx_forwarder(&self) -> Option<SequencerClient> {
81 self.inner.sequencer_client.clone()
82 }
83}
84
85pub struct OpTxInfoMapper<Provider> {
90 provider: Provider,
91}
92
93impl<Provider: Clone> Clone for OpTxInfoMapper<Provider> {
94 fn clone(&self) -> Self {
95 Self { provider: self.provider.clone() }
96 }
97}
98
99impl<Provider> Debug for OpTxInfoMapper<Provider> {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 f.debug_struct("OpTxInfoMapper").finish()
102 }
103}
104
105impl<Provider> OpTxInfoMapper<Provider> {
106 pub const fn new(provider: Provider) -> Self {
108 Self { provider }
109 }
110}
111
112impl<T, Provider> TxInfoMapper<T> for OpTxInfoMapper<Provider>
113where
114 T: OpTransaction + SignedTransaction,
115 Provider: ReceiptProvider<Receipt: DepositReceipt>,
116{
117 type Out = OpTransactionInfo;
118 type Err = ProviderError;
119
120 fn try_map(&self, tx: &T, tx_info: TransactionInfo) -> Result<Self::Out, ProviderError> {
121 try_into_op_tx_info(&self.provider, tx, tx_info)
122 }
123}