refactor: replace TryFrom*Response traits with unified RpcResponseConverter (#22320)

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Matthias Seitz
2026-02-18 14:32:47 +01:00
committed by GitHub
parent e6e0dde903
commit 251f83ab0b
10 changed files with 156 additions and 334 deletions

View File

@@ -0,0 +1,6 @@
---
reth-rpc-convert: minor
reth-storage-rpc-provider: minor
---
Replaced the separate `TryFromBlockResponse`, `TryFromReceiptResponse`, and `TryFromTransactionResponse` traits with a unified `RpcResponseConverter` trait and default `EthRpcConverter` implementation. Removed the `op-alloy-network` dependency and refactored `RpcBlockchainProvider` to store a dynamic converter instance instead of relying on per-type trait bounds.

4
Cargo.lock generated
View File

@@ -9934,9 +9934,7 @@ dependencies = [
"dyn-clone",
"jsonrpsee-types",
"op-alloy-consensus",
"op-alloy-network",
"op-alloy-rpc-types",
"reth-ethereum-primitives",
"reth-evm",
"reth-primitives-traits",
"serde_json",
@@ -10328,12 +10326,12 @@ dependencies = [
"reth-chainspec",
"reth-db-api",
"reth-errors",
"reth-ethereum-primitives",
"reth-execution-types",
"reth-node-types",
"reth-primitives",
"reth-provider",
"reth-prune-types",
"reth-rpc-convert",
"reth-stages-types",
"reth-storage-api",
"reth-trie",

View File

@@ -15,7 +15,6 @@ workspace = true
# reth
reth-primitives-traits.workspace = true
reth-evm.workspace = true
reth-ethereum-primitives.workspace = true
# ethereum
alloy-primitives.workspace = true
@@ -29,7 +28,6 @@ alloy-evm = { workspace = true, features = ["rpc"] }
# optimism
op-alloy-consensus = { workspace = true, optional = true }
op-alloy-rpc-types = { workspace = true, optional = true }
op-alloy-network = { workspace = true, optional = true }
# io
jsonrpsee-types.workspace = true
@@ -48,7 +46,6 @@ default = []
op = [
"dep:op-alloy-consensus",
"dep:op-alloy-rpc-types",
"dep:op-alloy-network",
"reth-evm/op",
"reth-primitives-traits/op",
"alloy-evm/op",

View File

@@ -1,47 +0,0 @@
//! Conversion traits for block responses to primitive block types.
use alloy_network::Network;
use std::convert::Infallible;
/// Trait for converting network block responses to primitive block types.
pub trait TryFromBlockResponse<N: Network> {
/// The error type returned if the conversion fails.
type Error: core::error::Error + Send + Sync + Unpin;
/// Converts a network block response to a primitive block type.
///
/// # Returns
///
/// Returns `Ok(Self)` on successful conversion, or `Err(Self::Error)` if the conversion fails.
fn from_block_response(block_response: N::BlockResponse) -> Result<Self, Self::Error>
where
Self: Sized;
}
impl<N: Network, T> TryFromBlockResponse<N> for alloy_consensus::Block<T>
where
N::BlockResponse: Into<Self>,
{
type Error = Infallible;
fn from_block_response(block_response: N::BlockResponse) -> Result<Self, Self::Error> {
Ok(block_response.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_consensus::{Block, TxEnvelope};
use alloy_network::Ethereum;
use alloy_rpc_types_eth::BlockTransactions;
#[test]
fn test_try_from_block_response() {
let rpc_block: alloy_rpc_types_eth::Block =
alloy_rpc_types_eth::Block::new(Default::default(), BlockTransactions::Full(vec![]));
let result =
<Block<TxEnvelope> as TryFromBlockResponse<Ethereum>>::from_block_response(rpc_block);
assert!(result.is_ok());
}
}

View File

@@ -10,17 +10,12 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod block;
pub mod receipt;
mod rpc;
pub mod transaction;
pub use block::TryFromBlockResponse;
pub use receipt::TryFromReceiptResponse;
pub use rpc::*;
pub use transaction::{
RpcConvert, RpcConverter, TransactionConversionError, TryFromTransactionResponse, TryIntoSimTx,
TxInfoMapper,
RpcConvert, RpcConverter, TransactionConversionError, TryIntoSimTx, TxInfoMapper,
};
pub use alloy_evm::rpc::{CallFees, CallFeesError, EthTxEnvError, TryIntoTxEnv};

View File

@@ -1,102 +0,0 @@
//! Conversion traits for receipt responses to primitive receipt types.
use alloy_network::Network;
use std::convert::Infallible;
/// Trait for converting network receipt responses to primitive receipt types.
pub trait TryFromReceiptResponse<N: Network> {
/// The error type returned if the conversion fails.
type Error: core::error::Error + Send + Sync + Unpin;
/// Converts a network receipt response to a primitive receipt type.
///
/// # Returns
///
/// Returns `Ok(Self)` on successful conversion, or `Err(Self::Error)` if the conversion fails.
fn from_receipt_response(receipt_response: N::ReceiptResponse) -> Result<Self, Self::Error>
where
Self: Sized;
}
impl TryFromReceiptResponse<alloy_network::Ethereum> for reth_ethereum_primitives::Receipt {
type Error = Infallible;
fn from_receipt_response(
receipt_response: alloy_rpc_types_eth::TransactionReceipt,
) -> Result<Self, Self::Error> {
Ok(receipt_response.into_inner().into())
}
}
#[cfg(feature = "op")]
impl TryFromReceiptResponse<op_alloy_network::Optimism> for op_alloy_consensus::OpReceipt {
type Error = Infallible;
fn from_receipt_response(
receipt_response: op_alloy_rpc_types::OpTransactionReceipt,
) -> Result<Self, Self::Error> {
Ok(receipt_response.inner.inner.into_components().0.map_logs(Into::into))
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_consensus::ReceiptEnvelope;
use alloy_network::Ethereum;
use reth_ethereum_primitives::Receipt;
#[test]
fn test_try_from_receipt_response() {
let rpc_receipt = alloy_rpc_types_eth::TransactionReceipt {
inner: ReceiptEnvelope::Eip1559(Default::default()),
transaction_hash: Default::default(),
transaction_index: None,
block_hash: None,
block_number: None,
gas_used: 0,
effective_gas_price: 0,
blob_gas_used: None,
blob_gas_price: None,
from: Default::default(),
to: None,
contract_address: None,
};
let result =
<Receipt as TryFromReceiptResponse<Ethereum>>::from_receipt_response(rpc_receipt);
assert!(result.is_ok());
}
#[cfg(feature = "op")]
#[test]
fn test_try_from_receipt_response_optimism() {
use alloy_consensus::ReceiptWithBloom;
use op_alloy_consensus::OpReceipt;
use op_alloy_network::Optimism;
use op_alloy_rpc_types::OpTransactionReceipt;
let op_receipt = OpTransactionReceipt {
inner: alloy_rpc_types_eth::TransactionReceipt {
inner: ReceiptWithBloom {
receipt: OpReceipt::Eip1559(Default::default()),
logs_bloom: Default::default(),
},
transaction_hash: Default::default(),
transaction_index: None,
block_hash: None,
block_number: None,
gas_used: 0,
effective_gas_price: 0,
blob_gas_used: None,
blob_gas_price: None,
from: Default::default(),
to: None,
contract_address: None,
},
l1_block_info: Default::default(),
};
let result =
<OpReceipt as TryFromReceiptResponse<Optimism>>::from_receipt_response(op_receipt);
assert!(result.is_ok());
}
}

View File

@@ -5,7 +5,6 @@ use crate::{
use alloy_consensus::{
error::ValueError, transaction::Recovered, EthereumTxEnvelope, Sealable, TxEip4844,
};
use alloy_network::Network;
use alloy_primitives::{Address, U256};
use alloy_rpc_types_eth::{request::TransactionRequest, Transaction, TransactionInfo};
use core::error;
@@ -903,112 +902,3 @@ pub mod op {
}
}
}
/// Trait for converting network transaction responses to primitive transaction types.
pub trait TryFromTransactionResponse<N: Network> {
/// The error type returned if the conversion fails.
type Error: core::error::Error + Send + Sync + Unpin;
/// Converts a network transaction response to a primitive transaction type.
///
/// # Returns
///
/// Returns `Ok(Self)` on successful conversion, or `Err(Self::Error)` if the conversion fails.
fn from_transaction_response(
transaction_response: N::TransactionResponse,
) -> Result<Self, Self::Error>
where
Self: Sized;
}
impl TryFromTransactionResponse<alloy_network::Ethereum>
for reth_ethereum_primitives::TransactionSigned
{
type Error = Infallible;
fn from_transaction_response(transaction_response: Transaction) -> Result<Self, Self::Error> {
Ok(transaction_response.into_inner().into())
}
}
#[cfg(feature = "op")]
impl TryFromTransactionResponse<op_alloy_network::Optimism> for op_alloy_consensus::OpTxEnvelope {
type Error = Infallible;
fn from_transaction_response(
transaction_response: op_alloy_rpc_types::Transaction,
) -> Result<Self, Self::Error> {
Ok(transaction_response.inner.into_inner())
}
}
#[cfg(test)]
mod transaction_response_tests {
use super::*;
use alloy_consensus::{transaction::Recovered, EthereumTxEnvelope, Signed, TxLegacy};
use alloy_network::Ethereum;
use alloy_primitives::{Address, Signature, B256, U256};
use alloy_rpc_types_eth::Transaction;
#[test]
fn test_ethereum_transaction_conversion() {
let signed_tx = Signed::new_unchecked(
TxLegacy::default(),
Signature::new(U256::ONE, U256::ONE, false),
B256::ZERO,
);
let envelope = EthereumTxEnvelope::Legacy(signed_tx);
let tx_response = Transaction {
inner: Recovered::new_unchecked(envelope, Address::ZERO),
block_hash: None,
block_number: None,
transaction_index: None,
effective_gas_price: None,
};
let result = <reth_ethereum_primitives::TransactionSigned as TryFromTransactionResponse<
Ethereum,
>>::from_transaction_response(tx_response);
assert!(result.is_ok());
}
#[cfg(feature = "op")]
mod op {
use super::*;
#[test]
fn test_optimism_transaction_conversion() {
use op_alloy_consensus::OpTxEnvelope;
use op_alloy_network::Optimism;
let signed_tx = Signed::new_unchecked(
TxLegacy::default(),
Signature::new(U256::ONE, U256::ONE, false),
B256::ZERO,
);
let envelope = OpTxEnvelope::Legacy(signed_tx);
let inner_tx = Transaction {
inner: Recovered::new_unchecked(envelope, Address::ZERO),
block_hash: None,
block_number: None,
transaction_index: None,
effective_gas_price: None,
};
let tx_response = op_alloy_rpc_types::Transaction {
inner: inner_tx,
deposit_nonce: None,
deposit_receipt_version: None,
};
let result =
<OpTxEnvelope as TryFromTransactionResponse<Optimism>>::from_transaction_response(
tx_response,
);
assert!(result.is_ok());
}
}
}

View File

@@ -16,6 +16,7 @@ workspace = true
reth-storage-api.workspace = true
reth-chainspec.workspace = true
reth-primitives.workspace = true
reth-ethereum-primitives.workspace = true
reth-provider.workspace = true
reth-errors.workspace = true
reth-execution-types.workspace = true
@@ -24,7 +25,6 @@ reth-node-types.workspace = true
reth-trie.workspace = true
reth-stages-types.workspace = true
reth-db-api.workspace = true
reth-rpc-convert.workspace = true
# alloy
alloy-provider = { workspace = true, features = ["debug-api"] }

View File

@@ -51,13 +51,14 @@ use reth_provider::{
TransactionVariant, TransactionsProvider,
};
use reth_prune_types::{PruneCheckpoint, PruneSegment};
use reth_rpc_convert::{TryFromBlockResponse, TryFromReceiptResponse, TryFromTransactionResponse};
pub mod rpc_response;
use reth_stages_types::{StageCheckpoint, StageId};
use reth_storage_api::{
BlockBodyIndicesProvider, BlockReaderIdExt, BlockSource, DBProvider, NodePrimitivesProvider,
ReceiptProviderIdExt, StatsReader,
};
use reth_trie::{updates::TrieUpdates, AccountProof, HashedPostState, MultiProof, TrieInput};
pub use rpc_response::{EthRpcConverter, RpcResponseConverter};
use std::{
collections::BTreeMap,
future::{Future, IntoFuture},
@@ -100,6 +101,14 @@ impl RpcBlockchainProviderConfig {
}
}
/// Type-erased RPC response converter stored in [`RpcBlockchainProvider`].
type DynRpcConverter<Node, N> = dyn RpcResponseConverter<
N,
Block = BlockTy<Node>,
Transaction = TxTy<Node>,
Receipt = ReceiptTy<Node>,
>;
/// An RPC-based blockchain provider that fetches blockchain data via remote RPC calls.
///
/// This is the RPC equivalent of
@@ -119,6 +128,7 @@ impl RpcBlockchainProviderConfig {
pub struct RpcBlockchainProvider<P, Node, N = alloy_network::AnyNetwork>
where
Node: NodeTypes,
N: Network,
{
/// The underlying Alloy provider
provider: P,
@@ -132,25 +142,66 @@ where
config: RpcBlockchainProviderConfig,
/// Cached chain spec
chain_spec: Arc<Node::ChainSpec>,
/// Converts RPC responses to primitive types.
converter: Arc<DynRpcConverter<Node, N>>,
}
impl<P, Node: NodeTypes, N> std::fmt::Debug for RpcBlockchainProvider<P, Node, N> {
impl<P, Node: NodeTypes, N: Network> std::fmt::Debug for RpcBlockchainProvider<P, Node, N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RpcBlockchainProvider").field("config", &self.config).finish()
}
}
impl<P, Node: NodeTypes, N> RpcBlockchainProvider<P, Node, N> {
/// Creates a new `RpcBlockchainProvider` with default configuration
impl<P, Node: NodeTypes, N: Network> RpcBlockchainProvider<P, Node, N>
where
EthRpcConverter: RpcResponseConverter<
N,
Block = BlockTy<Node>,
Transaction = TxTy<Node>,
Receipt = ReceiptTy<Node>,
>,
{
/// Creates a new `RpcBlockchainProvider` with the default [`EthRpcConverter`].
pub fn new(provider: P) -> Self
where
Node::ChainSpec: Default,
{
Self::new_with_config(provider, RpcBlockchainProviderConfig::default())
Self::new_with_converter(provider, EthRpcConverter)
}
}
impl<P, Node: NodeTypes, N: Network> RpcBlockchainProvider<P, Node, N> {
/// Creates a new `RpcBlockchainProvider` with default configuration and the given converter.
pub fn new_with_converter(
provider: P,
converter: impl RpcResponseConverter<
N,
Block = BlockTy<Node>,
Transaction = TxTy<Node>,
Receipt = ReceiptTy<Node>,
>,
) -> Self
where
Node::ChainSpec: Default,
{
Self::new_with_converter_and_config(
provider,
converter,
RpcBlockchainProviderConfig::default(),
)
}
/// Creates a new `RpcBlockchainProvider` with custom configuration
pub fn new_with_config(provider: P, config: RpcBlockchainProviderConfig) -> Self
/// Creates a new `RpcBlockchainProvider` with custom configuration and the given converter.
pub fn new_with_converter_and_config(
provider: P,
converter: impl RpcResponseConverter<
N,
Block = BlockTy<Node>,
Transaction = TxTy<Node>,
Receipt = ReceiptTy<Node>,
>,
config: RpcBlockchainProviderConfig,
) -> Self
where
Node::ChainSpec: Default,
{
@@ -162,19 +213,13 @@ impl<P, Node: NodeTypes, N> RpcBlockchainProvider<P, Node, N> {
canon_state_notification,
config,
chain_spec: Arc::new(Node::ChainSpec::default()),
converter: Arc::new(converter),
}
}
/// Use a custom chain spec for the provider
pub fn with_chain_spec(self, chain_spec: Arc<Node::ChainSpec>) -> Self {
Self {
provider: self.provider,
node_types: std::marker::PhantomData,
network: std::marker::PhantomData,
canon_state_notification: self.canon_state_notification,
config: self.config,
chain_spec,
}
Self { chain_spec, ..self }
}
/// Helper function to execute async operations in a blocking context
@@ -332,7 +377,6 @@ where
P: Provider<N> + Clone + 'static,
N: Network,
Node: NodeTypes,
BlockTy<Node>: TryFromBlockResponse<N>,
{
type Header = HeaderTy<Node>;
@@ -347,8 +391,7 @@ where
};
// Convert the network block response to primitive block
let block = <BlockTy<Node> as TryFromBlockResponse<N>>::from_block_response(block_response)
.map_err(ProviderError::other)?;
let block = self.converter.block(block_response).map_err(ProviderError::other)?;
Ok(Some(block.into_header()))
}
@@ -384,8 +427,7 @@ where
let block_hash = block_response.header().hash();
// Convert the network block response to primitive block
let block = <BlockTy<Node> as TryFromBlockResponse<N>>::from_block_response(block_response)
.map_err(ProviderError::other)?;
let block = self.converter.block(block_response).map_err(ProviderError::other)?;
Ok(Some(SealedHeader::new(block.into_header(), block_hash)))
}
@@ -422,9 +464,6 @@ where
P: Provider<N> + Clone + 'static,
N: Network,
Node: NodeTypes,
BlockTy<Node>: TryFromBlockResponse<N>,
TxTy<Node>: TryFromTransactionResponse<N>,
ReceiptTy<Node>: TryFromReceiptResponse<N>,
{
type Block = BlockTy<Node>;
@@ -447,8 +486,7 @@ where
};
// Convert the network block response to primitive block
let block = <BlockTy<Node> as TryFromBlockResponse<N>>::from_block_response(block_response)
.map_err(ProviderError::other)?;
let block = self.converter.block(block_response).map_err(ProviderError::other)?;
Ok(Some(block))
}
@@ -507,9 +545,6 @@ where
P: Provider<N> + Clone + 'static,
N: Network,
Node: NodeTypes,
BlockTy<Node>: TryFromBlockResponse<N>,
TxTy<Node>: TryFromTransactionResponse<N>,
ReceiptTy<Node>: TryFromReceiptResponse<N>,
{
fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
match id {
@@ -541,7 +576,6 @@ where
P: Provider<N> + Clone + 'static,
N: Network,
Node: NodeTypes,
ReceiptTy<Node>: TryFromReceiptResponse<N>,
{
type Receipt = ReceiptTy<Node>;
@@ -555,15 +589,10 @@ where
})?;
let Some(receipt_response) = receipt_response else {
// If the receipt was not found, return None
return Ok(None);
};
// Convert the network receipt response to primitive receipt
let receipt =
<ReceiptTy<Node> as TryFromReceiptResponse<N>>::from_receipt_response(receipt_response)
.map_err(ProviderError::other)?;
let receipt = self.converter.receipt(receipt_response).map_err(ProviderError::other)?;
Ok(Some(receipt))
}
@@ -579,19 +608,12 @@ where
.map_err(ProviderError::other)?;
let Some(receipts) = receipts_response else {
// If the receipts were not found, return None
return Ok(None);
};
// Convert the network receipts response to primitive receipts
let receipts = receipts
.into_iter()
.map(|receipt_response| {
<ReceiptTy<Node> as TryFromReceiptResponse<N>>::from_receipt_response(
receipt_response,
)
.map_err(ProviderError::other)
})
.map(|r| self.converter.receipt(r).map_err(ProviderError::other))
.collect::<Result<Vec<_>, _>>()?;
Ok(Some(receipts))
@@ -618,7 +640,6 @@ where
P: Provider<N> + Clone + 'static,
N: Network,
Node: NodeTypes,
ReceiptTy<Node>: TryFromReceiptResponse<N>,
{
}
@@ -627,8 +648,6 @@ where
P: Provider<N> + Clone + 'static,
N: Network,
Node: NodeTypes,
BlockTy<Node>: TryFromBlockResponse<N>,
TxTy<Node>: TryFromTransactionResponse<N>,
{
type Transaction = TxTy<Node>;
@@ -653,16 +672,11 @@ where
})?;
let Some(transaction_response) = transaction_response else {
// If the transaction was not found, return None
return Ok(None);
};
// Convert the network transaction response to primitive transaction
let transaction = <TxTy<Node> as TryFromTransactionResponse<N>>::from_transaction_response(
transaction_response,
)
.map_err(ProviderError::other)?;
let transaction =
self.converter.transaction(transaction_response).map_err(ProviderError::other)?;
Ok(Some(transaction))
}
@@ -682,14 +696,10 @@ where
})?;
let Some(block_response) = block_response else {
// If the block was not found, return None
return Ok(None);
};
// Convert the network block response to primitive block
let block = <BlockTy<Node> as TryFromBlockResponse<N>>::from_block_response(block_response)
.map_err(ProviderError::other)?;
let block = self.converter.block(block_response).map_err(ProviderError::other)?;
Ok(Some(block.into_body().into_transactions()))
}
@@ -855,7 +865,7 @@ where
impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainProvider<P, Node, N>
where
P: Send + Sync,
N: Send + Sync,
N: Network,
Node: NodeTypes,
{
type Primitives = PrimitivesTy<Node>;
@@ -876,7 +886,7 @@ where
impl<P, Node, N> ChainSpecProvider for RpcBlockchainProvider<P, Node, N>
where
P: Send + Sync,
N: Send + Sync,
N: Network,
Node: NodeTypes,
Node::ChainSpec: Default,
{
@@ -1834,7 +1844,7 @@ where
impl<P, Node, N> ChainSpecProvider for RpcBlockchainStateProvider<P, Node, N>
where
P: Send + Sync + std::fmt::Debug,
N: Send + Sync,
N: Network,
Node: NodeTypes,
Node::ChainSpec: Default,
{
@@ -1888,7 +1898,7 @@ where
impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainStateProvider<P, Node, N>
where
P: Send + Sync + std::fmt::Debug,
N: Send + Sync,
N: Network,
Node: NodeTypes,
{
type Primitives = PrimitivesTy<Node>;

View File

@@ -0,0 +1,75 @@
//! Unified converter for RPC network responses to primitive types.
use alloy_network::Network;
use alloy_rpc_types::eth::{Block, Transaction, TransactionReceipt};
use core::fmt::Debug;
use reth_ethereum_primitives::{Receipt, TransactionSigned};
/// Error type used by [`RpcResponseConverter`].
#[derive(Debug)]
pub struct RpcResponseConverterError(pub Box<dyn core::error::Error + Send + Sync>);
impl core::fmt::Display for RpcResponseConverterError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&self.0, f)
}
}
impl core::error::Error for RpcResponseConverterError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
self.0.source()
}
}
/// Converts RPC network responses (blocks, transactions, receipts) into primitive types.
pub trait RpcResponseConverter<N: Network>: Send + Sync + Debug + 'static {
/// Primitive block type.
type Block;
/// Primitive transaction type.
type Transaction;
/// Primitive receipt type.
type Receipt;
/// Converts a network block response to a primitive block.
fn block(&self, response: N::BlockResponse) -> Result<Self::Block, RpcResponseConverterError>;
/// Converts a network transaction response to a primitive transaction.
fn transaction(
&self,
response: N::TransactionResponse,
) -> Result<Self::Transaction, RpcResponseConverterError>;
/// Converts a network receipt response to a primitive receipt.
fn receipt(
&self,
response: N::ReceiptResponse,
) -> Result<Self::Receipt, RpcResponseConverterError>;
}
/// Default Ethereum converter using upstream `From` impls.
#[derive(Debug, Clone, Copy, Default)]
pub struct EthRpcConverter;
impl RpcResponseConverter<alloy_network::Ethereum> for EthRpcConverter {
type Block = alloy_consensus::Block<TransactionSigned>;
type Transaction = TransactionSigned;
type Receipt = Receipt;
fn block(&self, response: Block) -> Result<Self::Block, RpcResponseConverterError> {
Ok(response.into())
}
fn transaction(
&self,
response: Transaction,
) -> Result<Self::Transaction, RpcResponseConverterError> {
Ok(response.into_inner().into())
}
fn receipt(
&self,
response: TransactionReceipt,
) -> Result<Self::Receipt, RpcResponseConverterError> {
Ok(response.into_inner().into())
}
}