diff --git a/crates/rpc/rpc-convert/src/transaction.rs b/crates/rpc/rpc-convert/src/transaction.rs index cf845067410..e33d254e272 100644 --- a/crates/rpc/rpc-convert/src/transaction.rs +++ b/crates/rpc/rpc-convert/src/transaction.rs @@ -223,6 +223,55 @@ where } } +/// Converts `TxReq` into `SimTx`. +/// +/// Where: +/// * `TxReq` is a transaction request received from an RPC API +/// * `SimTx` is the corresponding consensus layer transaction for execution simulation +/// +/// The `SimTxConverter` has two blanket implementations: +/// * `()` assuming `TxReq` implements [`TryIntoSimTx`] and is used as default for [`RpcConverter`]. +/// * `Fn(TxReq) -> Result>` and can be applied using +/// [`RpcConverter::with_sim_tx_converter`]. +/// +/// One should prefer to implement [`TryIntoSimTx`] for `TxReq` to get the `SimTxConverter` +/// implementation for free, thanks to the blanket implementation, unless the conversion requires +/// more context. For example, some configuration parameters or access handles to database, network, +/// etc. +pub trait SimTxConverter: Clone + Debug + Unpin + Send + Sync + 'static { + /// An associated error that can occur during the conversion. + type Err: Error; + + /// Performs the conversion from `tx_req` into `SimTx`. + /// + /// See [`SimTxConverter`] for more information. + fn convert_sim_tx(&self, tx_req: TxReq) -> Result; +} + +impl SimTxConverter for () +where + TxReq: TryIntoSimTx + Debug, +{ + type Err = ValueError; + + fn convert_sim_tx(&self, tx_req: TxReq) -> Result { + tx_req.try_into_sim_tx() + } +} + +impl SimTxConverter for F +where + TxReq: Debug, + E: Error, + F: Fn(TxReq) -> Result + Clone + Debug + Unpin + Send + Sync + 'static, +{ + type Err = E; + + fn convert_sim_tx(&self, tx_req: TxReq) -> Result { + self(tx_req) + } +} + /// Converts `self` into `T`. /// /// Should create a fake transaction for simulation using [`TransactionRequest`]. @@ -402,12 +451,13 @@ pub struct TransactionConversionError(String); /// is [`TransactionInfo`] then `()` can be used as `Map` which trivially passes over the input /// object. #[derive(Debug)] -pub struct RpcConverter { +pub struct RpcConverter { network: PhantomData, evm: PhantomData, receipt_converter: Receipt, header_converter: Header, mapper: Map, + sim_tx_converter: SimTx, } impl RpcConverter { @@ -419,20 +469,24 @@ impl RpcConverter { receipt_converter, header_converter: (), mapper: (), + sim_tx_converter: (), } } } -impl RpcConverter { +impl + RpcConverter +{ /// Converts the network type - pub fn with_network(self) -> RpcConverter { - let Self { receipt_converter, header_converter, mapper, evm, .. } = self; + pub fn with_network(self) -> RpcConverter { + let Self { receipt_converter, header_converter, mapper, evm, sim_tx_converter, .. } = self; RpcConverter { receipt_converter, header_converter, mapper, network: Default::default(), evm, + sim_tx_converter, } } @@ -440,27 +494,39 @@ impl RpcConverter( self, header_converter: HeaderNew, - ) -> RpcConverter { - let Self { receipt_converter, header_converter: _, mapper, network, evm } = self; - RpcConverter { receipt_converter, header_converter, mapper, network, evm } + ) -> RpcConverter { + let Self { receipt_converter, header_converter: _, mapper, network, evm, sim_tx_converter } = + self; + RpcConverter { receipt_converter, header_converter, mapper, network, evm, sim_tx_converter } } /// Configures the mapper. pub fn with_mapper( self, mapper: MapNew, - ) -> RpcConverter { - let Self { receipt_converter, header_converter, mapper: _, network, evm } = self; - RpcConverter { receipt_converter, header_converter, mapper, network, evm } + ) -> RpcConverter { + let Self { receipt_converter, header_converter, mapper: _, network, evm, sim_tx_converter } = + self; + RpcConverter { receipt_converter, header_converter, mapper, network, evm, sim_tx_converter } + } + + /// Swaps the simulate transaction converter with `sim_tx_converter`. + pub fn with_sim_tx_converter( + self, + sim_tx_converter: SimTxNew, + ) -> RpcConverter { + let Self { receipt_converter, header_converter, mapper, network, evm, .. } = self; + RpcConverter { receipt_converter, header_converter, mapper, network, evm, sim_tx_converter } } } -impl Default - for RpcConverter +impl Default + for RpcConverter where Receipt: Default, Header: Default, Map: Default, + SimTx: Default, { fn default() -> Self { Self { @@ -469,12 +535,13 @@ where receipt_converter: Default::default(), header_converter: Default::default(), mapper: Default::default(), + sim_tx_converter: Default::default(), } } } -impl Clone - for RpcConverter +impl Clone + for RpcConverter { fn clone(&self) -> Self { Self { @@ -483,18 +550,19 @@ impl Clone receipt_converter: self.receipt_converter.clone(), header_converter: self.header_converter.clone(), mapper: self.mapper.clone(), + sim_tx_converter: self.sim_tx_converter.clone(), } } } -impl RpcConvert - for RpcConverter +impl RpcConvert + for RpcConverter where N: NodePrimitives, Network: RpcTypes + Send + Sync + Unpin + Clone + Debug, Evm: ConfigureEvm + 'static, TxTy: IntoRpcTx + Clone + Debug, - RpcTxReq: TryIntoSimTx> + TryIntoTxEnv>, + RpcTxReq: TryIntoTxEnv>, Receipt: ReceiptConverter< N, RpcReceipt = RpcReceipt, @@ -521,6 +589,7 @@ where + Send + Sync + 'static, + SimTx: SimTxConverter, TxTy>, { type Primitives = N; type Network = Network; @@ -542,7 +611,10 @@ where &self, request: RpcTxReq, ) -> Result, Self::Error> { - Ok(request.try_into_sim_tx().map_err(|e| TransactionConversionError(e.to_string()))?) + Ok(self + .sim_tx_converter + .convert_sim_tx(request) + .map_err(|e| TransactionConversionError(e.to_string()))?) } fn tx_env(