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