1use crate::{
3 RpcHeader, RpcReceipt, RpcTransaction, RpcTxReq, RpcTypes, SignableTxRequest, TryIntoTxEnv,
4};
5use alloy_consensus::{
6 error::ValueError, transaction::Recovered, EthereumTxEnvelope, Sealable, TxEip4844,
7};
8use alloy_network::Network;
9use alloy_primitives::{Address, U256};
10use alloy_rpc_types_eth::{request::TransactionRequest, Transaction, TransactionInfo};
11use core::error;
12use dyn_clone::DynClone;
13use reth_evm::{BlockEnvFor, ConfigureEvm, EvmEnvFor, TxEnvFor};
14use reth_primitives_traits::{
15 BlockTy, HeaderTy, NodePrimitives, SealedBlock, SealedHeader, SealedHeaderFor, TransactionMeta,
16 TxTy,
17};
18use std::{convert::Infallible, error::Error, fmt::Debug, marker::PhantomData};
19use thiserror::Error;
20
21#[derive(Debug, Clone)]
23pub struct ConvertReceiptInput<'a, N: NodePrimitives> {
24 pub receipt: N::Receipt,
26 pub tx: Recovered<&'a N::SignedTx>,
28 pub gas_used: u64,
30 pub next_log_index: usize,
32 pub meta: TransactionMeta,
34}
35
36pub trait ReceiptConverter<N: NodePrimitives>: Debug + 'static {
38 type RpcReceipt;
40
41 type Error;
43
44 fn convert_receipts(
47 &self,
48 receipts: Vec<ConvertReceiptInput<'_, N>>,
49 ) -> Result<Vec<Self::RpcReceipt>, Self::Error>;
50
51 fn convert_receipts_with_block(
54 &self,
55 receipts: Vec<ConvertReceiptInput<'_, N>>,
56 _block: &SealedBlock<N::Block>,
57 ) -> Result<Vec<Self::RpcReceipt>, Self::Error> {
58 self.convert_receipts(receipts)
59 }
60}
61
62pub trait HeaderConverter<Consensus, Rpc>: Debug + Send + Sync + Unpin + Clone + 'static {
64 type Err: error::Error;
66
67 fn convert_header(
69 &self,
70 header: SealedHeader<Consensus>,
71 block_size: usize,
72 ) -> Result<Rpc, Self::Err>;
73}
74
75impl<Consensus, Rpc> HeaderConverter<Consensus, Rpc> for ()
78where
79 Rpc: FromConsensusHeader<Consensus>,
80{
81 type Err = Infallible;
82
83 fn convert_header(
84 &self,
85 header: SealedHeader<Consensus>,
86 block_size: usize,
87 ) -> Result<Rpc, Self::Err> {
88 Ok(Rpc::from_consensus_header(header, block_size))
89 }
90}
91
92pub trait FromConsensusHeader<T> {
94 fn from_consensus_header(header: SealedHeader<T>, block_size: usize) -> Self;
96}
97
98impl<T: Sealable> FromConsensusHeader<T> for alloy_rpc_types_eth::Header<T> {
99 fn from_consensus_header(header: SealedHeader<T>, block_size: usize) -> Self {
100 Self::from_consensus(header.into(), None, Some(U256::from(block_size)))
101 }
102}
103
104#[auto_impl::auto_impl(&, Box, Arc)]
113pub trait RpcConvert: Send + Sync + Unpin + Debug + DynClone + 'static {
114 type Primitives: NodePrimitives;
116
117 type Evm: ConfigureEvm<Primitives = Self::Primitives>;
119
120 type Network: RpcTypes<TransactionRequest: SignableTxRequest<TxTy<Self::Primitives>>>;
123
124 type Error: error::Error + Into<jsonrpsee_types::ErrorObject<'static>>;
126
127 fn fill_pending(
131 &self,
132 tx: Recovered<TxTy<Self::Primitives>>,
133 ) -> Result<RpcTransaction<Self::Network>, Self::Error> {
134 self.fill(tx, TransactionInfo::default())
135 }
136
137 fn fill(
143 &self,
144 tx: Recovered<TxTy<Self::Primitives>>,
145 tx_info: TransactionInfo,
146 ) -> Result<RpcTransaction<Self::Network>, Self::Error>;
147
148 fn build_simulate_v1_transaction(
151 &self,
152 request: RpcTxReq<Self::Network>,
153 ) -> Result<TxTy<Self::Primitives>, Self::Error>;
154
155 fn tx_env(
158 &self,
159 request: RpcTxReq<Self::Network>,
160 evm_env: &EvmEnvFor<Self::Evm>,
161 ) -> Result<TxEnvFor<Self::Evm>, Self::Error>;
162
163 fn convert_receipts(
166 &self,
167 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
168 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error>;
169
170 fn convert_receipts_with_block(
175 &self,
176 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
177 block: &SealedBlock<BlockTy<Self::Primitives>>,
178 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error>;
179
180 fn convert_header(
182 &self,
183 header: SealedHeaderFor<Self::Primitives>,
184 block_size: usize,
185 ) -> Result<RpcHeader<Self::Network>, Self::Error>;
186}
187
188dyn_clone::clone_trait_object!(
189 <Primitives, Network, Error, Evm>
190 RpcConvert<Primitives = Primitives, Network = Network, Error = Error, Evm = Evm>
191);
192
193pub trait IntoRpcTx<T> {
205 type TxInfo;
208 type Err: error::Error;
210
211 fn into_rpc_tx(self, signer: Address, tx_info: Self::TxInfo) -> Result<T, Self::Err>;
214}
215
216pub trait FromConsensusTx<T>: Sized {
228 type TxInfo;
231 type Err: error::Error;
233
234 fn from_consensus_tx(tx: T, signer: Address, tx_info: Self::TxInfo) -> Result<Self, Self::Err>;
237}
238
239impl<TxIn: alloy_consensus::Transaction, T: alloy_consensus::Transaction + From<TxIn>>
240 FromConsensusTx<TxIn> for Transaction<T>
241{
242 type TxInfo = TransactionInfo;
243 type Err = Infallible;
244
245 fn from_consensus_tx(
246 tx: TxIn,
247 signer: Address,
248 tx_info: Self::TxInfo,
249 ) -> Result<Self, Self::Err> {
250 Ok(Self::from_transaction(Recovered::new_unchecked(tx.into(), signer), tx_info))
251 }
252}
253
254impl<ConsensusTx, RpcTx> IntoRpcTx<RpcTx> for ConsensusTx
255where
256 ConsensusTx: alloy_consensus::Transaction,
257 RpcTx: FromConsensusTx<Self>,
258 <RpcTx as FromConsensusTx<ConsensusTx>>::Err: Debug,
259{
260 type TxInfo = RpcTx::TxInfo;
261 type Err = <RpcTx as FromConsensusTx<ConsensusTx>>::Err;
262
263 fn into_rpc_tx(self, signer: Address, tx_info: Self::TxInfo) -> Result<RpcTx, Self::Err> {
264 RpcTx::from_consensus_tx(self, signer, tx_info)
265 }
266}
267
268pub trait RpcTxConverter<Tx, RpcTx, TxInfo>: Clone + Debug + Unpin + Send + Sync + 'static {
286 type Err;
288
289 fn convert_rpc_tx(&self, tx: Tx, signer: Address, tx_info: TxInfo) -> Result<RpcTx, Self::Err>;
293}
294
295impl<Tx, RpcTx> RpcTxConverter<Tx, RpcTx, Tx::TxInfo> for ()
296where
297 Tx: IntoRpcTx<RpcTx>,
298{
299 type Err = Tx::Err;
300
301 fn convert_rpc_tx(
302 &self,
303 tx: Tx,
304 signer: Address,
305 tx_info: Tx::TxInfo,
306 ) -> Result<RpcTx, Self::Err> {
307 tx.into_rpc_tx(signer, tx_info)
308 }
309}
310
311impl<Tx, RpcTx, F, TxInfo, E> RpcTxConverter<Tx, RpcTx, TxInfo> for F
312where
313 F: Fn(Tx, Address, TxInfo) -> Result<RpcTx, E> + Clone + Debug + Unpin + Send + Sync + 'static,
314{
315 type Err = E;
316
317 fn convert_rpc_tx(&self, tx: Tx, signer: Address, tx_info: TxInfo) -> Result<RpcTx, Self::Err> {
318 self(tx, signer, tx_info)
319 }
320}
321
322pub trait SimTxConverter<TxReq, SimTx>: Clone + Debug + Unpin + Send + Sync + 'static {
338 type Err: Error;
340
341 fn convert_sim_tx(&self, tx_req: TxReq) -> Result<SimTx, Self::Err>;
345}
346
347impl<TxReq, SimTx> SimTxConverter<TxReq, SimTx> for ()
348where
349 TxReq: TryIntoSimTx<SimTx> + Debug,
350{
351 type Err = ValueError<TxReq>;
352
353 fn convert_sim_tx(&self, tx_req: TxReq) -> Result<SimTx, Self::Err> {
354 tx_req.try_into_sim_tx()
355 }
356}
357
358impl<TxReq, SimTx, F, E> SimTxConverter<TxReq, SimTx> for F
359where
360 TxReq: Debug,
361 E: Error,
362 F: Fn(TxReq) -> Result<SimTx, E> + Clone + Debug + Unpin + Send + Sync + 'static,
363{
364 type Err = E;
365
366 fn convert_sim_tx(&self, tx_req: TxReq) -> Result<SimTx, Self::Err> {
367 self(tx_req)
368 }
369}
370
371pub trait TryIntoSimTx<T>
375where
376 Self: Sized,
377{
378 fn try_into_sim_tx(self) -> Result<T, ValueError<Self>>;
386}
387
388pub trait TxInfoMapper<T> {
390 type Out;
392 type Err;
394
395 fn try_map(&self, tx: &T, tx_info: TransactionInfo) -> Result<Self::Out, Self::Err>;
397}
398
399impl<T> TxInfoMapper<T> for () {
400 type Out = TransactionInfo;
401 type Err = Infallible;
402
403 fn try_map(&self, _tx: &T, tx_info: TransactionInfo) -> Result<Self::Out, Self::Err> {
404 Ok(tx_info)
405 }
406}
407
408impl TryIntoSimTx<EthereumTxEnvelope<TxEip4844>> for TransactionRequest {
409 fn try_into_sim_tx(self) -> Result<EthereumTxEnvelope<TxEip4844>, ValueError<Self>> {
410 Self::build_typed_simulate_transaction(self)
411 }
412}
413
414pub trait TxEnvConverter<TxReq, Evm: ConfigureEvm>:
430 Debug + Send + Sync + Unpin + Clone + 'static
431{
432 type Error;
434
435 fn convert_tx_env(
439 &self,
440 tx_req: TxReq,
441 evm_env: &EvmEnvFor<Evm>,
442 ) -> Result<TxEnvFor<Evm>, Self::Error>;
443}
444
445impl<TxReq, Evm> TxEnvConverter<TxReq, Evm> for ()
446where
447 TxReq: TryIntoTxEnv<TxEnvFor<Evm>, BlockEnvFor<Evm>>,
448 Evm: ConfigureEvm,
449{
450 type Error = TxReq::Err;
451
452 fn convert_tx_env(
453 &self,
454 tx_req: TxReq,
455 evm_env: &EvmEnvFor<Evm>,
456 ) -> Result<TxEnvFor<Evm>, Self::Error> {
457 tx_req.try_into_tx_env(evm_env)
458 }
459}
460
461impl<F, TxReq, E, Evm> TxEnvConverter<TxReq, Evm> for F
463where
464 F: Fn(TxReq, &EvmEnvFor<Evm>) -> Result<TxEnvFor<Evm>, E>
465 + Debug
466 + Send
467 + Sync
468 + Unpin
469 + Clone
470 + 'static,
471 TxReq: Clone,
472 Evm: ConfigureEvm,
473 E: error::Error + Send + Sync + 'static,
474{
475 type Error = E;
476
477 fn convert_tx_env(
478 &self,
479 tx_req: TxReq,
480 evm_env: &EvmEnvFor<Evm>,
481 ) -> Result<TxEnvFor<Evm>, Self::Error> {
482 self(tx_req, evm_env)
483 }
484}
485
486#[derive(Debug, Clone, Error)]
488#[error("Failed to convert transaction into RPC response: {0}")]
489pub struct TransactionConversionError(String);
490
491#[derive(Debug)]
507pub struct RpcConverter<
508 Network,
509 Evm,
510 Receipt,
511 Header = (),
512 Map = (),
513 SimTx = (),
514 RpcTx = (),
515 TxEnv = (),
516> {
517 network: PhantomData<Network>,
518 evm: PhantomData<Evm>,
519 receipt_converter: Receipt,
520 header_converter: Header,
521 mapper: Map,
522 tx_env_converter: TxEnv,
523 sim_tx_converter: SimTx,
524 rpc_tx_converter: RpcTx,
525}
526
527impl<Network, Evm, Receipt> RpcConverter<Network, Evm, Receipt> {
528 pub const fn new(receipt_converter: Receipt) -> Self {
530 Self {
531 network: PhantomData,
532 evm: PhantomData,
533 receipt_converter,
534 header_converter: (),
535 mapper: (),
536 tx_env_converter: (),
537 sim_tx_converter: (),
538 rpc_tx_converter: (),
539 }
540 }
541}
542
543impl<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
544 RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
545{
546 pub fn with_network<N>(
548 self,
549 ) -> RpcConverter<N, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv> {
550 let Self {
551 receipt_converter,
552 header_converter,
553 mapper,
554 evm,
555 sim_tx_converter,
556 rpc_tx_converter,
557 tx_env_converter,
558 ..
559 } = self;
560 RpcConverter {
561 receipt_converter,
562 header_converter,
563 mapper,
564 network: Default::default(),
565 evm,
566 sim_tx_converter,
567 rpc_tx_converter,
568 tx_env_converter,
569 }
570 }
571
572 pub fn with_tx_env_converter<TxEnvNew>(
574 self,
575 tx_env_converter: TxEnvNew,
576 ) -> RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnvNew> {
577 let Self {
578 receipt_converter,
579 header_converter,
580 mapper,
581 network,
582 evm,
583 sim_tx_converter,
584 rpc_tx_converter,
585 tx_env_converter: _,
586 ..
587 } = self;
588 RpcConverter {
589 receipt_converter,
590 header_converter,
591 mapper,
592 network,
593 evm,
594 sim_tx_converter,
595 rpc_tx_converter,
596 tx_env_converter,
597 }
598 }
599
600 pub fn with_header_converter<HeaderNew>(
602 self,
603 header_converter: HeaderNew,
604 ) -> RpcConverter<Network, Evm, Receipt, HeaderNew, Map, SimTx, RpcTx, TxEnv> {
605 let Self {
606 receipt_converter,
607 header_converter: _,
608 mapper,
609 network,
610 evm,
611 sim_tx_converter,
612 rpc_tx_converter,
613 tx_env_converter,
614 } = self;
615 RpcConverter {
616 receipt_converter,
617 header_converter,
618 mapper,
619 network,
620 evm,
621 sim_tx_converter,
622 rpc_tx_converter,
623 tx_env_converter,
624 }
625 }
626
627 pub fn with_mapper<MapNew>(
629 self,
630 mapper: MapNew,
631 ) -> RpcConverter<Network, Evm, Receipt, Header, MapNew, SimTx, RpcTx, TxEnv> {
632 let Self {
633 receipt_converter,
634 header_converter,
635 mapper: _,
636 network,
637 evm,
638 sim_tx_converter,
639 rpc_tx_converter,
640 tx_env_converter,
641 } = self;
642 RpcConverter {
643 receipt_converter,
644 header_converter,
645 mapper,
646 network,
647 evm,
648 sim_tx_converter,
649 rpc_tx_converter,
650 tx_env_converter,
651 }
652 }
653
654 pub fn with_sim_tx_converter<SimTxNew>(
656 self,
657 sim_tx_converter: SimTxNew,
658 ) -> RpcConverter<Network, Evm, Receipt, Header, Map, SimTxNew, RpcTx, TxEnv> {
659 let Self {
660 receipt_converter,
661 header_converter,
662 mapper,
663 network,
664 evm,
665 rpc_tx_converter,
666 tx_env_converter,
667 ..
668 } = self;
669 RpcConverter {
670 receipt_converter,
671 header_converter,
672 mapper,
673 network,
674 evm,
675 sim_tx_converter,
676 rpc_tx_converter,
677 tx_env_converter,
678 }
679 }
680
681 pub fn with_rpc_tx_converter<RpcTxNew>(
683 self,
684 rpc_tx_converter: RpcTxNew,
685 ) -> RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTxNew, TxEnv> {
686 let Self {
687 receipt_converter,
688 header_converter,
689 mapper,
690 network,
691 evm,
692 sim_tx_converter,
693 tx_env_converter,
694 ..
695 } = self;
696 RpcConverter {
697 receipt_converter,
698 header_converter,
699 mapper,
700 network,
701 evm,
702 sim_tx_converter,
703 rpc_tx_converter,
704 tx_env_converter,
705 }
706 }
707
708 pub fn erased(
710 self,
711 ) -> Box<
712 dyn RpcConvert<
713 Primitives = <Self as RpcConvert>::Primitives,
714 Network = <Self as RpcConvert>::Network,
715 Error = <Self as RpcConvert>::Error,
716 Evm = <Self as RpcConvert>::Evm,
717 >,
718 >
719 where
720 Self: RpcConvert,
721 {
722 Box::new(self)
723 }
724}
725
726impl<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv> Default
727 for RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
728where
729 Receipt: Default,
730 Header: Default,
731 Map: Default,
732 SimTx: Default,
733 RpcTx: Default,
734 TxEnv: Default,
735{
736 fn default() -> Self {
737 Self {
738 network: Default::default(),
739 evm: Default::default(),
740 receipt_converter: Default::default(),
741 header_converter: Default::default(),
742 mapper: Default::default(),
743 sim_tx_converter: Default::default(),
744 rpc_tx_converter: Default::default(),
745 tx_env_converter: Default::default(),
746 }
747 }
748}
749
750impl<
751 Network,
752 Evm,
753 Receipt: Clone,
754 Header: Clone,
755 Map: Clone,
756 SimTx: Clone,
757 RpcTx: Clone,
758 TxEnv: Clone,
759 > Clone for RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
760{
761 fn clone(&self) -> Self {
762 Self {
763 network: Default::default(),
764 evm: Default::default(),
765 receipt_converter: self.receipt_converter.clone(),
766 header_converter: self.header_converter.clone(),
767 mapper: self.mapper.clone(),
768 sim_tx_converter: self.sim_tx_converter.clone(),
769 rpc_tx_converter: self.rpc_tx_converter.clone(),
770 tx_env_converter: self.tx_env_converter.clone(),
771 }
772 }
773}
774
775impl<N, Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv> RpcConvert
776 for RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
777where
778 N: NodePrimitives,
779 Network: RpcTypes<TransactionRequest: SignableTxRequest<N::SignedTx>>,
780 Evm: ConfigureEvm<Primitives = N> + 'static,
781 Receipt: ReceiptConverter<
782 N,
783 RpcReceipt = RpcReceipt<Network>,
784 Error: From<TransactionConversionError>
785 + From<TxEnv::Error>
786 + From<<Map as TxInfoMapper<TxTy<N>>>::Err>
787 + From<RpcTx::Err>
788 + From<Header::Err>
789 + Error
790 + Unpin
791 + Sync
792 + Send
793 + Into<jsonrpsee_types::ErrorObject<'static>>,
794 > + Send
795 + Sync
796 + Unpin
797 + Clone
798 + Debug,
799 Header: HeaderConverter<HeaderTy<N>, RpcHeader<Network>>,
800 Map: TxInfoMapper<TxTy<N>> + Clone + Debug + Unpin + Send + Sync + 'static,
801 SimTx: SimTxConverter<RpcTxReq<Network>, TxTy<N>>,
802 RpcTx:
803 RpcTxConverter<TxTy<N>, Network::TransactionResponse, <Map as TxInfoMapper<TxTy<N>>>::Out>,
804 TxEnv: TxEnvConverter<RpcTxReq<Network>, Evm>,
805{
806 type Primitives = N;
807 type Evm = Evm;
808 type Network = Network;
809 type Error = Receipt::Error;
810
811 fn fill(
812 &self,
813 tx: Recovered<TxTy<N>>,
814 tx_info: TransactionInfo,
815 ) -> Result<Network::TransactionResponse, Self::Error> {
816 let (tx, signer) = tx.into_parts();
817 let tx_info = self.mapper.try_map(&tx, tx_info)?;
818
819 self.rpc_tx_converter.convert_rpc_tx(tx, signer, tx_info).map_err(Into::into)
820 }
821
822 fn build_simulate_v1_transaction(
823 &self,
824 request: RpcTxReq<Network>,
825 ) -> Result<TxTy<N>, Self::Error> {
826 Ok(self
827 .sim_tx_converter
828 .convert_sim_tx(request)
829 .map_err(|e| TransactionConversionError(e.to_string()))?)
830 }
831
832 fn tx_env(
833 &self,
834 request: RpcTxReq<Network>,
835 evm_env: &EvmEnvFor<Evm>,
836 ) -> Result<TxEnvFor<Evm>, Self::Error> {
837 self.tx_env_converter.convert_tx_env(request, evm_env).map_err(Into::into)
838 }
839
840 fn convert_receipts(
841 &self,
842 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
843 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error> {
844 self.receipt_converter.convert_receipts(receipts)
845 }
846
847 fn convert_receipts_with_block(
848 &self,
849 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
850 block: &SealedBlock<BlockTy<Self::Primitives>>,
851 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error> {
852 self.receipt_converter.convert_receipts_with_block(receipts, block)
853 }
854
855 fn convert_header(
856 &self,
857 header: SealedHeaderFor<Self::Primitives>,
858 block_size: usize,
859 ) -> Result<RpcHeader<Self::Network>, Self::Error> {
860 Ok(self.header_converter.convert_header(header, block_size)?)
861 }
862}
863
864#[cfg(feature = "op")]
866pub mod op {
867 use super::*;
868 use alloy_consensus::SignableTransaction;
869 use alloy_signer::Signature;
870 use op_alloy_consensus::{
871 transaction::{OpDepositInfo, OpTransactionInfo},
872 OpTxEnvelope,
873 };
874 use op_alloy_rpc_types::OpTransactionRequest;
875 use reth_optimism_primitives::DepositReceipt;
876 use reth_primitives_traits::SignedTransaction;
877 use reth_storage_api::{errors::ProviderError, ReceiptProvider};
878
879 pub fn try_into_op_tx_info<Tx, T>(
882 provider: &T,
883 tx: &Tx,
884 tx_info: TransactionInfo,
885 ) -> Result<OpTransactionInfo, ProviderError>
886 where
887 Tx: op_alloy_consensus::OpTransaction + SignedTransaction,
888 T: ReceiptProvider<Receipt: DepositReceipt>,
889 {
890 let deposit_meta = if tx.is_deposit() {
891 provider.receipt_by_hash(*tx.tx_hash())?.and_then(|receipt| {
892 receipt.as_deposit_receipt().map(|receipt| OpDepositInfo {
893 deposit_receipt_version: receipt.deposit_receipt_version,
894 deposit_nonce: receipt.deposit_nonce,
895 })
896 })
897 } else {
898 None
899 }
900 .unwrap_or_default();
901
902 Ok(OpTransactionInfo::new(tx_info, deposit_meta))
903 }
904
905 impl<T: op_alloy_consensus::OpTransaction + alloy_consensus::Transaction> FromConsensusTx<T>
906 for op_alloy_rpc_types::Transaction<T>
907 {
908 type TxInfo = OpTransactionInfo;
909 type Err = Infallible;
910
911 fn from_consensus_tx(
912 tx: T,
913 signer: Address,
914 tx_info: Self::TxInfo,
915 ) -> Result<Self, Self::Err> {
916 Ok(Self::from_transaction(Recovered::new_unchecked(tx, signer), tx_info))
917 }
918 }
919
920 impl TryIntoSimTx<OpTxEnvelope> for OpTransactionRequest {
921 fn try_into_sim_tx(self) -> Result<OpTxEnvelope, ValueError<Self>> {
922 let tx = self
923 .build_typed_tx()
924 .map_err(|request| ValueError::new(request, "Required fields missing"))?;
925
926 let signature = Signature::new(Default::default(), Default::default(), false);
928
929 Ok(tx.into_signed(signature).into())
930 }
931 }
932}
933
934pub trait TryFromTransactionResponse<N: Network> {
936 type Error: core::error::Error + Send + Sync + Unpin;
938
939 fn from_transaction_response(
945 transaction_response: N::TransactionResponse,
946 ) -> Result<Self, Self::Error>
947 where
948 Self: Sized;
949}
950
951impl TryFromTransactionResponse<alloy_network::Ethereum>
952 for reth_ethereum_primitives::TransactionSigned
953{
954 type Error = Infallible;
955
956 fn from_transaction_response(transaction_response: Transaction) -> Result<Self, Self::Error> {
957 Ok(transaction_response.into_inner().into())
958 }
959}
960
961#[cfg(feature = "op")]
962impl TryFromTransactionResponse<op_alloy_network::Optimism>
963 for reth_optimism_primitives::OpTransactionSigned
964{
965 type Error = Infallible;
966
967 fn from_transaction_response(
968 transaction_response: op_alloy_rpc_types::Transaction,
969 ) -> Result<Self, Self::Error> {
970 Ok(transaction_response.inner.into_inner())
971 }
972}
973
974#[cfg(test)]
975mod transaction_response_tests {
976 use super::*;
977 use alloy_consensus::{transaction::Recovered, EthereumTxEnvelope, Signed, TxLegacy};
978 use alloy_network::Ethereum;
979 use alloy_primitives::{Address, Signature, B256, U256};
980 use alloy_rpc_types_eth::Transaction;
981
982 #[test]
983 fn test_ethereum_transaction_conversion() {
984 let signed_tx = Signed::new_unchecked(
985 TxLegacy::default(),
986 Signature::new(U256::ONE, U256::ONE, false),
987 B256::ZERO,
988 );
989 let envelope = EthereumTxEnvelope::Legacy(signed_tx);
990
991 let tx_response = Transaction {
992 inner: Recovered::new_unchecked(envelope, Address::ZERO),
993 block_hash: None,
994 block_number: None,
995 transaction_index: None,
996 effective_gas_price: None,
997 };
998
999 let result = <reth_ethereum_primitives::TransactionSigned as TryFromTransactionResponse<
1000 Ethereum,
1001 >>::from_transaction_response(tx_response);
1002 assert!(result.is_ok());
1003 }
1004
1005 #[cfg(feature = "op")]
1006 mod op {
1007 use super::*;
1008
1009 #[test]
1010 fn test_optimism_transaction_conversion() {
1011 use op_alloy_consensus::OpTxEnvelope;
1012 use op_alloy_network::Optimism;
1013 use reth_optimism_primitives::OpTransactionSigned;
1014
1015 let signed_tx = Signed::new_unchecked(
1016 TxLegacy::default(),
1017 Signature::new(U256::ONE, U256::ONE, false),
1018 B256::ZERO,
1019 );
1020 let envelope = OpTxEnvelope::Legacy(signed_tx);
1021
1022 let inner_tx = Transaction {
1023 inner: Recovered::new_unchecked(envelope, Address::ZERO),
1024 block_hash: None,
1025 block_number: None,
1026 transaction_index: None,
1027 effective_gas_price: None,
1028 };
1029
1030 let tx_response = op_alloy_rpc_types::Transaction {
1031 inner: inner_tx,
1032 deposit_nonce: None,
1033 deposit_receipt_version: None,
1034 };
1035
1036 let result = <OpTransactionSigned as TryFromTransactionResponse<Optimism>>::from_transaction_response(tx_response);
1037
1038 assert!(result.is_ok());
1039 }
1040 }
1041}