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_primitives::{Address, U256};
9use alloy_rpc_types_eth::{request::TransactionRequest, Transaction, TransactionInfo};
10use core::error;
11use dyn_clone::DynClone;
12use reth_evm::{BlockEnvFor, ConfigureEvm, EvmEnvFor, SpecFor, TxEnvFor};
13use reth_primitives_traits::{
14 BlockTy, HeaderTy, NodePrimitives, SealedBlock, SealedHeader, SealedHeaderFor, TransactionMeta,
15 TxTy,
16};
17use std::{convert::Infallible, error::Error, fmt::Debug, marker::PhantomData};
18
19#[derive(Debug, Clone)]
21pub struct ConvertReceiptInput<'a, N: NodePrimitives> {
22 pub receipt: N::Receipt,
24 pub tx: Recovered<&'a N::SignedTx>,
26 pub gas_used: u64,
28 pub next_log_index: usize,
30 pub meta: TransactionMeta,
32}
33
34pub trait ReceiptConverter<N: NodePrimitives>: Debug + 'static {
36 type RpcReceipt;
38
39 type Error;
41
42 fn convert_receipts(
45 &self,
46 receipts: Vec<ConvertReceiptInput<'_, N>>,
47 ) -> Result<Vec<Self::RpcReceipt>, Self::Error>;
48
49 fn convert_receipts_with_block(
52 &self,
53 receipts: Vec<ConvertReceiptInput<'_, N>>,
54 _block: &SealedBlock<N::Block>,
55 ) -> Result<Vec<Self::RpcReceipt>, Self::Error> {
56 self.convert_receipts(receipts)
57 }
58}
59
60pub trait HeaderConverter<Consensus, Rpc>: Debug + Send + Sync + Unpin + Clone + 'static {
62 type Err: error::Error;
64
65 fn convert_header(
67 &self,
68 header: SealedHeader<Consensus>,
69 block_size: usize,
70 ) -> Result<Rpc, Self::Err>;
71}
72
73impl<Consensus, Rpc> HeaderConverter<Consensus, Rpc> for ()
76where
77 Rpc: FromConsensusHeader<Consensus>,
78{
79 type Err = Infallible;
80
81 fn convert_header(
82 &self,
83 header: SealedHeader<Consensus>,
84 block_size: usize,
85 ) -> Result<Rpc, Self::Err> {
86 Ok(Rpc::from_consensus_header(header, block_size))
87 }
88}
89
90pub trait FromConsensusHeader<T> {
92 fn from_consensus_header(header: SealedHeader<T>, block_size: usize) -> Self;
94}
95
96impl<T: Sealable> FromConsensusHeader<T> for alloy_rpc_types_eth::Header<T> {
97 fn from_consensus_header(header: SealedHeader<T>, block_size: usize) -> Self {
98 Self::from_consensus(header.into(), None, Some(U256::from(block_size)))
99 }
100}
101
102#[auto_impl::auto_impl(&, Box, Arc)]
111pub trait RpcConvert: Send + Sync + Unpin + Debug + DynClone + 'static {
112 type Primitives: NodePrimitives;
114
115 type Evm: ConfigureEvm<Primitives = Self::Primitives>;
117
118 type Network: RpcTypes<TransactionRequest: SignableTxRequest<TxTy<Self::Primitives>>>;
121
122 type Error: error::Error + Into<jsonrpsee_types::ErrorObject<'static>>;
124
125 fn fill_pending(
129 &self,
130 tx: Recovered<TxTy<Self::Primitives>>,
131 ) -> Result<RpcTransaction<Self::Network>, Self::Error> {
132 self.fill(tx, TransactionInfo::default())
133 }
134
135 fn fill(
141 &self,
142 tx: Recovered<TxTy<Self::Primitives>>,
143 tx_info: TransactionInfo,
144 ) -> Result<RpcTransaction<Self::Network>, Self::Error>;
145
146 fn build_simulate_v1_transaction(
149 &self,
150 request: RpcTxReq<Self::Network>,
151 ) -> Result<TxTy<Self::Primitives>, Self::Error>;
152
153 fn tx_env(
156 &self,
157 request: RpcTxReq<Self::Network>,
158 evm_env: &EvmEnvFor<Self::Evm>,
159 ) -> Result<TxEnvFor<Self::Evm>, Self::Error>;
160
161 fn convert_receipts(
164 &self,
165 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
166 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error>;
167
168 fn convert_receipts_with_block(
173 &self,
174 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
175 block: &SealedBlock<BlockTy<Self::Primitives>>,
176 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error>;
177
178 fn convert_header(
180 &self,
181 header: SealedHeaderFor<Self::Primitives>,
182 block_size: usize,
183 ) -> Result<RpcHeader<Self::Network>, Self::Error>;
184}
185
186dyn_clone::clone_trait_object!(
187 <Primitives, Network, Error, Evm>
188 RpcConvert<Primitives = Primitives, Network = Network, Error = Error, Evm = Evm>
189);
190
191pub trait IntoRpcTx<T> {
203 type TxInfo;
206 type Err: error::Error;
208
209 fn into_rpc_tx(self, signer: Address, tx_info: Self::TxInfo) -> Result<T, Self::Err>;
212}
213
214pub trait FromConsensusTx<T>: Sized {
226 type TxInfo;
229 type Err: error::Error;
231
232 fn from_consensus_tx(tx: T, signer: Address, tx_info: Self::TxInfo) -> Result<Self, Self::Err>;
235}
236
237impl<TxIn: alloy_consensus::Transaction, T: alloy_consensus::Transaction + From<TxIn>>
238 FromConsensusTx<TxIn> for Transaction<T>
239{
240 type TxInfo = TransactionInfo;
241 type Err = Infallible;
242
243 fn from_consensus_tx(
244 tx: TxIn,
245 signer: Address,
246 tx_info: Self::TxInfo,
247 ) -> Result<Self, Self::Err> {
248 Ok(Self::from_transaction(Recovered::new_unchecked(tx.into(), signer), tx_info))
249 }
250}
251
252impl<ConsensusTx, RpcTx> IntoRpcTx<RpcTx> for ConsensusTx
253where
254 ConsensusTx: alloy_consensus::Transaction,
255 RpcTx: FromConsensusTx<Self>,
256 <RpcTx as FromConsensusTx<ConsensusTx>>::Err: Debug,
257{
258 type TxInfo = RpcTx::TxInfo;
259 type Err = <RpcTx as FromConsensusTx<ConsensusTx>>::Err;
260
261 fn into_rpc_tx(self, signer: Address, tx_info: Self::TxInfo) -> Result<RpcTx, Self::Err> {
262 RpcTx::from_consensus_tx(self, signer, tx_info)
263 }
264}
265
266pub trait RpcTxConverter<Tx, RpcTx, TxInfo>: Clone + Debug + Unpin + Send + Sync + 'static {
284 type Err;
286
287 fn convert_rpc_tx(&self, tx: Tx, signer: Address, tx_info: TxInfo) -> Result<RpcTx, Self::Err>;
291}
292
293impl<Tx, RpcTx> RpcTxConverter<Tx, RpcTx, Tx::TxInfo> for ()
294where
295 Tx: IntoRpcTx<RpcTx>,
296{
297 type Err = Tx::Err;
298
299 fn convert_rpc_tx(
300 &self,
301 tx: Tx,
302 signer: Address,
303 tx_info: Tx::TxInfo,
304 ) -> Result<RpcTx, Self::Err> {
305 tx.into_rpc_tx(signer, tx_info)
306 }
307}
308
309impl<Tx, RpcTx, F, TxInfo, E> RpcTxConverter<Tx, RpcTx, TxInfo> for F
310where
311 F: Fn(Tx, Address, TxInfo) -> Result<RpcTx, E> + Clone + Debug + Unpin + Send + Sync + 'static,
312{
313 type Err = E;
314
315 fn convert_rpc_tx(&self, tx: Tx, signer: Address, tx_info: TxInfo) -> Result<RpcTx, Self::Err> {
316 self(tx, signer, tx_info)
317 }
318}
319
320pub trait SimTxConverter<TxReq, SimTx>: Clone + Debug + Unpin + Send + Sync + 'static {
336 type Err: Error;
338
339 fn convert_sim_tx(&self, tx_req: TxReq) -> Result<SimTx, Self::Err>;
343}
344
345impl<TxReq, SimTx> SimTxConverter<TxReq, SimTx> for ()
346where
347 TxReq: TryIntoSimTx<SimTx> + Debug,
348{
349 type Err = ValueError<TxReq>;
350
351 fn convert_sim_tx(&self, tx_req: TxReq) -> Result<SimTx, Self::Err> {
352 tx_req.try_into_sim_tx()
353 }
354}
355
356impl<TxReq, SimTx, F, E> SimTxConverter<TxReq, SimTx> for F
357where
358 TxReq: Debug,
359 E: Error,
360 F: Fn(TxReq) -> Result<SimTx, E> + Clone + Debug + Unpin + Send + Sync + 'static,
361{
362 type Err = E;
363
364 fn convert_sim_tx(&self, tx_req: TxReq) -> Result<SimTx, Self::Err> {
365 self(tx_req)
366 }
367}
368
369pub trait TryIntoSimTx<T>
373where
374 Self: Sized,
375{
376 fn try_into_sim_tx(self) -> Result<T, ValueError<Self>>;
384}
385
386pub trait TxInfoMapper<T> {
388 type Out;
390 type Err;
392
393 fn try_map(&self, tx: &T, tx_info: TransactionInfo) -> Result<Self::Out, Self::Err>;
395}
396
397impl<T> TxInfoMapper<T> for () {
398 type Out = TransactionInfo;
399 type Err = Infallible;
400
401 fn try_map(&self, _tx: &T, tx_info: TransactionInfo) -> Result<Self::Out, Self::Err> {
402 Ok(tx_info)
403 }
404}
405
406impl TryIntoSimTx<EthereumTxEnvelope<TxEip4844>> for TransactionRequest {
407 fn try_into_sim_tx(self) -> Result<EthereumTxEnvelope<TxEip4844>, ValueError<Self>> {
408 Self::build_typed_simulate_transaction(self)
409 }
410}
411
412pub trait TxEnvConverter<TxReq, Evm: ConfigureEvm>:
428 Debug + Send + Sync + Unpin + Clone + 'static
429{
430 type Error;
432
433 fn convert_tx_env(
437 &self,
438 tx_req: TxReq,
439 evm_env: &EvmEnvFor<Evm>,
440 ) -> Result<TxEnvFor<Evm>, Self::Error>;
441}
442
443impl<TxReq, Evm> TxEnvConverter<TxReq, Evm> for ()
444where
445 TxReq: TryIntoTxEnv<TxEnvFor<Evm>, SpecFor<Evm>, BlockEnvFor<Evm>>,
446 Evm: ConfigureEvm,
447{
448 type Error = TxReq::Err;
449
450 fn convert_tx_env(
451 &self,
452 tx_req: TxReq,
453 evm_env: &EvmEnvFor<Evm>,
454 ) -> Result<TxEnvFor<Evm>, Self::Error> {
455 tx_req.try_into_tx_env(evm_env)
456 }
457}
458
459impl<F, TxReq, E, Evm> TxEnvConverter<TxReq, Evm> for F
461where
462 F: Fn(TxReq, &EvmEnvFor<Evm>) -> Result<TxEnvFor<Evm>, E>
463 + Debug
464 + Send
465 + Sync
466 + Unpin
467 + Clone
468 + 'static,
469 TxReq: Clone,
470 Evm: ConfigureEvm,
471 E: error::Error + Send + Sync + 'static,
472{
473 type Error = E;
474
475 fn convert_tx_env(
476 &self,
477 tx_req: TxReq,
478 evm_env: &EvmEnvFor<Evm>,
479 ) -> Result<TxEnvFor<Evm>, Self::Error> {
480 self(tx_req, evm_env)
481 }
482}
483
484#[derive(Debug, thiserror::Error)]
486pub enum TransactionConversionError {
487 #[error("Failed to convert transaction into RPC response: {0}")]
489 FromTxReq(String),
490
491 #[error("{0}")]
493 Other(String),
494}
495#[derive(Debug)]
511pub struct RpcConverter<
512 Network,
513 Evm,
514 Receipt,
515 Header = (),
516 Map = (),
517 SimTx = (),
518 RpcTx = (),
519 TxEnv = (),
520> {
521 network: PhantomData<Network>,
522 evm: PhantomData<Evm>,
523 receipt_converter: Receipt,
524 header_converter: Header,
525 mapper: Map,
526 tx_env_converter: TxEnv,
527 sim_tx_converter: SimTx,
528 rpc_tx_converter: RpcTx,
529}
530
531impl<Network, Evm, Receipt> RpcConverter<Network, Evm, Receipt> {
532 pub const fn new(receipt_converter: Receipt) -> Self {
534 Self {
535 network: PhantomData,
536 evm: PhantomData,
537 receipt_converter,
538 header_converter: (),
539 mapper: (),
540 tx_env_converter: (),
541 sim_tx_converter: (),
542 rpc_tx_converter: (),
543 }
544 }
545}
546
547impl<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
548 RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
549{
550 pub fn with_network<N>(
552 self,
553 ) -> RpcConverter<N, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv> {
554 let Self {
555 receipt_converter,
556 header_converter,
557 mapper,
558 evm,
559 sim_tx_converter,
560 rpc_tx_converter,
561 tx_env_converter,
562 ..
563 } = self;
564 RpcConverter {
565 receipt_converter,
566 header_converter,
567 mapper,
568 network: Default::default(),
569 evm,
570 sim_tx_converter,
571 rpc_tx_converter,
572 tx_env_converter,
573 }
574 }
575
576 pub fn with_tx_env_converter<TxEnvNew>(
578 self,
579 tx_env_converter: TxEnvNew,
580 ) -> RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnvNew> {
581 let Self {
582 receipt_converter,
583 header_converter,
584 mapper,
585 network,
586 evm,
587 sim_tx_converter,
588 rpc_tx_converter,
589 tx_env_converter: _,
590 ..
591 } = self;
592 RpcConverter {
593 receipt_converter,
594 header_converter,
595 mapper,
596 network,
597 evm,
598 sim_tx_converter,
599 rpc_tx_converter,
600 tx_env_converter,
601 }
602 }
603
604 pub fn with_header_converter<HeaderNew>(
606 self,
607 header_converter: HeaderNew,
608 ) -> RpcConverter<Network, Evm, Receipt, HeaderNew, Map, SimTx, RpcTx, TxEnv> {
609 let Self {
610 receipt_converter,
611 header_converter: _,
612 mapper,
613 network,
614 evm,
615 sim_tx_converter,
616 rpc_tx_converter,
617 tx_env_converter,
618 } = self;
619 RpcConverter {
620 receipt_converter,
621 header_converter,
622 mapper,
623 network,
624 evm,
625 sim_tx_converter,
626 rpc_tx_converter,
627 tx_env_converter,
628 }
629 }
630
631 pub fn with_mapper<MapNew>(
633 self,
634 mapper: MapNew,
635 ) -> RpcConverter<Network, Evm, Receipt, Header, MapNew, SimTx, RpcTx, TxEnv> {
636 let Self {
637 receipt_converter,
638 header_converter,
639 mapper: _,
640 network,
641 evm,
642 sim_tx_converter,
643 rpc_tx_converter,
644 tx_env_converter,
645 } = self;
646 RpcConverter {
647 receipt_converter,
648 header_converter,
649 mapper,
650 network,
651 evm,
652 sim_tx_converter,
653 rpc_tx_converter,
654 tx_env_converter,
655 }
656 }
657
658 pub fn with_sim_tx_converter<SimTxNew>(
660 self,
661 sim_tx_converter: SimTxNew,
662 ) -> RpcConverter<Network, Evm, Receipt, Header, Map, SimTxNew, RpcTx, TxEnv> {
663 let Self {
664 receipt_converter,
665 header_converter,
666 mapper,
667 network,
668 evm,
669 rpc_tx_converter,
670 tx_env_converter,
671 ..
672 } = self;
673 RpcConverter {
674 receipt_converter,
675 header_converter,
676 mapper,
677 network,
678 evm,
679 sim_tx_converter,
680 rpc_tx_converter,
681 tx_env_converter,
682 }
683 }
684
685 pub fn with_rpc_tx_converter<RpcTxNew>(
687 self,
688 rpc_tx_converter: RpcTxNew,
689 ) -> RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTxNew, TxEnv> {
690 let Self {
691 receipt_converter,
692 header_converter,
693 mapper,
694 network,
695 evm,
696 sim_tx_converter,
697 tx_env_converter,
698 ..
699 } = self;
700 RpcConverter {
701 receipt_converter,
702 header_converter,
703 mapper,
704 network,
705 evm,
706 sim_tx_converter,
707 rpc_tx_converter,
708 tx_env_converter,
709 }
710 }
711
712 pub fn erased(
714 self,
715 ) -> Box<
716 dyn RpcConvert<
717 Primitives = <Self as RpcConvert>::Primitives,
718 Network = <Self as RpcConvert>::Network,
719 Error = <Self as RpcConvert>::Error,
720 Evm = <Self as RpcConvert>::Evm,
721 >,
722 >
723 where
724 Self: RpcConvert,
725 {
726 Box::new(self)
727 }
728}
729
730impl<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv> Default
731 for RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
732where
733 Receipt: Default,
734 Header: Default,
735 Map: Default,
736 SimTx: Default,
737 RpcTx: Default,
738 TxEnv: Default,
739{
740 fn default() -> Self {
741 Self {
742 network: Default::default(),
743 evm: Default::default(),
744 receipt_converter: Default::default(),
745 header_converter: Default::default(),
746 mapper: Default::default(),
747 sim_tx_converter: Default::default(),
748 rpc_tx_converter: Default::default(),
749 tx_env_converter: Default::default(),
750 }
751 }
752}
753
754impl<
755 Network,
756 Evm,
757 Receipt: Clone,
758 Header: Clone,
759 Map: Clone,
760 SimTx: Clone,
761 RpcTx: Clone,
762 TxEnv: Clone,
763 > Clone for RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
764{
765 fn clone(&self) -> Self {
766 Self {
767 network: Default::default(),
768 evm: Default::default(),
769 receipt_converter: self.receipt_converter.clone(),
770 header_converter: self.header_converter.clone(),
771 mapper: self.mapper.clone(),
772 sim_tx_converter: self.sim_tx_converter.clone(),
773 rpc_tx_converter: self.rpc_tx_converter.clone(),
774 tx_env_converter: self.tx_env_converter.clone(),
775 }
776 }
777}
778
779impl<N, Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv> RpcConvert
780 for RpcConverter<Network, Evm, Receipt, Header, Map, SimTx, RpcTx, TxEnv>
781where
782 N: NodePrimitives,
783 Network: RpcTypes<TransactionRequest: SignableTxRequest<N::SignedTx>>,
784 Evm: ConfigureEvm<Primitives = N> + 'static,
785 Receipt: ReceiptConverter<
786 N,
787 RpcReceipt = RpcReceipt<Network>,
788 Error: From<TransactionConversionError>
789 + From<TxEnv::Error>
790 + From<<Map as TxInfoMapper<TxTy<N>>>::Err>
791 + From<RpcTx::Err>
792 + From<Header::Err>
793 + Error
794 + Unpin
795 + Sync
796 + Send
797 + Into<jsonrpsee_types::ErrorObject<'static>>,
798 > + Send
799 + Sync
800 + Unpin
801 + Clone
802 + Debug,
803 Header: HeaderConverter<HeaderTy<N>, RpcHeader<Network>>,
804 Map: TxInfoMapper<TxTy<N>> + Clone + Debug + Unpin + Send + Sync + 'static,
805 SimTx: SimTxConverter<RpcTxReq<Network>, TxTy<N>>,
806 RpcTx:
807 RpcTxConverter<TxTy<N>, Network::TransactionResponse, <Map as TxInfoMapper<TxTy<N>>>::Out>,
808 TxEnv: TxEnvConverter<RpcTxReq<Network>, Evm>,
809{
810 type Primitives = N;
811 type Evm = Evm;
812 type Network = Network;
813 type Error = Receipt::Error;
814
815 fn fill(
816 &self,
817 tx: Recovered<TxTy<N>>,
818 tx_info: TransactionInfo,
819 ) -> Result<Network::TransactionResponse, Self::Error> {
820 let (tx, signer) = tx.into_parts();
821 let tx_info = self.mapper.try_map(&tx, tx_info)?;
822
823 self.rpc_tx_converter.convert_rpc_tx(tx, signer, tx_info).map_err(Into::into)
824 }
825
826 fn build_simulate_v1_transaction(
827 &self,
828 request: RpcTxReq<Network>,
829 ) -> Result<TxTy<N>, Self::Error> {
830 Ok(self
831 .sim_tx_converter
832 .convert_sim_tx(request)
833 .map_err(|e| TransactionConversionError::FromTxReq(e.to_string()))?)
834 }
835
836 fn tx_env(
837 &self,
838 request: RpcTxReq<Network>,
839 evm_env: &EvmEnvFor<Evm>,
840 ) -> Result<TxEnvFor<Evm>, Self::Error> {
841 self.tx_env_converter.convert_tx_env(request, evm_env).map_err(Into::into)
842 }
843
844 fn convert_receipts(
845 &self,
846 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
847 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error> {
848 self.receipt_converter.convert_receipts(receipts)
849 }
850
851 fn convert_receipts_with_block(
852 &self,
853 receipts: Vec<ConvertReceiptInput<'_, Self::Primitives>>,
854 block: &SealedBlock<BlockTy<Self::Primitives>>,
855 ) -> Result<Vec<RpcReceipt<Self::Network>>, Self::Error> {
856 self.receipt_converter.convert_receipts_with_block(receipts, block)
857 }
858
859 fn convert_header(
860 &self,
861 header: SealedHeaderFor<Self::Primitives>,
862 block_size: usize,
863 ) -> Result<RpcHeader<Self::Network>, Self::Error> {
864 Ok(self.header_converter.convert_header(header, block_size)?)
865 }
866}
867
868#[cfg(feature = "op")]
870pub mod op {
871 use super::*;
872 use alloy_consensus::SignableTransaction;
873 use alloy_signer::Signature;
874 use op_alloy_consensus::{transaction::OpTransactionInfo, OpTxEnvelope};
875 use op_alloy_rpc_types::OpTransactionRequest;
876
877 impl<T: op_alloy_consensus::OpTransaction + alloy_consensus::Transaction> FromConsensusTx<T>
878 for op_alloy_rpc_types::Transaction<T>
879 {
880 type TxInfo = OpTransactionInfo;
881 type Err = Infallible;
882
883 fn from_consensus_tx(
884 tx: T,
885 signer: Address,
886 tx_info: Self::TxInfo,
887 ) -> Result<Self, Self::Err> {
888 Ok(Self::from_transaction(Recovered::new_unchecked(tx, signer), tx_info))
889 }
890 }
891
892 impl TryIntoSimTx<OpTxEnvelope> for OpTransactionRequest {
893 fn try_into_sim_tx(self) -> Result<OpTxEnvelope, ValueError<Self>> {
894 let tx = self
895 .build_typed_tx()
896 .map_err(|request| ValueError::new(request, "Required fields missing"))?;
897
898 let signature = Signature::new(Default::default(), Default::default(), false);
900
901 Ok(tx.into_signed(signature).into())
902 }
903 }
904}