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::{transaction::OpTransactionInfo, OpTxEnvelope};
876 use op_alloy_rpc_types::OpTransactionRequest;
877
878 impl<T: op_alloy_consensus::OpTransaction + alloy_consensus::Transaction> FromConsensusTx<T>
879 for op_alloy_rpc_types::Transaction<T>
880 {
881 type TxInfo = OpTransactionInfo;
882 type Err = Infallible;
883
884 fn from_consensus_tx(
885 tx: T,
886 signer: Address,
887 tx_info: Self::TxInfo,
888 ) -> Result<Self, Self::Err> {
889 Ok(Self::from_transaction(Recovered::new_unchecked(tx, signer), tx_info))
890 }
891 }
892
893 impl TryIntoSimTx<OpTxEnvelope> for OpTransactionRequest {
894 fn try_into_sim_tx(self) -> Result<OpTxEnvelope, ValueError<Self>> {
895 let tx = self
896 .build_typed_tx()
897 .map_err(|request| ValueError::new(request, "Required fields missing"))?;
898
899 let signature = Signature::new(Default::default(), Default::default(), false);
901
902 Ok(tx.into_signed(signature).into())
903 }
904 }
905}
906
907pub trait TryFromTransactionResponse<N: Network> {
909 type Error: core::error::Error + Send + Sync + Unpin;
911
912 fn from_transaction_response(
918 transaction_response: N::TransactionResponse,
919 ) -> Result<Self, Self::Error>
920 where
921 Self: Sized;
922}
923
924impl TryFromTransactionResponse<alloy_network::Ethereum>
925 for reth_ethereum_primitives::TransactionSigned
926{
927 type Error = Infallible;
928
929 fn from_transaction_response(transaction_response: Transaction) -> Result<Self, Self::Error> {
930 Ok(transaction_response.into_inner().into())
931 }
932}
933
934#[cfg(feature = "op")]
935impl TryFromTransactionResponse<op_alloy_network::Optimism> for op_alloy_consensus::OpTxEnvelope {
936 type Error = Infallible;
937
938 fn from_transaction_response(
939 transaction_response: op_alloy_rpc_types::Transaction,
940 ) -> Result<Self, Self::Error> {
941 Ok(transaction_response.inner.into_inner())
942 }
943}
944
945#[cfg(test)]
946mod transaction_response_tests {
947 use super::*;
948 use alloy_consensus::{transaction::Recovered, EthereumTxEnvelope, Signed, TxLegacy};
949 use alloy_network::Ethereum;
950 use alloy_primitives::{Address, Signature, B256, U256};
951 use alloy_rpc_types_eth::Transaction;
952
953 #[test]
954 fn test_ethereum_transaction_conversion() {
955 let signed_tx = Signed::new_unchecked(
956 TxLegacy::default(),
957 Signature::new(U256::ONE, U256::ONE, false),
958 B256::ZERO,
959 );
960 let envelope = EthereumTxEnvelope::Legacy(signed_tx);
961
962 let tx_response = Transaction {
963 inner: Recovered::new_unchecked(envelope, Address::ZERO),
964 block_hash: None,
965 block_number: None,
966 transaction_index: None,
967 effective_gas_price: None,
968 };
969
970 let result = <reth_ethereum_primitives::TransactionSigned as TryFromTransactionResponse<
971 Ethereum,
972 >>::from_transaction_response(tx_response);
973 assert!(result.is_ok());
974 }
975
976 #[cfg(feature = "op")]
977 mod op {
978 use super::*;
979
980 #[test]
981 fn test_optimism_transaction_conversion() {
982 use op_alloy_consensus::OpTxEnvelope;
983 use op_alloy_network::Optimism;
984
985 let signed_tx = Signed::new_unchecked(
986 TxLegacy::default(),
987 Signature::new(U256::ONE, U256::ONE, false),
988 B256::ZERO,
989 );
990 let envelope = OpTxEnvelope::Legacy(signed_tx);
991
992 let inner_tx = Transaction {
993 inner: Recovered::new_unchecked(envelope, Address::ZERO),
994 block_hash: None,
995 block_number: None,
996 transaction_index: None,
997 effective_gas_price: None,
998 };
999
1000 let tx_response = op_alloy_rpc_types::Transaction {
1001 inner: inner_tx,
1002 deposit_nonce: None,
1003 deposit_receipt_version: None,
1004 };
1005
1006 let result =
1007 <OpTxEnvelope as TryFromTransactionResponse<Optimism>>::from_transaction_response(
1008 tx_response,
1009 );
1010
1011 assert!(result.is_ok());
1012 }
1013 }
1014}