chore(rpc): remove use of extensible transaction + receipt types (#9774)

This commit is contained in:
Emilia Hane
2024-09-20 17:00:28 +02:00
committed by GitHub
parent 05f862af41
commit b5adf24a65
52 changed files with 833 additions and 664 deletions

5
Cargo.lock generated
View File

@ -7714,7 +7714,6 @@ dependencies = [
name = "reth-node-builder"
version = "1.0.7"
dependencies = [
"alloy-network",
"alloy-primitives",
"aquamarine",
"eyre",
@ -8086,6 +8085,7 @@ name = "reth-optimism-rpc"
version = "1.0.7"
dependencies = [
"alloy-primitives",
"derive_more",
"jsonrpsee-types",
"op-alloy-consensus",
"op-alloy-network",
@ -8352,7 +8352,6 @@ name = "reth-rpc"
version = "1.0.7"
dependencies = [
"alloy-dyn-abi",
"alloy-eips",
"alloy-genesis",
"alloy-network",
"alloy-primitives",
@ -8566,6 +8565,7 @@ version = "1.0.7"
dependencies = [
"alloy-consensus",
"alloy-primitives",
"alloy-rpc-types",
"alloy-sol-types",
"derive_more",
"futures",
@ -8580,6 +8580,7 @@ dependencies = [
"reth-execution-types",
"reth-metrics",
"reth-primitives",
"reth-provider",
"reth-revm",
"reth-rpc-server-types",
"reth-rpc-types",

View File

@ -2,16 +2,12 @@
use std::sync::Arc;
use alloy_network::Network;
use node::NodeTestContext;
use reth::{
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
builder::{NodeBuilder, NodeConfig, NodeHandle},
network::PeersHandleProvider,
rpc::{
api::eth::{helpers::AddDevSigners, FullEthApiServer},
types::AnyTransactionReceipt,
},
rpc::api::eth::{helpers::AddDevSigners, FullEthApiServer},
tasks::TaskManager,
};
use reth_chainspec::ChainSpec;
@ -62,13 +58,7 @@ where
>,
N::AddOns: NodeAddOns<
Adapter<N>,
EthApi: FullEthApiServer<
NetworkTypes: Network<
TransactionResponse = reth_rpc_types::WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
> + AddDevSigners
+ EthApiBuilderProvider<Adapter<N>>,
EthApi: FullEthApiServer + AddDevSigners + EthApiBuilderProvider<Adapter<N>>,
>,
{
let tasks = TaskManager::current();

View File

@ -1,6 +1,5 @@
use std::{marker::PhantomData, pin::Pin};
use alloy_network::Network;
use alloy_primitives::{BlockHash, BlockNumber, Bytes, B256};
use alloy_rpc_types::BlockNumberOrTag;
use eyre::Ok;
@ -11,13 +10,15 @@ use reth::{
network::PeersHandleProvider,
providers::{BlockReader, BlockReaderIdExt, CanonStateSubscriptions, StageCheckpointReader},
rpc::{
api::eth::helpers::{EthApiSpec, EthTransactions, TraceExt},
types::{engine::PayloadStatusEnum, AnyTransactionReceipt},
api::eth::{
helpers::{EthApiSpec, EthTransactions, TraceExt},
FullEthApiTypes,
},
types::engine::PayloadStatusEnum,
},
};
use reth_chainspec::ChainSpec;
use reth_node_builder::{EthApiTypes, NodeAddOns, NodeTypesWithEngine};
use reth_rpc_types::WithOtherFields;
use reth_node_builder::{NodeAddOns, NodeTypesWithEngine};
use reth_stages_types::StageId;
use tokio_stream::StreamExt;
@ -87,13 +88,8 @@ where
attributes_generator: impl Fn(u64) -> Engine::PayloadBuilderAttributes + Copy,
) -> eyre::Result<Vec<(Engine::BuiltPayload, Engine::PayloadBuilderAttributes)>>
where
<Engine as EngineTypes>::ExecutionPayloadV3:
From<Engine::BuiltPayload> + PayloadEnvelopeExt,
AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt,
<AddOns::EthApi as EthApiTypes>::NetworkTypes: Network<
TransactionResponse = WithOtherFields<alloy_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
Engine::ExecutionPayloadV3: From<Engine::BuiltPayload> + PayloadEnvelopeExt,
AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt + FullEthApiTypes,
{
let mut chain = Vec::with_capacity(length as usize);
for i in 0..length {

View File

@ -1,5 +1,5 @@
use alloy_consensus::TxEnvelope;
use alloy_network::{eip2718::Decodable2718, Network};
use alloy_network::eip2718::Decodable2718;
use alloy_primitives::{Bytes, B256};
use reth::{
builder::{rpc::RpcRegistry, FullNodeComponents},
@ -10,7 +10,6 @@ use reth::{
};
use reth_chainspec::ChainSpec;
use reth_node_builder::{EthApiTypes, NodeTypes};
use reth_rpc_types::{AnyTransactionReceipt, WithOtherFields};
#[allow(missing_debug_implementations)]
pub struct RpcTestContext<Node: FullNodeComponents, EthApi: EthApiTypes> {
@ -20,13 +19,7 @@ pub struct RpcTestContext<Node: FullNodeComponents, EthApi: EthApiTypes> {
impl<Node, EthApi> RpcTestContext<Node, EthApi>
where
Node: FullNodeComponents<Types: NodeTypes<ChainSpec = ChainSpec>>,
EthApi: EthApiSpec
+ EthTransactions<
NetworkTypes: Network<
TransactionResponse = WithOtherFields<alloy_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
> + TraceExt,
EthApi: EthApiSpec + EthTransactions + TraceExt,
{
/// Injects a raw transaction into the node tx pool via RPC server
pub async fn inject_tx(&self, raw_tx: Bytes) -> Result<B256, EthApi::Error> {

View File

@ -60,7 +60,6 @@ reth-tracing.workspace = true
reth-transaction-pool.workspace = true
## ethereum
alloy-network.workspace = true
alloy-primitives.workspace = true
## async

View File

@ -5,7 +5,6 @@
pub mod add_ons;
mod states;
use reth_rpc_types::WithOtherFields;
pub use states::*;
use std::sync::Arc;
@ -30,10 +29,7 @@ use reth_node_core::{
dirs::{ChainPath, DataDirPath},
node_config::NodeConfig,
primitives::Head,
rpc::{
eth::{helpers::AddDevSigners, FullEthApiServer},
types::AnyTransactionReceipt,
},
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
};
use reth_primitives::revm_primitives::EnvKzgSettings;
use reth_provider::{providers::BlockchainProvider, ChainSpecProvider, FullProvider};
@ -346,12 +342,7 @@ where
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>
>
+ FullEthApiServer<
NetworkTypes: alloy_network::Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
>
+ FullEthApiServer
+ AddDevSigners
>,
{
@ -497,12 +488,8 @@ where
AO: NodeAddOns<
NodeAdapter<RethFullAdapter<DB, T>, CB::Components>,
EthApi: EthApiBuilderProvider<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>
+ FullEthApiServer<
NetworkTypes: alloy_network::Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
> + AddDevSigners,
+ FullEthApiServer
+ AddDevSigners,
>,
{
/// Launches the node with the [`DefaultNodeLauncher`] that sets up engine API consensus and rpc

View File

@ -24,17 +24,14 @@ use reth_node_core::{
dirs::{ChainPath, DataDirPath},
exit::NodeExitFuture,
primitives::Head,
rpc::{
eth::{helpers::AddDevSigners, FullEthApiServer},
types::AnyTransactionReceipt,
},
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA},
};
use reth_node_events::{cl::ConsensusLayerHealthEvents, node};
use reth_payload_primitives::PayloadBuilder;
use reth_provider::providers::BlockchainProvider2;
use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
use reth_rpc_types::{engine::ClientVersionV1, WithOtherFields};
use reth_rpc_types::engine::ClientVersionV1;
use reth_tasks::TaskExecutor;
use reth_tokio_util::EventSender;
use reth_tracing::tracing::{debug, error, info};
@ -81,12 +78,8 @@ where
AO: NodeAddOns<
NodeAdapter<T, CB::Components>,
EthApi: EthApiBuilderProvider<NodeAdapter<T, CB::Components>>
+ FullEthApiServer<
NetworkTypes: alloy_network::Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
> + AddDevSigners,
+ FullEthApiServer
+ AddDevSigners,
>,
{
type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;

View File

@ -28,17 +28,14 @@ use reth_node_api::{
use reth_node_core::{
dirs::{ChainPath, DataDirPath},
exit::NodeExitFuture,
rpc::{
eth::{helpers::AddDevSigners, FullEthApiServer},
types::AnyTransactionReceipt,
},
rpc::eth::{helpers::AddDevSigners, FullEthApiServer},
version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA},
};
use reth_node_events::{cl::ConsensusLayerHealthEvents, node};
use reth_primitives::format_ether;
use reth_provider::providers::BlockchainProvider;
use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
use reth_rpc_types::{engine::ClientVersionV1, WithOtherFields};
use reth_rpc_types::engine::ClientVersionV1;
use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::TransactionPool;
@ -55,13 +52,14 @@ use crate::{
};
/// Alias for [`reth_rpc_eth_types::EthApiBuilderCtx`], adapter for [`FullNodeComponents`].
pub type EthApiBuilderCtx<N> = reth_rpc_eth_types::EthApiBuilderCtx<
pub type EthApiBuilderCtx<N, Eth> = reth_rpc_eth_types::EthApiBuilderCtx<
<N as FullNodeTypes>::Provider,
<N as FullNodeComponents>::Pool,
<N as FullNodeComponents>::Evm,
<N as FullNodeComponents>::Network,
TaskExecutor,
<N as FullNodeTypes>::Provider,
Eth,
>;
/// A general purpose trait that launches a new node of any kind.
@ -114,12 +112,8 @@ where
AO: NodeAddOns<
NodeAdapter<T, CB::Components>,
EthApi: EthApiBuilderProvider<NodeAdapter<T, CB::Components>>
+ FullEthApiServer<
NetworkTypes: alloy_network::Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
> + AddDevSigners,
+ FullEthApiServer
+ AddDevSigners,
>,
{
type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;

View File

@ -15,7 +15,6 @@ use reth_node_core::{
rpc::{
api::EngineApiServer,
eth::{EthApiTypes, FullEthApiServer},
types::AnyTransactionReceipt,
},
};
use reth_payload_builder::PayloadBuilderHandle;
@ -25,7 +24,6 @@ use reth_rpc_builder::{
RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules,
};
use reth_rpc_layer::JwtSecret;
use reth_rpc_types::WithOtherFields;
use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, info};
@ -305,13 +303,7 @@ pub async fn launch_rpc_servers<Node, Engine, EthApi>(
where
Node: FullNodeComponents<Types: NodeTypesWithDB<ChainSpec = ChainSpec>> + Clone,
Engine: EngineApiServer<<Node::Types as NodeTypesWithEngine>::Engine>,
EthApi: EthApiBuilderProvider<Node>
+ FullEthApiServer<
NetworkTypes: alloy_network::Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
>,
EthApi: EthApiBuilderProvider<Node> + FullEthApiServer,
{
let auth_config = config.rpc.auth_server_config(jwt_secret)?;
let module_config = config.rpc.transport_rpc_module_config();
@ -386,15 +378,15 @@ where
pub trait EthApiBuilderProvider<N: FullNodeComponents>: BuilderProvider<N> + EthApiTypes {
/// Returns the eth api builder.
#[allow(clippy::type_complexity)]
fn eth_api_builder() -> Box<dyn Fn(&EthApiBuilderCtx<N>) -> Self + Send>;
fn eth_api_builder() -> Box<dyn Fn(&EthApiBuilderCtx<N, Self>) -> Self + Send>;
}
impl<N, F> EthApiBuilderProvider<N> for F
where
N: FullNodeComponents,
for<'a> F: BuilderProvider<N, Ctx<'a> = &'a EthApiBuilderCtx<N>> + EthApiTypes,
for<'a> F: BuilderProvider<N, Ctx<'a> = &'a EthApiBuilderCtx<N, Self>> + EthApiTypes,
{
fn eth_api_builder() -> Box<dyn Fn(&EthApiBuilderCtx<N>) -> Self + Send> {
fn eth_api_builder() -> Box<dyn Fn(&EthApiBuilderCtx<N, Self>) -> Self + Send> {
F::builder()
}
}

View File

@ -48,6 +48,7 @@ serde_json.workspace = true
# misc
thiserror.workspace = true
tracing.workspace = true
derive_more.workspace = true
[dev-dependencies]
reth-optimism-chainspec.workspace = true

View File

@ -1,24 +1,26 @@
//! Loads and formats OP block RPC response.
use reth_chainspec::ChainSpec;
use op_alloy_network::Network;
use op_alloy_rpc_types::OpTransactionReceipt;
use reth_chainspec::{ChainSpec, ChainSpecProvider};
use reth_node_api::{FullNodeComponents, NodeTypes};
use reth_primitives::TransactionMeta;
use reth_provider::{BlockReaderIdExt, HeaderProvider};
use reth_rpc_eth_api::{
helpers::{
EthApiSpec, EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, LoadTransaction,
SpawnBlocking,
},
FromEthApiError,
helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking},
RpcReceipt,
};
use reth_rpc_eth_types::{EthStateCache, ReceiptBuilder};
use reth_rpc_types::{AnyTransactionReceipt, BlockId};
use reth_rpc_eth_types::EthStateCache;
use reth_rpc_types::BlockId;
use crate::{OpEthApi, OpEthApiError};
use crate::{OpEthApi, OpEthApiError, OpReceiptBuilder};
impl<N> EthBlocks for OpEthApi<N>
where
Self: EthApiSpec + LoadBlock<Error = OpEthApiError> + LoadTransaction,
Self: LoadBlock<
Error = OpEthApiError,
NetworkTypes: Network<ReceiptResponse = OpTransactionReceipt>,
>,
N: FullNodeComponents<Types: NodeTypes<ChainSpec = ChainSpec>>,
{
#[inline]
@ -29,7 +31,7 @@ where
async fn block_receipts(
&self,
block_id: BlockId,
) -> Result<Option<Vec<AnyTransactionReceipt>>, Self::Error>
) -> Result<Option<Vec<RpcReceipt<Self::NetworkTypes>>>, Self::Error>
where
Self: LoadReceipt,
{
@ -44,7 +46,7 @@ where
let l1_block_info =
reth_evm_optimism::extract_l1_info(&block).map_err(OpEthApiError::from)?;
let receipts = block
return block
.body
.into_iter()
.zip(receipts.iter())
@ -60,16 +62,18 @@ where
timestamp,
};
let op_tx_meta =
self.build_op_receipt_meta(tx, l1_block_info.clone(), receipt)?;
Ok(ReceiptBuilder::new(tx, meta, receipt, &receipts)
.map_err(Self::Error::from_eth_err)?
.add_other_fields(op_tx_meta.into())
.build())
Ok(OpReceiptBuilder::new(
&self.inner.provider().chain_spec(),
tx,
meta,
receipt,
&receipts,
l1_block_info.clone(),
)?
.build())
})
.collect::<Result<Vec<_>, Self::Error>>();
return receipts.map(Some)
.collect::<Result<Vec<_>, Self::Error>>()
.map(Some)
}
Ok(None)

View File

@ -12,7 +12,8 @@ pub use receipt::{OpReceiptBuilder, OpReceiptFieldsBuilder};
use std::{fmt, sync::Arc};
use alloy_primitives::U256;
use op_alloy_network::AnyNetwork;
use derive_more::Deref;
use op_alloy_network::Optimism;
use reth_chainspec::ChainSpec;
use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
@ -20,8 +21,8 @@ use reth_node_api::{BuilderProvider, FullNodeComponents, FullNodeTypes, NodeType
use reth_node_builder::EthApiBuilderCtx;
use reth_primitives::Header;
use reth_provider::{
BlockIdReader, BlockNumReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider,
HeaderProvider, StageCheckpointReader, StateProviderFactory,
BlockIdReader, BlockNumReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider,
StageCheckpointReader, StateProviderFactory,
};
use reth_rpc::eth::{core::EthApiInner, DevSigner};
use reth_rpc_eth_api::{
@ -39,7 +40,7 @@ use reth_tasks::{
use reth_transaction_pool::TransactionPool;
use tokio::sync::OnceCell;
use crate::{OpEthApiError, SequencerClient};
use crate::{OpEthApiError, OpTxBuilder, SequencerClient};
/// Adapter for [`EthApiInner`], which holds all the data required to serve core `eth_` API.
pub type EthApiNodeBackend<N> = EthApiInner<
@ -59,24 +60,20 @@ pub type EthApiNodeBackend<N> = EthApiInner<
///
/// This type implements the [`FullEthApi`](reth_rpc_eth_api::helpers::FullEthApi) by implemented
/// all the `Eth` helper traits and prerequisite traits.
#[derive(Clone)]
#[derive(Clone, Deref)]
pub struct OpEthApi<N: FullNodeComponents> {
/// Gateway to node's core components.
#[deref]
inner: Arc<EthApiNodeBackend<N>>,
/// Sequencer client, configured to forward submitted transactions to sequencer of given OP
/// network.
sequencer_client: OnceCell<SequencerClient>,
}
impl<N> OpEthApi<N>
where
N: FullNodeComponents<
Provider: BlockReaderIdExt + ChainSpecProvider + CanonStateSubscriptions + Clone + 'static,
>,
{
impl<N: FullNodeComponents> OpEthApi<N> {
/// Creates a new instance for given context.
#[allow(clippy::type_complexity)]
pub fn with_spawner(ctx: &EthApiBuilderCtx<N>) -> Self {
pub fn with_spawner(ctx: &EthApiBuilderCtx<N, Self>) -> Self {
let blocking_task_pool =
BlockingTaskPool::build().expect("failed to build blocking task pool");
@ -106,7 +103,8 @@ where
N: FullNodeComponents,
{
type Error = OpEthApiError;
type NetworkTypes = AnyNetwork;
type NetworkTypes = Optimism;
type TransactionCompat = OpTxBuilder;
}
impl<N> EthApiSpec for OpEthApi<N>
@ -189,7 +187,7 @@ where
impl<N> LoadState for OpEthApi<N>
where
Self: Send + Sync,
Self: Send + Sync + Clone,
N: FullNodeComponents<Types: NodeTypes<ChainSpec = ChainSpec>>,
{
#[inline]
@ -237,7 +235,10 @@ where
}
}
impl<N: FullNodeComponents<Types: NodeTypes<ChainSpec = ChainSpec>>> AddDevSigners for OpEthApi<N> {
impl<N> AddDevSigners for OpEthApi<N>
where
N: FullNodeComponents<Types: NodeTypes<ChainSpec = ChainSpec>>,
{
fn with_dev_accounts(&self) {
*self.signers().write() = DevSigner::random_signers(20)
}
@ -248,7 +249,7 @@ where
Self: Send,
N: FullNodeComponents,
{
type Ctx<'a> = &'a EthApiBuilderCtx<N>;
type Ctx<'a> = &'a EthApiBuilderCtx<N, Self>;
fn builder() -> Box<dyn for<'a> Fn(Self::Ctx<'a>) -> Self + Send> {
Box::new(Self::with_spawner)

View File

@ -9,18 +9,15 @@ use reth_evm_optimism::RethL1BlockInfo;
use reth_node_api::{FullNodeComponents, NodeTypes};
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned, TxType};
use reth_provider::ChainSpecProvider;
use reth_rpc_eth_api::{
helpers::{EthApiSpec, LoadReceipt, LoadTransaction},
FromEthApiError,
};
use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt};
use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder};
use reth_rpc_types::{AnyReceiptEnvelope, AnyTransactionReceipt, Log, TransactionReceipt};
use reth_rpc_types::{AnyReceiptEnvelope, Log, TransactionReceipt};
use crate::{OpEthApi, OpEthApiError};
impl<N> LoadReceipt for OpEthApi<N>
where
Self: EthApiSpec + LoadTransaction<Error = OpEthApiError>,
Self: Send + Sync,
N: FullNodeComponents<Types: NodeTypes<ChainSpec = ChainSpec>>,
{
#[inline]
@ -33,7 +30,7 @@ where
tx: TransactionSigned,
meta: TransactionMeta,
receipt: Receipt,
) -> Result<AnyTransactionReceipt, Self::Error> {
) -> Result<RpcReceipt<Self::NetworkTypes>, Self::Error> {
let (block, receipts) = LoadReceipt::cache(self)
.get_block_and_receipts(meta.block_hash)
.await
@ -46,16 +43,15 @@ where
let l1_block_info =
reth_evm_optimism::extract_l1_info(&block).map_err(OpEthApiError::from)?;
let op_receipt_meta = self
.build_op_receipt_meta(&tx, l1_block_info, &receipt)
.map_err(OpEthApiError::from)?;
let receipt_resp = ReceiptBuilder::new(&tx, meta, &receipt, &receipts)
.map_err(Self::Error::from_eth_err)?
.add_other_fields(op_receipt_meta.into())
.build();
Ok(receipt_resp)
Ok(OpReceiptBuilder::new(
&self.inner.provider().chain_spec(),
&tx,
meta,
&receipt,
&receipts,
l1_block_info,
)?
.build())
}
}

View File

@ -1,13 +1,17 @@
//! Loads and formats OP transaction RPC response.
use alloy_primitives::{Bytes, B256};
use op_alloy_rpc_types::Transaction;
use reth_node_api::FullNodeComponents;
use reth_primitives::TransactionSignedEcRecovered;
use reth_provider::{BlockReaderIdExt, TransactionsProvider};
use reth_rpc::eth::EthTxBuilder;
use reth_rpc_eth_api::{
helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking},
FromEthApiError,
FromEthApiError, FullEthApiTypes, TransactionCompat,
};
use reth_rpc_eth_types::{utils::recover_raw_transaction, EthStateCache};
use reth_rpc_types::TransactionInfo;
use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool};
use crate::{OpEthApi, SequencerClient};
@ -54,7 +58,7 @@ where
impl<N> LoadTransaction for OpEthApi<N>
where
Self: SpawnBlocking,
Self: SpawnBlocking + FullEthApiTypes,
N: FullNodeComponents,
{
type Pool = N::Pool;
@ -89,3 +93,34 @@ where
self.sequencer_client.get().cloned()
}
}
/// Builds OP transaction response type.
#[derive(Clone, Debug, Copy)]
pub struct OpTxBuilder;
impl TransactionCompat for OpTxBuilder {
type Transaction = Transaction;
fn fill(tx: TransactionSignedEcRecovered, tx_info: TransactionInfo) -> Self::Transaction {
let signed_tx = tx.clone().into_signed();
let inner = EthTxBuilder::fill(tx, tx_info).inner;
Transaction {
inner,
source_hash: signed_tx.source_hash(),
mint: signed_tx.mint(),
// only include is_system_tx if true: <https://github.com/ethereum-optimism/op-geth/blob/641e996a2dcf1f81bac9416cb6124f86a69f1de7/internal/ethapi/api.go#L1518-L1518>
is_system_tx: signed_tx.is_deposit().then_some(signed_tx.is_system_transaction()),
deposit_receipt_version: None, // todo: how to fill this field?
}
}
fn otterscan_api_truncate_input(tx: &mut Self::Transaction) {
tx.inner.input = tx.inner.input.slice(..4);
}
fn tx_type(tx: &Self::Transaction) -> u8 {
tx.inner.transaction_type.unwrap_or_default()
}
}

View File

@ -15,5 +15,5 @@ pub mod eth;
pub mod sequencer;
pub use error::{OpEthApiError, OptimismInvalidTransactionError, SequencerClientError};
pub use eth::OpEthApi;
pub use eth::{transaction::OpTxBuilder, OpEthApi, OpReceiptBuilder};
pub use sequencer::SequencerClient;

View File

@ -1,6 +1,6 @@
use alloy_eips::{BlockId, BlockNumberOrTag};
use alloy_primitives::{Address, Bytes, B256};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_primitives::{BlockId, BlockNumberOrTag};
use reth_rpc_types::{
debug::ExecutionWitness,
trace::geth::{

View File

@ -1,3 +1,4 @@
use alloy_json_rpc::RpcObject;
use alloy_primitives::{Address, Bytes, TxHash, B256};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_primitives::BlockId;
@ -6,13 +7,13 @@ use reth_rpc_types::{
BlockDetails, ContractCreator, InternalOperation, OtsBlockTransactions, TraceEntry,
TransactionsWithReceipts,
},
Header, Transaction, WithOtherFields,
Header,
};
/// Otterscan rpc interface.
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "ots"))]
#[cfg_attr(feature = "client", rpc(server, client, namespace = "ots"))]
pub trait Otterscan {
pub trait Otterscan<T: RpcObject> {
/// Get the block header by block number, required by otterscan.
/// Otterscan currently requires this endpoint, used as:
///
@ -62,7 +63,7 @@ pub trait Otterscan {
block_number: u64,
page_number: usize,
page_size: usize,
) -> RpcResult<OtsBlockTransactions<WithOtherFields<Transaction>>>;
) -> RpcResult<OtsBlockTransactions<T>>;
/// Gets paginated inbound/outbound transaction calls for a certain address.
#[method(name = "searchTransactionsBefore")]

View File

@ -1,14 +1,12 @@
use alloy_json_rpc::RpcObject;
use alloy_primitives::Address;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_rpc_types::{
txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolStatus},
Transaction, WithOtherFields,
};
use reth_rpc_types::txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolStatus};
/// Txpool rpc interface.
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "txpool"))]
#[cfg_attr(feature = "client", rpc(server, client, namespace = "txpool"))]
pub trait TxPoolApi {
pub trait TxPoolApi<T: RpcObject> {
/// Returns the number of transactions currently pending for inclusion in the next block(s), as
/// well as the ones that are being scheduled for future execution only.
///
@ -28,15 +26,12 @@ pub trait TxPoolApi {
///
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_contentFrom) for more details
#[method(name = "contentFrom")]
async fn txpool_content_from(
&self,
from: Address,
) -> RpcResult<TxpoolContentFrom<WithOtherFields<Transaction>>>;
async fn txpool_content_from(&self, from: Address) -> RpcResult<TxpoolContentFrom<T>>;
/// Returns the details of all transactions currently pending for inclusion in the next
/// block(s), as well as the ones that are being scheduled for future execution only.
///
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details
#[method(name = "content")]
async fn txpool_content(&self) -> RpcResult<TxpoolContent<WithOtherFields<Transaction>>>;
async fn txpool_content(&self) -> RpcResult<TxpoolContent<T>>;
}

View File

@ -62,11 +62,11 @@ reth-provider = { workspace = true, features = ["test-utils"] }
reth-rpc-api = { workspace = true, features = ["client"] }
reth-rpc-engine-api.workspace = true
reth-rpc-types.workspace = true
reth-rpc-types-compat.workspace = true
reth-tracing.workspace = true
reth-transaction-pool = { workspace = true, features = ["test-utils"] }
reth-tokio-util.workspace = true
reth-node-api.workspace = true
reth-rpc-types-compat.workspace = true
alloy-primitives.workspace = true

View File

@ -1,30 +1,37 @@
use std::marker::PhantomData;
use reth_evm::ConfigureEvm;
use reth_primitives::Header;
use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory};
use reth_rpc::{EthFilter, EthPubSub};
use reth_rpc_eth_api::EthApiTypes;
use reth_rpc_eth_types::{
cache::cache_new_blocks_task, EthApiBuilderCtx, EthConfig, EthStateCache,
};
use reth_tasks::TaskSpawner;
/// Alias for `eth` namespace API builder.
pub type DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi> =
Box<dyn Fn(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>) -> EthApi>;
pub type DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi> = Box<
dyn Fn(&EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>) -> EthApi,
>;
/// Handlers for core, filter and pubsub `eth` namespace APIs.
#[derive(Debug, Clone)]
pub struct EthHandlers<Provider, Pool, Network, Events, EthApi> {
pub struct EthHandlers<Provider, Pool, Network, Events, EthApi: EthApiTypes> {
/// Main `eth_` request handler
pub api: EthApi,
/// The async caching layer used by the eth handlers
pub cache: EthStateCache,
/// Polling based filter handler available on all transports
pub filter: EthFilter<Provider, Pool>,
pub filter: EthFilter<Provider, Pool, EthApi>,
/// Handler for subscriptions only available for transports that support it (ws, ipc)
pub pubsub: EthPubSub<Provider, Pool, Events, Network>,
pub pubsub: EthPubSub<Provider, Pool, Events, Network, EthApi>,
}
impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Network, Events, EthApi> {
impl<Provider, Pool, Network, Events, EthApi> EthHandlers<Provider, Pool, Network, Events, EthApi>
where
EthApi: EthApiTypes,
{
/// Returns a new [`EthHandlers`] builder.
#[allow(clippy::too_many_arguments)]
pub fn builder<EvmConfig, Tasks>(
@ -80,7 +87,7 @@ where
Network: Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
EthApi: 'static,
EthApi: EthApiTypes + 'static,
{
/// Returns a new instance with handlers for `eth` namespace.
pub fn build(self) -> EthHandlers<Provider, Pool, Network, Events, EthApi> {
@ -112,6 +119,7 @@ where
executor,
events,
cache,
_rpc_ty_builders: PhantomData,
};
let api = eth_api_builder(&ctx);
@ -130,13 +138,14 @@ pub struct EthFilterApiBuilder;
impl EthFilterApiBuilder {
/// Builds the [`EthFilterApiServer`](reth_rpc_eth_api::EthFilterApiServer), for given context.
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> EthFilter<Provider, Pool>
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>,
) -> EthFilter<Provider, Pool, Eth>
where
Provider: Send + Sync + Clone + 'static,
Pool: Send + Sync + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
Eth: EthApiTypes + 'static,
{
EthFilter::new(
ctx.provider.clone(),
@ -154,15 +163,16 @@ pub struct EthPubSubApiBuilder;
impl EthPubSubApiBuilder {
/// Builds the [`EthPubSubApiServer`](reth_rpc_eth_api::EthPubSubApiServer), for given context.
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
) -> EthPubSub<Provider, Pool, Events, Network>
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>,
) -> EthPubSub<Provider, Pool, Events, Network, Eth>
where
Provider: Clone,
Pool: Clone,
Events: Clone,
Network: Clone,
Tasks: TaskSpawner + Clone + 'static,
Eth: EthApiTypes + 'static,
{
EthPubSub::with_spawner(
ctx.provider.clone(),

View File

@ -168,11 +168,10 @@ use reth_rpc::{
use reth_rpc_api::servers::*;
use reth_rpc_eth_api::{
helpers::{Call, EthApiSpec, EthTransactions, LoadPendingBlock, TraceExt},
EthApiServer, EthApiTypes, FullEthApiServer, RpcReceipt,
EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcReceipt, RpcTransaction,
};
use reth_rpc_eth_types::{EthConfig, EthStateCache, EthSubscriptionIdProvider};
use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret};
use reth_rpc_types::WithOtherFields;
use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool};
use serde::{Deserialize, Serialize};
@ -210,7 +209,6 @@ pub use eth::EthHandlers;
// Rpc server metrics
mod metrics;
pub use metrics::{MeteredRequestFuture, RpcRequestMetricsService};
use reth_node_core::rpc::types::AnyTransactionReceipt;
/// Convenience function for starting a server in one step.
#[allow(clippy::too_many_arguments)]
@ -231,10 +229,8 @@ where
Network: NetworkInfo + Peers + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
EvmConfig: ConfigureEvm<Header = Header>,
EthApi: FullEthApiServer<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
>,
EvmConfig: ConfigureEvm<Header = reth_primitives::Header>,
EthApi: FullEthApiServer,
{
let module_config = module_config.into();
server_config
@ -441,9 +437,7 @@ where
where
EngineT: EngineTypes,
EngineApi: EngineApiServer<EngineT>,
EthApi: FullEthApiServer<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
>,
EthApi: FullEthApiServer,
{
let Self { provider, pool, network, executor, events, evm_config } = self;
@ -496,7 +490,7 @@ where
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi>
where
EthApi: 'static,
EthApi: EthApiTypes + 'static,
{
let Self { provider, pool, network, executor, events, evm_config } = self;
RpcRegistryInner::new(provider, pool, network, executor, events, config, evm_config, eth)
@ -510,9 +504,7 @@ where
eth: DynEthApiBuilder<Provider, Pool, EvmConfig, Network, Tasks, Events, EthApi>,
) -> TransportRpcModules<()>
where
EthApi: FullEthApiServer<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
>,
EthApi: FullEthApiServer,
{
let mut modules = TransportRpcModules::default();
@ -618,7 +610,7 @@ impl RpcModuleConfigBuilder {
/// A Helper type the holds instances of the configured modules.
#[derive(Debug, Clone)]
pub struct RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi> {
pub struct RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi: EthApiTypes> {
provider: Provider,
pool: Pool,
network: Network,
@ -642,7 +634,7 @@ where
Network: Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
EthApi: 'static,
EthApi: EthApiTypes + 'static,
{
/// Creates a new, empty instance.
#[allow(clippy::too_many_arguments)]
@ -696,6 +688,8 @@ where
impl<Provider, Pool, Network, Tasks, Events, EthApi>
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi>
where
EthApi: EthApiTypes,
{
/// Returns a reference to the installed [`EthApi`](reth_rpc::eth::EthApi).
pub const fn eth_api(&self) -> &EthApi {
@ -754,6 +748,7 @@ impl<Provider, Pool, Network, Tasks, Events, EthApi>
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi>
where
Network: NetworkInfo + Clone + 'static,
EthApi: EthApiTypes,
Provider: ChainSpecProvider<ChainSpec = ChainSpec>,
{
/// Instantiates `AdminApi`
@ -793,23 +788,18 @@ where
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
Network: NetworkInfo + Peers + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
EthApi: Clone,
EthApi: EthApiServer<
RpcTransaction<EthApi::NetworkTypes>,
RpcBlock<EthApi::NetworkTypes>,
RpcReceipt<EthApi::NetworkTypes>,
> + EthApiTypes,
{
/// Register Eth Namespace
///
/// # Panics
///
/// If called outside of the tokio runtime. See also [`Self::eth_api`]
pub fn register_eth(&mut self) -> &mut Self
where
EthApi: EthApiServer<
reth_rpc_types::Transaction,
reth_rpc_types::Block,
RpcReceipt<EthApi::NetworkTypes>,
> + EthApiTypes<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
>,
{
pub fn register_eth(&mut self) -> &mut Self {
let eth_api = self.eth_api().clone();
self.modules.insert(RethRpcModule::Eth, eth_api.into_rpc().into());
self
@ -822,14 +812,14 @@ where
/// If called outside of the tokio runtime. See also [`Self::eth_api`]
pub fn register_ots(&mut self) -> &mut Self
where
EthApi: EthApiServer<
WithOtherFields<reth_rpc_types::Transaction>,
reth_rpc_types::Block<WithOtherFields<reth_rpc_types::Transaction>>,
RpcReceipt<EthApi::NetworkTypes>,
> + EthApiTypes<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
> + TraceExt
+ EthTransactions,
EthApi: TraceExt
+ EthTransactions<
NetworkTypes: alloy_network::Network<
TransactionResponse = reth_rpc_types::WithOtherFields<
reth_rpc_types::Transaction,
>,
>,
>,
{
let otterscan_api = self.otterscan_api();
self.modules.insert(RethRpcModule::Ots, otterscan_api.into_rpc().into());
@ -893,6 +883,25 @@ where
self
}
/// Instantiates `OtterscanApi`
///
/// # Panics
///
/// If called outside of the tokio runtime. See also [`Self::eth_api`]
pub fn otterscan_api(&self) -> OtterscanApi<EthApi> {
let eth_api = self.eth_api().clone();
OtterscanApi::new(eth_api)
}
}
impl<Provider, Pool, Network, Tasks, Events, EthApi>
RpcRegistryInner<Provider, Pool, Network, Tasks, Events, EthApi>
where
Provider: FullRpcProvider + AccountReader + ChangeSetReader,
Network: NetworkInfo + Peers + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
EthApi: EthApiTypes,
{
/// Instantiates `TraceApi`
///
/// # Panics
@ -922,26 +931,6 @@ where
EthBundle::new(eth_api, self.blocking_pool_guard.clone())
}
/// Instantiates `OtterscanApi`
///
/// # Panics
///
/// If called outside of the tokio runtime. See also [`Self::eth_api`]
pub fn otterscan_api(&self) -> OtterscanApi<EthApi>
where
EthApi: EthApiServer<
WithOtherFields<reth_rpc_types::Transaction>,
reth_rpc_types::Block<WithOtherFields<reth_rpc_types::Transaction>>,
RpcReceipt<EthApi::NetworkTypes>,
> + EthApiTypes<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
> + TraceExt
+ EthTransactions,
{
let eth_api = self.eth_api().clone();
OtterscanApi::new(eth_api)
}
/// Instantiates `DebugApi`
///
/// # Panics
@ -982,9 +971,7 @@ where
Network: NetworkInfo + Peers + Clone + 'static,
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
EthApi: FullEthApiServer<
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
>,
EthApi: FullEthApiServer,
{
/// Configures the auth module that includes the
/// * `engine_` namespace
@ -1109,7 +1096,7 @@ where
.into(),
RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
RethRpcModule::Txpool => {
TxPoolApi::new(self.pool.clone()).into_rpc().into()
TxPoolApi::<_, EthApi>::new(self.pool.clone()).into_rpc().into()
}
RethRpcModule::Rpc => RPCApi::new(
namespaces

View File

@ -398,45 +398,69 @@ where
let nonce = 1;
let block_hash = B256::default();
OtterscanClient::get_header_by_number(client, block_number).await.unwrap();
OtterscanClient::<Transaction>::get_header_by_number(client, block_number).await.unwrap();
OtterscanClient::has_code(client, address, None).await.unwrap();
OtterscanClient::has_code(client, address, Some(block_number.into())).await.unwrap();
OtterscanClient::get_api_level(client).await.unwrap();
OtterscanClient::get_internal_operations(client, tx_hash).await.unwrap();
OtterscanClient::get_transaction_error(client, tx_hash).await.unwrap();
OtterscanClient::trace_transaction(client, tx_hash).await.unwrap();
OtterscanClient::get_block_details(client, block_number).await.unwrap_err();
OtterscanClient::get_block_details_by_hash(client, block_hash).await.unwrap_err();
OtterscanClient::get_block_transactions(client, block_number, page_number, page_size)
OtterscanClient::<Transaction>::has_code(client, address, None).await.unwrap();
OtterscanClient::<Transaction>::has_code(client, address, Some(block_number.into()))
.await
.err()
.unwrap();
OtterscanClient::<Transaction>::get_api_level(client).await.unwrap();
OtterscanClient::<Transaction>::get_internal_operations(client, tx_hash).await.unwrap();
OtterscanClient::<Transaction>::get_transaction_error(client, tx_hash).await.unwrap();
OtterscanClient::<Transaction>::trace_transaction(client, tx_hash).await.unwrap();
OtterscanClient::<Transaction>::get_block_details(client, block_number).await.unwrap_err();
OtterscanClient::<Transaction>::get_block_details_by_hash(client, block_hash)
.await
.unwrap_err();
OtterscanClient::<Transaction>::get_block_transactions(
client,
block_number,
page_number,
page_size,
)
.await
.err()
.unwrap();
assert!(is_unimplemented(
OtterscanClient::search_transactions_before(client, address, block_number, page_size,)
.await
.err()
.unwrap()
));
assert!(is_unimplemented(
OtterscanClient::search_transactions_after(client, address, block_number, page_size,)
.await
.err()
.unwrap()
));
assert!(OtterscanClient::get_transaction_by_sender_and_nonce(client, sender, nonce)
OtterscanClient::<Transaction>::search_transactions_before(
client,
address,
block_number,
page_size,
)
.await
.err()
.unwrap()
));
assert!(is_unimplemented(
OtterscanClient::<Transaction>::search_transactions_after(
client,
address,
block_number,
page_size,
)
.await
.err()
.unwrap()
));
assert!(OtterscanClient::<Transaction>::get_transaction_by_sender_and_nonce(
client, sender, nonce
)
.await
.err()
.is_none());
assert!(OtterscanClient::<Transaction>::get_contract_creator(client, address)
.await
.unwrap()
.is_none());
assert!(OtterscanClient::get_contract_creator(client, address).await.unwrap().is_none());
}
#[tokio::test(flavor = "multi_thread")]

View File

@ -2,7 +2,6 @@
//! the `eth_` namespace.
use alloy_dyn_abi::TypedData;
use alloy_json_rpc::RpcObject;
use alloy_network::Network;
use alloy_primitives::{Address, Bytes, B256, B64, U256, U64};
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_primitives::{transaction::AccessListResult, BlockId, BlockNumberOrTag};
@ -11,8 +10,8 @@ use reth_rpc_types::{
serde_helpers::JsonStorageKey,
simulate::{SimulatePayload, SimulatedBlock},
state::{EvmOverrides, StateOverride},
AnyTransactionReceipt, BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse,
FeeHistory, Header, Index, StateContext, SyncStatus, TransactionRequest, Work,
BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header,
Index, StateContext, SyncStatus, TransactionRequest, Work,
};
use tracing::trace;
@ -368,7 +367,7 @@ impl<T>
RpcReceipt<T::NetworkTypes>,
> for T
where
T: FullEthApi<NetworkTypes: Network<ReceiptResponse = AnyTransactionReceipt>>,
T: FullEthApi,
jsonrpsee_types::error::ErrorObject<'static>: From<T::Error>,
{
/// Handler for: `eth_protocolVersion`
@ -499,7 +498,9 @@ where
hash: B256,
) -> RpcResult<Option<RpcTransaction<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash");
Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into))
Ok(EthTransactions::transaction_by_hash(self, hash)
.await?
.map(|tx| tx.into_transaction::<T::TransactionCompat>()))
}
/// Handler for: `eth_getRawTransactionByBlockHashAndIndex`

View File

@ -6,10 +6,10 @@ use futures::Future;
use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders};
use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider};
use reth_rpc_eth_types::{EthApiError, EthStateCache};
use reth_rpc_types::{AnyTransactionReceipt, Header, Index};
use reth_rpc_types::{Header, Index};
use reth_rpc_types_compat::block::{from_block, uncle_block_from_header};
use crate::{FromEthApiError, RpcBlock};
use crate::{FromEthApiError, FullEthApiTypes, RpcBlock, RpcReceipt};
use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking};
@ -25,7 +25,10 @@ pub trait EthBlocks: LoadBlock {
fn rpc_block_header(
&self,
block_id: BlockId,
) -> impl Future<Output = Result<Option<Header>, Self::Error>> + Send {
) -> impl Future<Output = Result<Option<Header>, Self::Error>> + Send
where
Self: FullEthApiTypes,
{
async move { Ok(self.rpc_block(block_id, false).await?.map(|block| block.header)) }
}
@ -38,6 +41,8 @@ pub trait EthBlocks: LoadBlock {
block_id: BlockId,
full: bool,
) -> impl Future<Output = Result<Option<RpcBlock<Self::NetworkTypes>>, Self::Error>> + Send
where
Self: FullEthApiTypes,
{
async move {
let Some(block) = self.block_with_senders(block_id).await? else { return Ok(None) };
@ -46,8 +51,13 @@ pub trait EthBlocks: LoadBlock {
.header_td_by_number(block.number)
.map_err(Self::Error::from_eth_err)?
.ok_or(EthApiError::HeaderNotFound(block_id))?;
let block = from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash))
.map_err(Self::Error::from_eth_err)?;
let block = from_block::<Self::TransactionCompat>(
block.unseal(),
total_difficulty,
full.into(),
Some(block_hash),
)
.map_err(Self::Error::from_eth_err)?;
Ok(Some(block))
}
}
@ -65,7 +75,7 @@ pub trait EthBlocks: LoadBlock {
return Ok(LoadBlock::provider(self)
.pending_block()
.map_err(Self::Error::from_eth_err)?
.map(|block| block.body.len()))
.map(|block| block.body.len()));
}
let block_hash = match LoadBlock::provider(self)
@ -91,7 +101,7 @@ pub trait EthBlocks: LoadBlock {
fn block_receipts(
&self,
block_id: BlockId,
) -> impl Future<Output = Result<Option<Vec<AnyTransactionReceipt>>, Self::Error>> + Send
) -> impl Future<Output = Result<Option<Vec<RpcReceipt<Self::NetworkTypes>>>, Self::Error>> + Send
where
Self: LoadReceipt;

View File

@ -1,7 +1,9 @@
//! Loads a pending block from database. Helper trait for `eth_` transaction, call and trace RPC
//! methods.
use crate::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError};
use crate::{
AsEthApiError, FromEthApiError, FromEvmError, FullEthApiTypes, IntoEthApiError, RpcBlock,
};
use alloy_primitives::{Bytes, TxKind, B256, U256};
use futures::Future;
use reth_chainspec::MIN_TRANSACTION_GAS;
@ -31,8 +33,7 @@ use reth_rpc_server_types::constants::gas_oracle::{CALL_STIPEND_GAS, ESTIMATE_GA
use reth_rpc_types::{
simulate::{SimBlock, SimulatePayload, SimulatedBlock},
state::{EvmOverrides, StateOverride},
Block, BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo, TransactionRequest,
WithOtherFields,
BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo, TransactionRequest,
};
use revm::{Database, DatabaseCommit, GetInspector};
use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
@ -61,14 +62,10 @@ pub trait EthCall: Call + LoadPendingBlock {
&self,
payload: SimulatePayload,
block: Option<BlockId>,
) -> impl Future<
Output = Result<
Vec<SimulatedBlock<Block<WithOtherFields<reth_rpc_types::Transaction>>>>,
Self::Error,
>,
> + Send
) -> impl Future<Output = Result<Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>>, Self::Error>>
+ Send
where
Self: LoadBlock,
Self: LoadBlock + FullEthApiTypes,
{
async move {
if payload.block_state_calls.len() > self.max_simulate_blocks() as usize {
@ -108,9 +105,8 @@ pub trait EthCall: Call + LoadPendingBlock {
let this = self.clone();
self.spawn_with_state_at_block(block, move |state| {
let mut db = CacheDB::new(StateProviderDatabase::new(state));
let mut blocks: Vec<
SimulatedBlock<Block<WithOtherFields<reth_rpc_types::Transaction>>>,
> = Vec::with_capacity(block_state_calls.len());
let mut blocks: Vec<SimulatedBlock<RpcBlock<Self::NetworkTypes>>> =
Vec::with_capacity(block_state_calls.len());
let mut gas_used = 0;
for block in block_state_calls {
// Increase number and timestamp for every new block
@ -191,7 +187,7 @@ pub trait EthCall: Call + LoadPendingBlock {
results.push((env.tx.caller, res.result));
}
let block = simulate::build_block(
let block = simulate::build_block::<Self::TransactionCompat>(
results,
transactions,
&block_env,

View File

@ -152,58 +152,64 @@ pub trait EthFees: LoadFee {
base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default());
} else {
// read the requested header range
let headers = LoadFee::provider(self).sealed_headers_range(start_block..=end_block).map_err(Self::Error::from_eth_err)?;
if headers.len() != block_count as usize {
return Err(EthApiError::InvalidBlockRange.into())
}
// read the requested header range
let headers = LoadFee::provider(self)
.sealed_headers_range(start_block..=end_block)
.map_err(Self::Error::from_eth_err)?;
if headers.len() != block_count as usize {
return Err(EthApiError::InvalidBlockRange.into())
}
for header in &headers {
base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128);
gas_used_ratio.push(header.gas_used as f64 / header.gas_limit as f64);
base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default());
blob_gas_used_ratio.push(
header.blob_gas_used.unwrap_or_default() as f64 /
reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64,
for header in &headers {
base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128);
gas_used_ratio.push(header.gas_used as f64 / header.gas_limit as f64);
base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default());
blob_gas_used_ratio.push(
header.blob_gas_used.unwrap_or_default() as f64
/ reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64,
);
// Percentiles were specified, so we need to collect reward percentile ino
if let Some(percentiles) = &reward_percentiles {
let (transactions, receipts) = LoadFee::cache(self)
.get_transactions_and_receipts(header.hash())
.await
.map_err(Self::Error::from_eth_err)?
.ok_or(EthApiError::InvalidBlockRange)?;
rewards.push(
calculate_reward_percentiles_for_block(
percentiles,
header.gas_used,
header.base_fee_per_gas.unwrap_or_default(),
&transactions,
&receipts,
)
.unwrap_or_default(),
);
}
}
// The spec states that `base_fee_per_gas` "[..] includes the next block after the
// newest of the returned range, because this value can be derived from the
// newest block"
//
// The unwrap is safe since we checked earlier that we got at least 1 header.
let last_header = headers.last().expect("is present");
base_fee_per_gas.push(
LoadFee::provider(self)
.chain_spec()
.base_fee_params_at_timestamp(last_header.timestamp)
.next_block_base_fee(
last_header.gas_used as u128,
last_header.gas_limit as u128,
last_header.base_fee_per_gas.unwrap_or_default() as u128,
),
);
// Percentiles were specified, so we need to collect reward percentile ino
if let Some(percentiles) = &reward_percentiles {
let (transactions, receipts) = LoadFee::cache(self)
.get_transactions_and_receipts(header.hash())
.await.map_err(Self::Error::from_eth_err)?
.ok_or(EthApiError::InvalidBlockRange)?;
rewards.push(
calculate_reward_percentiles_for_block(
percentiles,
header.gas_used,
header.base_fee_per_gas.unwrap_or_default(),
&transactions,
&receipts,
)
.unwrap_or_default(),
);
}
}
// The spec states that `base_fee_per_gas` "[..] includes the next block after the
// newest of the returned range, because this value can be derived from the
// newest block"
//
// The unwrap is safe since we checked earlier that we got at least 1 header.
let last_header = headers.last().expect("is present");
base_fee_per_gas.push(
LoadFee::provider(self).chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee(
last_header.gas_used as u128,
last_header.gas_limit as u128,
last_header.base_fee_per_gas.unwrap_or_default() as u128,
));
// Same goes for the `base_fee_per_blob_gas`:
// > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block.
base_fee_per_blob_gas
.push(last_header.next_block_blob_fee().unwrap_or_default());
};
// Same goes for the `base_fee_per_blob_gas`:
// > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block.
base_fee_per_blob_gas.push(last_header.next_block_blob_fee().unwrap_or_default());
};
Ok(FeeHistory {
base_fee_per_gas,

View File

@ -39,7 +39,7 @@ pub use state::{EthState, LoadState};
pub use trace::Trace;
pub use transaction::{EthTransactions, LoadTransaction};
use crate::EthApiTypes;
use crate::FullEthApiTypes;
/// Extension trait that bundles traits needed for tracing transactions.
pub trait TraceExt:
@ -53,7 +53,7 @@ impl<T> TraceExt for T where T: LoadTransaction + LoadBlock + LoadPendingBlock +
///
/// This trait is automatically implemented for any type that implements all the `Eth` traits.
pub trait FullEthApi:
EthApiTypes
FullEthApiTypes
+ EthApiSpec
+ EthTransactions
+ EthBlocks
@ -66,7 +66,7 @@ pub trait FullEthApi:
}
impl<T> FullEthApi for T where
T: EthApiTypes
T: FullEthApiTypes
+ EthApiSpec
+ EthTransactions
+ EthBlocks

View File

@ -4,9 +4,8 @@
use futures::Future;
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned};
use reth_rpc_eth_types::EthStateCache;
use reth_rpc_types::AnyTransactionReceipt;
use crate::EthApiTypes;
use crate::{EthApiTypes, RpcReceipt};
/// Assembles transaction receipt data w.r.t to network.
///
@ -23,5 +22,5 @@ pub trait LoadReceipt: EthApiTypes + Send + Sync {
tx: TransactionSigned,
meta: TransactionMeta,
receipt: Receipt,
) -> impl Future<Output = Result<AnyTransactionReceipt, Self::Error>> + Send;
) -> impl Future<Output = Result<RpcReceipt<Self::NetworkTypes>, Self::Error>> + Send;
}

View File

@ -17,13 +17,12 @@ use reth_rpc_types::{
EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest,
LegacyTransactionRequest,
},
AnyTransactionReceipt, BlockNumberOrTag, TransactionInfo, TransactionRequest,
TypedTransactionRequest,
BlockNumberOrTag, TransactionInfo, TransactionRequest, TypedTransactionRequest,
};
use reth_rpc_types_compat::transaction::{from_recovered, from_recovered_with_block_context};
use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool};
use crate::{FromEthApiError, IntoEthApiError, RpcTransaction};
use crate::{FromEthApiError, FullEthApiTypes, IntoEthApiError, RpcReceipt, RpcTransaction};
use super::{
Call, EthApiSpec, EthSigner, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, LoadState,
@ -137,7 +136,7 @@ pub trait EthTransactions: LoadTransaction {
fn transaction_receipt(
&self,
hash: B256,
) -> impl Future<Output = Result<Option<AnyTransactionReceipt>, Self::Error>> + Send
) -> impl Future<Output = Result<Option<RpcReceipt<Self::NetworkTypes>>, Self::Error>> + Send
where
Self: LoadReceipt + 'static,
{
@ -207,7 +206,10 @@ pub trait EthTransactions: LoadTransaction {
base_fee: base_fee_per_gas.map(u128::from),
index: Some(index as u64),
};
return Ok(Some(from_recovered_with_block_context(tx, tx_info)))
return Ok(Some(from_recovered_with_block_context::<Self::TransactionCompat>(
tx, tx_info,
)))
}
}
@ -223,7 +225,7 @@ pub trait EthTransactions: LoadTransaction {
include_pending: bool,
) -> impl Future<Output = Result<Option<RpcTransaction<Self::NetworkTypes>>, Self::Error>> + Send
where
Self: LoadBlock + LoadState,
Self: LoadBlock + LoadState + FullEthApiTypes,
{
async move {
// Check the pool first
@ -232,7 +234,7 @@ pub trait EthTransactions: LoadTransaction {
LoadState::pool(self).get_transaction_by_sender_and_nonce(sender, nonce)
{
let transaction = tx.transaction.clone().into_consensus();
return Ok(Some(from_recovered(transaction)));
return Ok(Some(from_recovered::<Self::TransactionCompat>(transaction)));
}
}
@ -283,7 +285,9 @@ pub trait EthTransactions: LoadTransaction {
base_fee: base_fee_per_gas.map(u128::from),
index: Some(index as u64),
};
from_recovered_with_block_context(tx, tx_info)
from_recovered_with_block_context::<Self::TransactionCompat>(
tx, tx_info,
)
})
})
.ok_or(EthApiError::HeaderNotFound(block_id).into())
@ -352,7 +356,7 @@ pub trait EthTransactions: LoadTransaction {
};
if self.find_signer(&from).is_err() {
return Err(SignError::NoAccount.into_eth_err());
return Err(SignError::NoAccount.into_eth_err())
}
// set nonce if not already set before
@ -605,7 +609,7 @@ pub trait EthTransactions: LoadTransaction {
///
/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` transactions RPC
/// methods.
pub trait LoadTransaction: SpawnBlocking {
pub trait LoadTransaction: SpawnBlocking + FullEthApiTypes {
/// Transaction pool with pending transactions. [`TransactionPool::Transaction`] is the
/// supported transaction type.
type Pool: TransactionPool;

View File

@ -19,12 +19,14 @@ pub mod helpers;
pub mod pubsub;
pub mod types;
pub use reth_rpc_types_compat::TransactionCompat;
pub use bundle::{EthBundleApiServer, EthCallBundleApiServer};
pub use core::{EthApiServer, FullEthApiServer};
pub use filter::EthFilterApiServer;
pub use helpers::error::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError};
pub use pubsub::EthPubSubApiServer;
pub use types::{EthApiTypes, RpcBlock, RpcReceipt, RpcTransaction};
pub use types::{EthApiTypes, FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction};
#[cfg(feature = "client")]
pub use bundle::{EthBundleApiClient, EthCallBundleApiClient};

View File

@ -1,10 +1,11 @@
//! Trait for specifying `eth` network dependent API types.
use std::error::Error;
use std::{error::Error, fmt};
use alloy_network::{AnyNetwork, Network};
use reth_rpc_eth_types::EthApiError;
use reth_rpc_types::{Block, Transaction, WithOtherFields};
use reth_rpc_types::Block;
use reth_rpc_types_compat::TransactionCompat;
use crate::{AsEthApiError, FromEthApiError, FromEvmError};
@ -19,16 +20,15 @@ pub trait EthApiTypes: Send + Sync + Clone {
+ Send
+ Sync;
/// Blockchain primitive types, specific to network, e.g. block and transaction.
// todo: remove restriction [`reth_rpc_types::Transaction`]
type NetworkTypes: Network<
TransactionResponse = WithOtherFields<Transaction>,
HeaderResponse = reth_rpc_types::Header,
>;
type NetworkTypes: Network<HeaderResponse = reth_rpc_types::Header>;
/// Conversion methods for transaction RPC type.
type TransactionCompat: Send + Sync + Clone + fmt::Debug;
}
impl EthApiTypes for () {
type Error = EthApiError;
type NetworkTypes = AnyNetwork;
type TransactionCompat = ();
}
/// Adapter for network specific transaction type.
@ -39,3 +39,16 @@ pub type RpcBlock<T> = Block<RpcTransaction<T>, <T as Network>::HeaderResponse>;
/// Adapter for network specific receipt type.
pub type RpcReceipt<T> = <T as Network>::ReceiptResponse;
/// Helper trait holds necessary trait bounds on [`EthApiTypes`] to implement `eth` API.
pub trait FullEthApiTypes:
EthApiTypes<TransactionCompat: TransactionCompat<Transaction = RpcTransaction<Self::NetworkTypes>>>
{
}
impl<T> FullEthApiTypes for T where
T: EthApiTypes<
TransactionCompat: TransactionCompat<Transaction = RpcTransaction<T::NetworkTypes>>,
>
{
}

View File

@ -27,6 +27,7 @@ reth-rpc-types-compat.workspace = true
reth-tasks.workspace = true
reth-transaction-pool.workspace = true
reth-trie.workspace = true
reth-provider.workspace = true
# ethereum
alloy-primitives.workspace = true
@ -35,6 +36,7 @@ alloy-sol-types.workspace = true
revm.workspace = true
revm-inspectors.workspace = true
revm-primitives = { workspace = true, features = ["dev"] }
alloy-rpc-types.workspace = true
# rpc
jsonrpsee-core.workspace = true

View File

@ -1,8 +1,8 @@
//! Context required for building `eth` namespace APIs.
use reth_chain_state::CanonStateSubscriptions;
use reth_chainspec::ChainSpecProvider;
use reth_storage_api::BlockReaderIdExt;
use std::marker::PhantomData;
use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider};
use reth_tasks::TaskSpawner;
use crate::{
@ -12,7 +12,7 @@ use crate::{
/// Context for building the `eth` namespace API.
#[derive(Debug, Clone)]
pub struct EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events> {
pub struct EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth> {
/// Database handle.
pub provider: Provider,
/// Mempool handle.
@ -29,10 +29,12 @@ pub struct EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events> {
pub events: Events,
/// RPC cache handle.
pub cache: EthStateCache,
/// RPC type builders.
pub _rpc_ty_builders: PhantomData<Eth>,
}
impl<Provider, Pool, EvmConfig, Network, Tasks, Events>
EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>
impl<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>
EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>
where
Provider: BlockReaderIdExt + Clone,
{
@ -58,8 +60,8 @@ pub struct GasPriceOracleBuilder;
impl GasPriceOracleBuilder {
/// Builds a [`GasPriceOracle`], for given context.
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>,
) -> GasPriceOracle<Provider>
where
Provider: BlockReaderIdExt + Clone,
@ -74,8 +76,8 @@ pub struct FeeHistoryCacheBuilder;
impl FeeHistoryCacheBuilder {
/// Builds a [`FeeHistoryCache`], for given context.
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
pub fn build<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Eth>,
) -> FeeHistoryCache
where
Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static,

View File

@ -11,9 +11,9 @@ use reth_revm::database::StateProviderDatabase;
use reth_rpc_server_types::result::rpc_err;
use reth_rpc_types::{
simulate::{SimCallResult, SimulateError, SimulatedBlock},
Block, BlockTransactionsKind, ToRpcError, TransactionRequest, WithOtherFields,
Block, BlockTransactionsKind, ToRpcError, TransactionRequest,
};
use reth_rpc_types_compat::block::from_block;
use reth_rpc_types_compat::{block::from_block, TransactionCompat};
use reth_storage_api::StateRootProvider;
use reth_trie::{HashedPostState, HashedStorage};
use revm::{db::CacheDB, Database};
@ -168,7 +168,7 @@ where
}
/// Handles outputs of the calls execution and builds a [`SimulatedBlock`].
pub fn build_block(
pub fn build_block<T: TransactionCompat>(
results: Vec<(Address, ExecutionResult)>,
transactions: Vec<TransactionSigned>,
block_env: &BlockEnv,
@ -176,7 +176,7 @@ pub fn build_block(
total_difficulty: U256,
full_transactions: bool,
db: &CacheDB<StateProviderDatabase<StateProviderTraitObjWrapper<'_>>>,
) -> Result<SimulatedBlock<Block<WithOtherFields<reth_rpc_types::Transaction>>>, EthApiError> {
) -> Result<SimulatedBlock<Block<T::Transaction>>, EthApiError> {
let mut calls: Vec<SimCallResult> = Vec::with_capacity(results.len());
let mut senders = Vec::with_capacity(results.len());
let mut receipts = Vec::new();
@ -297,6 +297,6 @@ pub fn build_block(
let txs_kind =
if full_transactions { BlockTransactionsKind::Full } else { BlockTransactionsKind::Hashes };
let block = from_block(block, total_difficulty, txs_kind, None)?;
let block = from_block::<T>(block, total_difficulty, txs_kind, None)?;
Ok(SimulatedBlock { inner: block, calls })
}

View File

@ -1,10 +1,14 @@
//! Helper types for `reth_rpc_eth_api::EthApiServer` implementation.
//!
//! Transaction wrapper that labels transaction with its origin.
use alloy_primitives::B256;
use alloy_rpc_types::TransactionInfo;
use reth_primitives::TransactionSignedEcRecovered;
use reth_rpc_types::{Transaction, TransactionInfo, WithOtherFields};
use reth_rpc_types_compat::transaction::from_recovered_with_block_context;
use reth_rpc_types_compat::{
transaction::{from_recovered, from_recovered_with_block_context},
TransactionCompat,
};
/// Represents from where a transaction was fetched.
#[derive(Debug, Clone, Eq, PartialEq)]
@ -36,6 +40,24 @@ impl TransactionSource {
self.into()
}
/// Conversion into network specific transaction type.
pub fn into_transaction<T: TransactionCompat>(self) -> T::Transaction {
match self {
Self::Pool(tx) => from_recovered::<T>(tx),
Self::Block { transaction, index, block_hash, block_number, base_fee } => {
let tx_info = TransactionInfo {
hash: Some(transaction.hash()),
index: Some(index),
block_hash: Some(block_hash),
block_number: Some(block_number),
base_fee: base_fee.map(u128::from),
};
from_recovered_with_block_context::<T>(transaction, tx_info)
}
}
}
/// Returns the transaction and block related info, if not pending
pub fn split(self) -> (TransactionSignedEcRecovered, TransactionInfo) {
match self {
@ -68,21 +90,3 @@ impl From<TransactionSource> for TransactionSignedEcRecovered {
}
}
}
impl From<TransactionSource> for WithOtherFields<Transaction> {
fn from(value: TransactionSource) -> Self {
match value {
TransactionSource::Pool(tx) => reth_rpc_types_compat::transaction::from_recovered(tx),
TransactionSource::Block { transaction, index, block_hash, block_number, base_fee } => {
let tx_info = TransactionInfo {
hash: Some(transaction.hash()),
block_hash: Some(block_hash),
block_number: Some(block_number),
base_fee: base_fee.map(u128::from),
index: Some(index),
};
from_recovered_with_block_context(transaction, tx_info)
}
}
}
}

View File

@ -1,31 +1,31 @@
//! Compatibility functions for rpc `Block` type.
use crate::transaction::from_recovered_with_block_context;
use alloy_primitives::{B256, U256};
use alloy_rlp::Encodable;
use alloy_rpc_types::{Transaction, TransactionInfo};
use reth_primitives::{
Block as PrimitiveBlock, BlockWithSenders, Header as PrimitiveHeader, Withdrawals,
};
use reth_rpc_types::{
Block, BlockError, BlockTransactions, BlockTransactionsKind, Header, WithOtherFields,
Block, BlockError, BlockTransactions, BlockTransactionsKind, Header, TransactionInfo,
};
use crate::{transaction::from_recovered_with_block_context, TransactionCompat};
/// Converts the given primitive block into a [`Block`] response with the given
/// [`BlockTransactionsKind`]
///
/// If a `block_hash` is provided, then this is used, otherwise the block hash is computed.
pub fn from_block(
pub fn from_block<T: TransactionCompat>(
block: BlockWithSenders,
total_difficulty: U256,
kind: BlockTransactionsKind,
block_hash: Option<B256>,
) -> Result<Block<WithOtherFields<Transaction>>, BlockError> {
) -> Result<Block<T::Transaction>, BlockError> {
match kind {
BlockTransactionsKind::Hashes => {
Ok(from_block_with_tx_hashes(block, total_difficulty, block_hash))
Ok(from_block_with_tx_hashes::<T::Transaction>(block, total_difficulty, block_hash))
}
BlockTransactionsKind::Full => from_block_full(block, total_difficulty, block_hash),
BlockTransactionsKind::Full => from_block_full::<T>(block, total_difficulty, block_hash),
}
}
@ -34,11 +34,11 @@ pub fn from_block(
///
/// This will populate the `transactions` field with only the hashes of the transactions in the
/// block: [`BlockTransactions::Hashes`]
pub fn from_block_with_tx_hashes(
pub fn from_block_with_tx_hashes<T>(
block: BlockWithSenders,
total_difficulty: U256,
block_hash: Option<B256>,
) -> Block<WithOtherFields<Transaction>> {
) -> Block<T> {
let block_hash = block_hash.unwrap_or_else(|| block.header.hash_slow());
let transactions = block.body.iter().map(|tx| tx.hash()).collect();
@ -55,12 +55,12 @@ pub fn from_block_with_tx_hashes(
/// total difficulty to populate its field in the rpc response.
///
/// This will populate the `transactions` field with the _full_
/// [`Transaction`] objects: [`BlockTransactions::Full`]
pub fn from_block_full(
/// [`TransactionCompat::Transaction`] objects: [`BlockTransactions::Full`]
pub fn from_block_full<T: TransactionCompat>(
mut block: BlockWithSenders,
total_difficulty: U256,
block_hash: Option<B256>,
) -> Result<Block<WithOtherFields<Transaction>>, BlockError> {
) -> Result<Block<T::Transaction>, BlockError> {
let block_hash = block_hash.unwrap_or_else(|| block.block.header.hash_slow());
let block_number = block.block.number;
let base_fee_per_gas = block.block.base_fee_per_gas;
@ -83,7 +83,7 @@ pub fn from_block_full(
index: Some(idx as u64),
};
from_recovered_with_block_context(signed_tx_ec_recovered, tx_info)
from_recovered_with_block_context::<T>(signed_tx_ec_recovered, tx_info)
})
.collect::<Vec<_>>();
@ -155,13 +155,13 @@ pub fn from_primitive_with_hash(primitive_header: reth_primitives::SealedHeader)
}
#[inline]
fn from_block_with_transactions(
fn from_block_with_transactions<T>(
block_length: usize,
block_hash: B256,
block: PrimitiveBlock,
total_difficulty: U256,
transactions: BlockTransactions<WithOtherFields<Transaction>>,
) -> Block<WithOtherFields<Transaction>> {
transactions: BlockTransactions<T>,
) -> Block<T> {
let uncles = block.ommers.into_iter().map(|h| h.hash_slow()).collect();
let mut header = from_primitive_with_hash(block.header.seal(block_hash));
header.total_difficulty = Some(total_difficulty);
@ -177,7 +177,7 @@ fn from_block_with_transactions(
/// Build an RPC block response representing
/// an Uncle from its header.
pub fn uncle_block_from_header(header: PrimitiveHeader) -> Block<WithOtherFields<Transaction>> {
pub fn uncle_block_from_header<T>(header: PrimitiveHeader) -> Block<T> {
let hash = header.hash_slow();
let rpc_header = from_primitive_with_hash(header.clone().seal(hash));
let uncle_block = PrimitiveBlock { header, ..Default::default() };

View File

@ -14,3 +14,5 @@ pub mod block;
pub mod engine;
pub mod proof;
pub mod transaction;
pub use transaction::TransactionCompat;

View File

@ -1,117 +1,107 @@
//! Compatibility functions for rpc `Transaction` type.
use alloy_primitives::{Address, TxKind};
use alloy_rpc_types::{
request::{TransactionInput, TransactionRequest},
TransactionInfo,
};
use reth_primitives::{TransactionSignedEcRecovered, TxType};
use reth_rpc_types::{Transaction, WithOtherFields};
use signature::from_primitive_signature;
pub use typed::*;
mod signature;
mod typed;
/// Create a new rpc transaction result for a mined transaction, using the given [`TransactionInfo`]
/// to populate the corresponding fields in the rpc result.
pub fn from_recovered_with_block_context(
pub use signature::*;
pub use typed::*;
use std::fmt;
use alloy_rpc_types::{
request::{TransactionInput, TransactionRequest},
TransactionInfo,
};
use reth_primitives::{TransactionSigned, TransactionSignedEcRecovered, TxType};
use reth_rpc_types::{Transaction, WithOtherFields};
/// Create a new rpc transaction result for a mined transaction, using the given block hash,
/// number, and tx index fields to populate the corresponding fields in the rpc result.
///
/// The block hash, number, and tx index fields should be from the original block where the
/// transaction was mined.
pub fn from_recovered_with_block_context<T: TransactionCompat>(
tx: TransactionSignedEcRecovered,
tx_info: TransactionInfo,
) -> WithOtherFields<Transaction> {
fill(tx, tx_info)
) -> T::Transaction {
T::fill(tx, tx_info)
}
/// Create a new rpc transaction result for a _pending_ signed transaction, setting block
/// environment related fields to `None`.
pub fn from_recovered(tx: TransactionSignedEcRecovered) -> WithOtherFields<Transaction> {
fill(tx, TransactionInfo::default())
pub fn from_recovered<T: TransactionCompat>(tx: TransactionSignedEcRecovered) -> T::Transaction {
T::fill(tx, TransactionInfo::default())
}
/// Create a new rpc transaction result for a _pending_ signed transaction, setting block
/// environment related fields to `None`.
fn fill(
tx: TransactionSignedEcRecovered,
tx_info: TransactionInfo,
) -> WithOtherFields<Transaction> {
let signer = tx.signer();
let signed_tx = tx.into_signed();
/// Builds RPC transaction w.r.t. network.
pub trait TransactionCompat: Send + Sync + Unpin + Clone + fmt::Debug {
/// RPC transaction response type.
type Transaction: Send + Clone + Default + fmt::Debug;
let to: Option<Address> = match signed_tx.kind() {
TxKind::Create => None,
TxKind::Call(to) => Some(Address(*to)),
};
/// Formats gas price and max fee per gas for RPC transaction response w.r.t. network specific
/// transaction type.
fn gas_price(signed_tx: &TransactionSigned, base_fee: Option<u64>) -> GasPrice {
match signed_tx.tx_type() {
TxType::Legacy | TxType::Eip2930 => {
GasPrice { gas_price: Some(signed_tx.max_fee_per_gas()), max_fee_per_gas: None }
}
TxType::Eip1559 | TxType::Eip4844 => {
// the gas price field for EIP1559 is set to `min(tip, gasFeeCap - baseFee) +
// baseFee`
let gas_price = base_fee
.and_then(|base_fee| {
signed_tx
.effective_tip_per_gas(Some(base_fee))
.map(|tip| tip + base_fee as u128)
})
.unwrap_or_else(|| signed_tx.max_fee_per_gas());
#[allow(unreachable_patterns)]
let (gas_price, max_fee_per_gas) = match signed_tx.tx_type() {
TxType::Legacy | TxType::Eip2930 => (Some(signed_tx.max_fee_per_gas()), None),
TxType::Eip1559 | TxType::Eip4844 | TxType::Eip7702 => {
// the gas price field for EIP1559 is set to `min(tip, gasFeeCap - baseFee) +
// baseFee`
let gas_price = tx_info
.base_fee
.and_then(|base_fee| {
signed_tx.effective_tip_per_gas(Some(base_fee as u64)).map(|tip| tip + base_fee)
})
.unwrap_or_else(|| signed_tx.max_fee_per_gas());
(Some(gas_price), Some(signed_tx.max_fee_per_gas()))
GasPrice {
gas_price: Some(gas_price),
max_fee_per_gas: Some(signed_tx.max_fee_per_gas()),
}
}
_ => GasPrice::default(),
}
_ => {
// OP-deposit
(Some(signed_tx.max_fee_per_gas()), None)
}
};
// let chain_id = signed_tx.chain_id().map(U64::from);
let chain_id = signed_tx.chain_id();
let blob_versioned_hashes = signed_tx.blob_versioned_hashes();
let access_list = signed_tx.access_list().cloned();
let authorization_list = signed_tx.authorization_list().map(|l| l.to_vec());
let signature =
from_primitive_signature(*signed_tx.signature(), signed_tx.tx_type(), signed_tx.chain_id());
WithOtherFields {
inner: Transaction {
hash: signed_tx.hash(),
nonce: signed_tx.nonce(),
from: signer,
to,
value: signed_tx.value(),
gas_price,
max_fee_per_gas,
max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas(),
signature: Some(signature),
gas: signed_tx.gas_limit() as u128,
input: signed_tx.input().clone(),
chain_id,
access_list,
transaction_type: Some(signed_tx.tx_type() as u8),
// These fields are set to None because they are not stored as part of the transaction
block_hash: tx_info.block_hash,
block_number: tx_info.block_number,
transaction_index: tx_info.index,
// EIP-4844 fields
max_fee_per_blob_gas: signed_tx.max_fee_per_blob_gas(),
blob_versioned_hashes,
// EIP-7702 fields
authorization_list,
},
// Optimism fields
#[cfg(feature = "optimism")]
other: reth_rpc_types::optimism::OptimismTransactionFields {
source_hash: signed_tx.source_hash(),
mint: signed_tx.mint(),
// only include is_system_tx if true: <https://github.com/ethereum-optimism/op-geth/blob/641e996a2dcf1f81bac9416cb6124f86a69f1de7/internal/ethapi/api.go#L1518-L1518>
is_system_tx: (signed_tx.is_deposit() && signed_tx.is_system_transaction())
.then_some(true),
deposit_receipt_version: None,
}
.into(),
#[cfg(not(feature = "optimism"))]
other: Default::default(),
}
/// Create a new rpc transaction result for a _pending_ signed transaction, setting block
/// environment related fields to `None`.
fn fill(tx: TransactionSignedEcRecovered, tx_inf: TransactionInfo) -> Self::Transaction;
/// Truncates the input of a transaction to only the first 4 bytes.
// todo: remove in favour of using constructor on `TransactionResponse` or similar
// <https://github.com/alloy-rs/alloy/issues/1315>.
fn otterscan_api_truncate_input(tx: &mut Self::Transaction);
/// Returns the transaction type.
// todo: remove when alloy TransactionResponse trait it updated.
fn tx_type(tx: &Self::Transaction) -> u8;
}
impl TransactionCompat for () {
// this noop impl depends on integration in `reth_rpc_eth_api::EthApiTypes` noop impl, and
// `alloy_network::AnyNetwork`
type Transaction = WithOtherFields<Transaction>;
fn fill(_tx: TransactionSignedEcRecovered, _tx_info: TransactionInfo) -> Self::Transaction {
WithOtherFields::default()
}
fn otterscan_api_truncate_input(_tx: &mut Self::Transaction) {}
fn tx_type(_tx: &Self::Transaction) -> u8 {
0
}
}
/// Gas price and max fee per gas for a transaction. Helper type to format transaction RPC response.
#[derive(Debug, Default)]
pub struct GasPrice {
/// Gas price for transaction.
pub gas_price: Option<u128>,
/// Max fee per gas for transaction.
pub max_fee_per_gas: Option<u128>,
}
/// Convert [`TransactionSignedEcRecovered`] to [`TransactionRequest`]

View File

@ -7,7 +7,7 @@ use reth_rpc_types::{Parity, Signature};
/// recovery id.
///
/// If the chain id is `Some`, the recovery id is computed according to [EIP-155](https://eips.ethereum.org/EIPS/eip-155).
pub(crate) fn from_legacy_primitive_signature(
pub fn from_legacy_primitive_signature(
signature: PrimitiveSignature,
chain_id: Option<u64>,
) -> Signature {
@ -22,7 +22,7 @@ pub(crate) fn from_legacy_primitive_signature(
/// Creates a new rpc signature from a non-legacy [primitive
/// signature](reth_primitives::Signature). This sets the `v` value to `0` or `1` depending on
/// the signature's `odd_y_parity`.
pub(crate) fn from_typed_primitive_signature(signature: PrimitiveSignature) -> Signature {
pub fn from_typed_primitive_signature(signature: PrimitiveSignature) -> Signature {
Signature {
r: signature.r,
s: signature.s,
@ -40,7 +40,7 @@ pub(crate) fn from_typed_primitive_signature(signature: PrimitiveSignature) -> S
/// If the transaction is a legacy transaction, it will use the `chain_id` to compute the
/// signature's recovery id. If the transaction is a typed transaction, it will set the `v`
/// value to `0` or `1` depending on the signature's `odd_y_parity`.
pub(crate) fn from_primitive_signature(
pub fn from_primitive_signature(
signature: PrimitiveSignature,
tx_type: TxType,
chain_id: Option<u64>,

View File

@ -38,7 +38,6 @@ reth-trie.workspace = true
# ethereum
alloy-dyn-abi.workspace = true
alloy-eips.workspace = true
alloy-genesis.workspace = true
alloy-network.workspace = true
alloy-primitives.workspace = true

View File

@ -1,14 +1,13 @@
use alloy_eips::{BlockId, BlockNumberOrTag};
use alloy_network::Network;
use alloy_primitives::{Address, Bytes, B256, U256, U64};
use jsonrpsee::core::RpcResult as Result;
use reth_primitives::{BlockId, BlockNumberOrTag};
use reth_rpc_api::{EngineEthApiServer, EthApiServer, EthFilterApiServer};
/// Re-export for convenience
pub use reth_rpc_engine_api::EngineApi;
use reth_rpc_eth_api::{EthApiTypes, RpcBlock, RpcReceipt, RpcTransaction};
use reth_rpc_eth_api::{FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction};
use reth_rpc_types::{
state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, JsonStorageKey, Log,
SyncStatus, TransactionRequest, WithOtherFields,
SyncStatus, TransactionRequest,
};
use tracing_futures::Instrument;
@ -41,11 +40,7 @@ where
RpcTransaction<Eth::NetworkTypes>,
RpcBlock<Eth::NetworkTypes>,
RpcReceipt<Eth::NetworkTypes>,
> + EthApiTypes<
NetworkTypes: Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
>,
>,
> + FullEthApiTypes,
EthFilter: EthFilterApiServer<RpcTransaction<Eth::NetworkTypes>>,
{
/// Handler for: `eth_syncing`

View File

@ -23,6 +23,8 @@ use reth_tasks::{
};
use tokio::sync::Mutex;
use crate::eth::EthTxBuilder;
/// `Eth` API implementation.
///
/// This type provides the functionality for handling `eth_` related requests.
@ -93,7 +95,7 @@ where
{
/// Creates a new, shareable instance.
pub fn with_spawner<Tasks, Events>(
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events>,
ctx: &EthApiBuilderCtx<Provider, Pool, EvmConfig, Network, Tasks, Events, Self>,
) -> Self
where
Tasks: TaskSpawner + Clone + 'static,
@ -127,7 +129,9 @@ where
Self: Send + Sync,
{
type Error = EthApiError;
// todo: replace with alloy_network::Ethereum
type NetworkTypes = AnyNetwork;
type TransactionCompat = EthTxBuilder;
}
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
@ -163,8 +167,15 @@ impl<N> BuilderProvider<N> for EthApi<N::Provider, N::Pool, N::Network, N::Evm>
where
N: FullNodeComponents,
{
type Ctx<'a> =
&'a EthApiBuilderCtx<N::Provider, N::Pool, N::Evm, N::Network, TaskExecutor, N::Provider>;
type Ctx<'a> = &'a EthApiBuilderCtx<
N::Provider,
N::Pool,
N::Evm,
N::Network,
TaskExecutor,
N::Provider,
Self,
>;
fn builder() -> Box<dyn for<'a> Fn(Self::Ctx<'a>) -> Self + Send> {
Box::new(Self::with_spawner)

View File

@ -4,6 +4,7 @@ use std::{
collections::HashMap,
fmt,
iter::StepBy,
marker::PhantomData,
ops::RangeInclusive,
sync::Arc,
time::{Duration, Instant},
@ -13,9 +14,10 @@ use alloy_primitives::TxHash;
use async_trait::async_trait;
use jsonrpsee::{core::RpcResult, server::IdProvider};
use reth_chainspec::ChainInfo;
use reth_node_api::EthApiTypes;
use reth_primitives::{IntoRecoveredTransaction, TransactionSignedEcRecovered};
use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError};
use reth_rpc_eth_api::EthFilterApiServer;
use reth_rpc_eth_api::{EthFilterApiServer, FullEthApiTypes, RpcTransaction, TransactionCompat};
use reth_rpc_eth_types::{
logs_utils::{self, append_matching_block_logs},
EthApiError, EthFilterConfig, EthFilterError, EthStateCache, EthSubscriptionIdProvider,
@ -23,8 +25,9 @@ use reth_rpc_eth_types::{
use reth_rpc_server_types::ToRpcResult;
use reth_rpc_types::{
BlockNumHash, Filter, FilterBlockOption, FilterChanges, FilterId, FilteredParams, Log,
PendingTransactionFilterKind, Transaction, WithOtherFields,
PendingTransactionFilterKind,
};
use reth_rpc_types_compat::transaction::from_recovered;
use reth_tasks::TaskSpawner;
use reth_transaction_pool::{NewSubpoolTransactionStream, PoolTransaction, TransactionPool};
use tokio::{
@ -37,15 +40,27 @@ use tracing::trace;
const MAX_HEADERS_RANGE: u64 = 1_000; // with ~530bytes per header this is ~500kb
/// `Eth` filter RPC implementation.
pub struct EthFilter<Provider, Pool> {
pub struct EthFilter<Provider, Pool, Eth: EthApiTypes> {
/// All nested fields bundled together
inner: Arc<EthFilterInner<Provider, Pool>>,
inner: Arc<EthFilterInner<Provider, Pool, RpcTransaction<Eth::NetworkTypes>>>,
/// Assembles response data w.r.t. network.
_tx_resp_builder: PhantomData<Eth>,
}
impl<Provider, Pool> EthFilter<Provider, Pool>
impl<Provider, Pool, Eth> Clone for EthFilter<Provider, Pool, Eth>
where
Eth: EthApiTypes,
{
fn clone(&self) -> Self {
Self { inner: self.inner.clone(), _tx_resp_builder: PhantomData }
}
}
impl<Provider, Pool, Eth> EthFilter<Provider, Pool, Eth>
where
Provider: Send + Sync + 'static,
Pool: Send + Sync + 'static,
Eth: EthApiTypes + 'static,
{
/// Creates a new, shareable instance.
///
@ -66,7 +81,7 @@ where
config;
let inner = EthFilterInner {
provider,
active_filters: Default::default(),
active_filters: ActiveFilters::new(),
pool,
id_provider: Arc::new(EthSubscriptionIdProvider::default()),
eth_cache,
@ -78,7 +93,7 @@ where
max_logs_per_response: max_logs_per_response.unwrap_or(usize::MAX),
};
let eth_filter = Self { inner: Arc::new(inner) };
let eth_filter = Self { inner: Arc::new(inner), _tx_resp_builder: PhantomData };
let this = eth_filter.clone();
eth_filter.inner.task_spawner.spawn_critical(
@ -92,7 +107,7 @@ where
}
/// Returns all currently active filters
pub fn active_filters(&self) -> &ActiveFilters {
pub fn active_filters(&self) -> &ActiveFilters<RpcTransaction<Eth::NetworkTypes>> {
&self.inner.active_filters
}
@ -126,17 +141,18 @@ where
}
}
impl<Provider, Pool> EthFilter<Provider, Pool>
impl<Provider, Pool, Eth> EthFilter<Provider, Pool, Eth>
where
Provider: BlockReader + BlockIdReader + EvmEnvProvider + 'static,
Pool: TransactionPool + 'static,
<Pool as TransactionPool>::Transaction: 'static,
Eth: FullEthApiTypes,
{
/// Returns all the filter changes for the given id, if any
pub async fn filter_changes(
&self,
id: FilterId,
) -> Result<FilterChanges<WithOtherFields<Transaction>>, EthFilterError> {
) -> Result<FilterChanges<RpcTransaction<Eth::NetworkTypes>>, EthFilterError> {
let info = self.inner.provider.chain_info()?;
let best_number = info.best_number;
@ -225,21 +241,25 @@ where
}
#[async_trait]
impl<Provider, Pool> EthFilterApiServer<WithOtherFields<Transaction>> for EthFilter<Provider, Pool>
impl<Provider, Pool, Eth> EthFilterApiServer<RpcTransaction<Eth::NetworkTypes>>
for EthFilter<Provider, Pool, Eth>
where
Provider: BlockReader + BlockIdReader + EvmEnvProvider + 'static,
Pool: TransactionPool + 'static,
Eth: FullEthApiTypes + 'static,
{
/// Handler for `eth_newFilter`
async fn new_filter(&self, filter: Filter) -> RpcResult<FilterId> {
trace!(target: "rpc::eth", "Serving eth_newFilter");
self.inner.install_filter(FilterKind::Log(Box::new(filter))).await
self.inner
.install_filter(FilterKind::<RpcTransaction<Eth::NetworkTypes>>::Log(Box::new(filter)))
.await
}
/// Handler for `eth_newBlockFilter`
async fn new_block_filter(&self) -> RpcResult<FilterId> {
trace!(target: "rpc::eth", "Serving eth_newBlockFilter");
self.inner.install_filter(FilterKind::Block).await
self.inner.install_filter(FilterKind::<RpcTransaction<Eth::NetworkTypes>>::Block).await
}
/// Handler for `eth_newPendingTransactionFilter`
@ -257,7 +277,8 @@ where
}
PendingTransactionFilterKind::Full => {
let stream = self.inner.pool.new_pending_pool_transactions_listener();
let full_txs_receiver = FullTransactionsReceiver::new(stream);
let full_txs_receiver =
FullTransactionsReceiver::<_, Eth::TransactionCompat>::new(stream);
FilterKind::PendingTransaction(PendingTransactionKind::FullTransaction(Arc::new(
full_txs_receiver,
)))
@ -274,7 +295,7 @@ where
async fn filter_changes(
&self,
id: FilterId,
) -> RpcResult<FilterChanges<WithOtherFields<Transaction>>> {
) -> RpcResult<FilterChanges<RpcTransaction<Eth::NetworkTypes>>> {
trace!(target: "rpc::eth", "Serving eth_getFilterChanges");
Ok(Self::filter_changes(self, id).await?)
}
@ -310,27 +331,24 @@ where
}
}
impl<Provider, Pool> std::fmt::Debug for EthFilter<Provider, Pool> {
impl<Provider, Pool, Eth> std::fmt::Debug for EthFilter<Provider, Pool, Eth>
where
Eth: EthApiTypes,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EthFilter").finish_non_exhaustive()
}
}
impl<Provider, Pool> Clone for EthFilter<Provider, Pool> {
fn clone(&self) -> Self {
Self { inner: Arc::clone(&self.inner) }
}
}
/// Container type `EthFilter`
#[derive(Debug)]
struct EthFilterInner<Provider, Pool> {
struct EthFilterInner<Provider, Pool, Tx> {
/// The transaction pool.
pool: Pool,
/// The provider that can interact with the chain.
provider: Provider,
/// All currently installed filters.
active_filters: ActiveFilters,
active_filters: ActiveFilters<Tx>,
/// Provides ids to identify filters
id_provider: Arc<dyn IdProvider>,
/// Maximum number of blocks that could be scanned per filter
@ -347,7 +365,7 @@ struct EthFilterInner<Provider, Pool> {
stale_filter_ttl: Duration,
}
impl<Provider, Pool> EthFilterInner<Provider, Pool>
impl<Provider, Pool, Tx> EthFilterInner<Provider, Pool, Tx>
where
Provider: BlockReader + BlockIdReader + EvmEnvProvider + 'static,
Pool: TransactionPool + 'static,
@ -408,7 +426,7 @@ where
}
/// Installs a new filter and returns the new identifier.
async fn install_filter(&self, kind: FilterKind) -> RpcResult<FilterId> {
async fn install_filter(&self, kind: FilterKind<Tx>) -> RpcResult<FilterId> {
let last_poll_block_number = self.provider.best_block_number().to_rpc_result()?;
let id = FilterId::from(self.id_provider.next_id());
let mut filters = self.active_filters.inner.lock().await;
@ -526,19 +544,26 @@ where
/// All active filters
#[derive(Debug, Clone, Default)]
pub struct ActiveFilters {
inner: Arc<Mutex<HashMap<FilterId, ActiveFilter>>>,
pub struct ActiveFilters<T> {
inner: Arc<Mutex<HashMap<FilterId, ActiveFilter<T>>>>,
}
impl<T> ActiveFilters<T> {
/// Returns an empty instance.
pub fn new() -> Self {
Self { inner: Arc::new(Mutex::new(HashMap::new())) }
}
}
/// An installed filter
#[derive(Debug)]
struct ActiveFilter {
struct ActiveFilter<T> {
/// At which block the filter was polled last.
block: u64,
/// Last time this filter was polled.
last_poll_timestamp: Instant,
/// What kind of filter it is.
kind: FilterKind,
kind: FilterKind<T>,
}
/// A receiver for pending transactions that returns all new transactions since the last poll.
@ -553,7 +578,7 @@ impl PendingTransactionsReceiver {
}
/// Returns all new pending transactions received since the last poll.
async fn drain(&self) -> FilterChanges<WithOtherFields<Transaction>> {
async fn drain<T>(&self) -> FilterChanges<T> {
let mut pending_txs = Vec::new();
let mut prepared_stream = self.txs_receiver.lock().await;
@ -568,21 +593,23 @@ impl PendingTransactionsReceiver {
/// A structure to manage and provide access to a stream of full transaction details.
#[derive(Debug, Clone)]
struct FullTransactionsReceiver<T: PoolTransaction> {
struct FullTransactionsReceiver<T: PoolTransaction, TxCompat> {
txs_stream: Arc<Mutex<NewSubpoolTransactionStream<T>>>,
_tx_resp_builder: PhantomData<TxCompat>,
}
impl<T> FullTransactionsReceiver<T>
impl<T, TxCompat> FullTransactionsReceiver<T, TxCompat>
where
T: PoolTransaction + 'static,
TxCompat: TransactionCompat,
{
/// Creates a new `FullTransactionsReceiver` encapsulating the provided transaction stream.
fn new(stream: NewSubpoolTransactionStream<T>) -> Self {
Self { txs_stream: Arc::new(Mutex::new(stream)) }
Self { txs_stream: Arc::new(Mutex::new(stream)), _tx_resp_builder: PhantomData }
}
/// Returns all new pending transactions received since the last poll.
async fn drain(&self) -> FilterChanges<WithOtherFields<Transaction>>
async fn drain(&self) -> FilterChanges<TxCompat::Transaction>
where
T: PoolTransaction<Consensus = TransactionSignedEcRecovered>,
{
@ -590,9 +617,7 @@ where
let mut prepared_stream = self.txs_stream.lock().await;
while let Ok(tx) = prepared_stream.try_recv() {
pending_txs.push(reth_rpc_types_compat::transaction::from_recovered(
tx.transaction.to_recovered_transaction(),
))
pending_txs.push(from_recovered::<TxCompat>(tx.transaction.to_recovered_transaction()))
}
FilterChanges::Transactions(pending_txs)
}
@ -600,16 +625,18 @@ where
/// Helper trait for [FullTransactionsReceiver] to erase the `Transaction` type.
#[async_trait]
trait FullTransactionsFilter: fmt::Debug + Send + Sync + Unpin + 'static {
async fn drain(&self) -> FilterChanges<WithOtherFields<Transaction>>;
trait FullTransactionsFilter<T>: fmt::Debug + Send + Sync + Unpin + 'static {
async fn drain(&self) -> FilterChanges<T>;
}
#[async_trait]
impl<T> FullTransactionsFilter for FullTransactionsReceiver<T>
impl<T, TxCompat> FullTransactionsFilter<TxCompat::Transaction>
for FullTransactionsReceiver<T, TxCompat>
where
T: PoolTransaction<Consensus = TransactionSignedEcRecovered> + 'static,
TxCompat: TransactionCompat + 'static,
{
async fn drain(&self) -> FilterChanges<WithOtherFields<Transaction>> {
async fn drain(&self) -> FilterChanges<TxCompat::Transaction> {
Self::drain(self).await
}
}
@ -620,13 +647,13 @@ where
/// - Just the transaction hashes.
/// - Full transaction details.
#[derive(Debug, Clone)]
enum PendingTransactionKind {
enum PendingTransactionKind<T> {
Hashes(PendingTransactionsReceiver),
FullTransaction(Arc<dyn FullTransactionsFilter>),
FullTransaction(Arc<dyn FullTransactionsFilter<T>>),
}
impl PendingTransactionKind {
async fn drain(&self) -> FilterChanges<WithOtherFields<Transaction>> {
impl<T: 'static> PendingTransactionKind<T> {
async fn drain(&self) -> FilterChanges<T> {
match self {
Self::Hashes(receiver) => receiver.drain().await,
Self::FullTransaction(receiver) => receiver.drain().await,
@ -635,10 +662,10 @@ impl PendingTransactionKind {
}
#[derive(Clone, Debug)]
enum FilterKind {
enum FilterKind<T> {
Log(Box<Filter>),
Block,
PendingTransaction(PendingTransactionKind),
PendingTransaction(PendingTransactionKind<T>),
}
/// An iterator that yields _inclusive_ block ranges of a given step size

View File

@ -1,19 +1,22 @@
//! Contains RPC handler implementations specific to blocks.
use reth_primitives::{BlockId, TransactionMeta};
use reth_primitives::TransactionMeta;
use reth_provider::{BlockReaderIdExt, HeaderProvider};
use reth_rpc_eth_api::{
helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking},
FromEthApiError,
RpcReceipt,
};
use reth_rpc_eth_types::{EthStateCache, ReceiptBuilder};
use reth_rpc_types::AnyTransactionReceipt;
use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder};
use reth_rpc_types::{AnyTransactionReceipt, BlockId};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthBlocks for EthApi<Provider, Pool, Network, EvmConfig>
where
Self: LoadBlock,
Self: LoadBlock<
Error = EthApiError,
NetworkTypes: alloy_network::Network<ReceiptResponse = AnyTransactionReceipt>,
>,
Provider: HeaderProvider,
{
#[inline]
@ -24,7 +27,7 @@ where
async fn block_receipts(
&self,
block_id: BlockId,
) -> Result<Option<Vec<AnyTransactionReceipt>>, Self::Error>
) -> Result<Option<Vec<RpcReceipt<Self::NetworkTypes>>>, Self::Error>
where
Self: LoadReceipt,
{
@ -36,7 +39,7 @@ where
let timestamp = block.timestamp;
let block = block.unseal();
let receipts = block
return block
.body
.into_iter()
.zip(receipts.iter())
@ -54,10 +57,9 @@ where
ReceiptBuilder::new(&tx, meta, receipt, &receipts)
.map(|builder| builder.build())
.map_err(Self::Error::from_eth_err)
})
.collect::<Result<Vec<_>, Self::Error>>();
return receipts.map(Some)
.collect::<Result<Vec<_>, Self::Error>>()
.map(Some)
}
Ok(None)

View File

@ -2,6 +2,7 @@
//! files.
pub mod signer;
pub mod types;
mod block;
mod call;

View File

@ -1,9 +1,8 @@
//! Builds an RPC receipt response w.r.t. data layout of network.
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned};
use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError};
use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt};
use reth_rpc_eth_types::{EthApiError, EthStateCache, ReceiptBuilder};
use reth_rpc_types::AnyTransactionReceipt;
use crate::EthApi;
@ -21,7 +20,7 @@ where
tx: TransactionSigned,
meta: TransactionMeta,
receipt: Receipt,
) -> Result<AnyTransactionReceipt, Self::Error> {
) -> Result<RpcReceipt<Self::NetworkTypes>, Self::Error> {
let hash = meta.block_hash;
// get all receipts for the block
let all_receipts = self

View File

@ -1,7 +1,10 @@
//! Contains RPC handler implementations specific to transactions
use reth_provider::{BlockReaderIdExt, TransactionsProvider};
use reth_rpc_eth_api::helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking};
use reth_rpc_eth_api::{
helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking},
FullEthApiTypes,
};
use reth_rpc_eth_types::EthStateCache;
use reth_transaction_pool::TransactionPool;
@ -28,7 +31,7 @@ where
impl<Provider, Pool, Network, EvmConfig> LoadTransaction
for EthApi<Provider, Pool, Network, EvmConfig>
where
Self: SpawnBlocking,
Self: SpawnBlocking + FullEthApiTypes,
Provider: TransactionsProvider,
Pool: TransactionPool,
{

View File

@ -0,0 +1,85 @@
//! L1 `eth` API types.
use alloy_network::{AnyNetwork, Network};
use reth_primitives::{Address, TransactionSignedEcRecovered, TxKind};
use reth_rpc_types::{Transaction, TransactionInfo, WithOtherFields};
use reth_rpc_types_compat::{
transaction::{from_primitive_signature, GasPrice},
TransactionCompat,
};
/// Builds RPC transaction response for l1.
#[derive(Debug, Clone, Copy)]
pub struct EthTxBuilder;
impl TransactionCompat for EthTxBuilder
where
Self: Send + Sync,
{
type Transaction = <AnyNetwork as Network>::TransactionResponse;
fn fill(tx: TransactionSignedEcRecovered, tx_info: TransactionInfo) -> Self::Transaction {
let signer = tx.signer();
let signed_tx = tx.into_signed();
let to: Option<Address> = match signed_tx.kind() {
TxKind::Create => None,
TxKind::Call(to) => Some(Address(*to)),
};
let TransactionInfo {
base_fee, block_hash, block_number, index: transaction_index, ..
} = tx_info;
let GasPrice { gas_price, max_fee_per_gas } =
Self::gas_price(&signed_tx, base_fee.map(|fee| fee as u64));
let chain_id = signed_tx.chain_id();
let blob_versioned_hashes = signed_tx.blob_versioned_hashes();
let access_list = signed_tx.access_list().cloned();
let authorization_list = signed_tx.authorization_list().map(|l| l.to_vec());
let signature = from_primitive_signature(
*signed_tx.signature(),
signed_tx.tx_type(),
signed_tx.chain_id(),
);
WithOtherFields {
inner: Transaction {
hash: signed_tx.hash(),
nonce: signed_tx.nonce(),
from: signer,
to,
value: signed_tx.value(),
gas_price,
max_fee_per_gas,
max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas(),
signature: Some(signature),
gas: signed_tx.gas_limit() as u128,
input: signed_tx.input().clone(),
chain_id,
access_list,
transaction_type: Some(signed_tx.tx_type() as u8),
// These fields are set to None because they are not stored as part of the
// transaction
block_hash,
block_number,
transaction_index,
// EIP-4844 fields
max_fee_per_blob_gas: signed_tx.max_fee_per_blob_gas(),
blob_versioned_hashes,
authorization_list,
},
..Default::default()
}
}
fn otterscan_api_truncate_input(tx: &mut Self::Transaction) {
tx.inner.input = tx.inner.input.slice(..4);
}
fn tx_type(tx: &Self::Transaction) -> u8 {
tx.inner.transaction_type.unwrap_or(0)
}
}

View File

@ -12,6 +12,6 @@ pub use core::EthApi;
pub use filter::EthFilter;
pub use pubsub::EthPubSub;
pub use helpers::signer::DevSigner;
pub use helpers::{signer::DevSigner, types::EthTxBuilder};
pub use reth_rpc_eth_api::EthApiServer;

View File

@ -1,6 +1,6 @@
//! `eth_` `PubSub` RPC handler implementation
use std::sync::Arc;
use std::{marker::PhantomData, sync::Arc};
use alloy_primitives::TxHash;
use futures::StreamExt;
@ -10,7 +10,7 @@ use jsonrpsee::{
use reth_network_api::NetworkInfo;
use reth_primitives::IntoRecoveredTransaction;
use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider};
use reth_rpc_eth_api::pubsub::EthPubSubApiServer;
use reth_rpc_eth_api::{pubsub::EthPubSubApiServer, FullEthApiTypes, RpcTransaction};
use reth_rpc_eth_types::logs_utils;
use reth_rpc_server_types::result::{internal_rpc_err, invalid_params_rpc_err};
use reth_rpc_types::{
@ -20,6 +20,7 @@ use reth_rpc_types::{
},
FilteredParams, Header, Log, Transaction, WithOtherFields,
};
use reth_rpc_types_compat::transaction::from_recovered;
use reth_tasks::{TaskSpawner, TokioTaskExecutor};
use reth_transaction_pool::{NewTransactionEvent, TransactionPool};
use serde::Serialize;
@ -32,16 +33,17 @@ use tokio_stream::{
///
/// This handles `eth_subscribe` RPC calls.
#[derive(Clone)]
pub struct EthPubSub<Provider, Pool, Events, Network> {
pub struct EthPubSub<Provider, Pool, Events, Network, Eth> {
/// All nested fields bundled together.
inner: Arc<EthPubSubInner<Provider, Pool, Events, Network>>,
/// The type that's used to spawn subscription tasks.
subscription_task_spawner: Box<dyn TaskSpawner>,
_tx_resp_builder: PhantomData<Eth>,
}
// === impl EthPubSub ===
impl<Provider, Pool, Events, Network> EthPubSub<Provider, Pool, Events, Network> {
impl<Provider, Pool, Events, Network, Eth> EthPubSub<Provider, Pool, Events, Network, Eth> {
/// Creates a new, shareable instance.
///
/// Subscription tasks are spawned via [`tokio::task::spawn`]
@ -64,18 +66,19 @@ impl<Provider, Pool, Events, Network> EthPubSub<Provider, Pool, Events, Network>
subscription_task_spawner: Box<dyn TaskSpawner>,
) -> Self {
let inner = EthPubSubInner { provider, pool, chain_events, network };
Self { inner: Arc::new(inner), subscription_task_spawner }
Self { inner: Arc::new(inner), subscription_task_spawner, _tx_resp_builder: PhantomData }
}
}
#[async_trait::async_trait]
impl<Provider, Pool, Events, Network> EthPubSubApiServer<reth_rpc_types::Transaction>
for EthPubSub<Provider, Pool, Events, Network>
impl<Provider, Pool, Events, Network, Eth> EthPubSubApiServer<RpcTransaction<Eth::NetworkTypes>>
for EthPubSub<Provider, Pool, Events, Network, Eth>
where
Provider: BlockReader + EvmEnvProvider + Clone + 'static,
Pool: TransactionPool + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
Network: NetworkInfo + Clone + 'static,
Eth: FullEthApiTypes + 'static,
{
/// Handler for `eth_subscribe`
async fn subscribe(
@ -87,7 +90,7 @@ where
let sink = pending.accept().await?;
let pubsub = self.inner.clone();
self.subscription_task_spawner.spawn(Box::pin(async move {
let _ = handle_accepted(pubsub, sink, kind, params).await;
let _ = handle_accepted::<_, _, _, _, Eth>(pubsub, sink, kind, params).await;
}));
Ok(())
@ -95,7 +98,7 @@ where
}
/// The actual handler for an accepted [`EthPubSub::subscribe`] call.
async fn handle_accepted<Provider, Pool, Events, Network>(
async fn handle_accepted<Provider, Pool, Events, Network, Eth>(
pubsub: Arc<EthPubSubInner<Provider, Pool, Events, Network>>,
accepted_sink: SubscriptionSink,
kind: SubscriptionKind,
@ -106,6 +109,7 @@ where
Pool: TransactionPool + 'static,
Events: CanonStateSubscriptions + Clone + 'static,
Network: NetworkInfo + Clone + 'static,
Eth: FullEthApiTypes,
{
match kind {
SubscriptionKind::NewHeads => {
@ -136,11 +140,11 @@ where
Params::Bool(true) => {
// full transaction objects requested
let stream = pubsub.full_pending_transaction_stream().map(|tx| {
EthSubscriptionResult::FullTransaction(Box::new(
reth_rpc_types_compat::transaction::from_recovered(
tx.transaction.to_recovered_transaction(),
),
))
EthSubscriptionResult::FullTransaction(Box::new(from_recovered::<
Eth::TransactionCompat,
>(
tx.transaction.to_recovered_transaction(),
)))
});
return pipe_from_stream(accepted_sink, stream).await
}
@ -246,8 +250,8 @@ where
}
}
impl<Provider, Pool, Events, Network> std::fmt::Debug
for EthPubSub<Provider, Pool, Events, Network>
impl<Provider, Pool, Events, Network, Eth> std::fmt::Debug
for EthPubSub<Provider, Pool, Events, Network, Eth>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EthPubSub").finish_non_exhaustive()

View File

@ -1,12 +1,12 @@
use alloy_eips::{BlockId, BlockNumberOrTag};
use alloy_network::Network;
use alloy_network::{ReceiptResponse, TransactionResponse};
use alloy_primitives::{Address, Bytes, TxHash, B256, U256};
use async_trait::async_trait;
use jsonrpsee::{core::RpcResult, types::ErrorObjectOwned};
use reth_primitives::{BlockId, BlockNumberOrTag};
use reth_rpc_api::{EthApiServer, OtterscanServer};
use reth_rpc_eth_api::{
helpers::{EthTransactions, TraceExt},
EthApiTypes, RpcBlock, RpcReceipt, RpcTransaction,
FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction, TransactionCompat,
};
use reth_rpc_eth_types::{utils::binary_search, EthApiError};
use reth_rpc_server_types::result::internal_rpc_err;
@ -18,13 +18,13 @@ use reth_rpc_types::{
},
parity::{Action, CreateAction, CreateOutput, TraceOutput},
},
AnyTransactionReceipt, BlockTransactions, Header, Transaction, WithOtherFields,
BlockTransactions, Header, TransactionReceipt,
};
use revm_inspectors::{
tracing::{types::CallTraceNode, TracingInspectorConfig},
transfer::{TransferInspector, TransferKind},
};
use revm_primitives::ExecutionResult;
use revm_primitives::{ExecutionResult, SignedAuthorization};
const API_LEVEL: u64 = 8;
@ -43,12 +43,7 @@ impl<Eth> OtterscanApi<Eth> {
impl<Eth> OtterscanApi<Eth>
where
Eth: EthApiTypes<
NetworkTypes: Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
>,
Eth: FullEthApiTypes,
{
/// Constructs a `BlockDetails` from a block and its receipts.
fn block_details(
@ -59,7 +54,7 @@ where
// blob fee is burnt, so we don't need to calculate it
let total_fees = receipts
.iter()
.map(|receipt| receipt.gas_used.saturating_mul(receipt.effective_gas_price))
.map(|receipt| receipt.gas_used().saturating_mul(receipt.effective_gas_price()))
.sum::<u128>();
Ok(BlockDetails::new(block, Default::default(), U256::from(total_fees)))
@ -67,19 +62,14 @@ where
}
#[async_trait]
impl<Eth> OtterscanServer for OtterscanApi<Eth>
impl<Eth> OtterscanServer<RpcTransaction<Eth::NetworkTypes>> for OtterscanApi<Eth>
where
Eth: EthApiServer<
RpcTransaction<Eth::NetworkTypes>,
RpcBlock<Eth::NetworkTypes>,
RpcReceipt<Eth::NetworkTypes>,
> + EthApiTypes<
NetworkTypes: Network<
TransactionResponse = WithOtherFields<reth_rpc_types::Transaction>,
ReceiptResponse = AnyTransactionReceipt,
>,
> + TraceExt
+ EthTransactions
> + EthTransactions<TransactionCompat: TransactionCompat>
+ TraceExt
+ 'static,
{
/// Handler for `{ots,erigon}_getHeaderByNumber`
@ -207,7 +197,7 @@ where
block_number: u64,
page_number: usize,
page_size: usize,
) -> RpcResult<OtsBlockTransactions<WithOtherFields<Transaction>>> {
) -> RpcResult<OtsBlockTransactions<RpcTransaction<Eth::NetworkTypes>>> {
let block_id = block_number.into();
// retrieve full block and its receipts
let block = self.eth.block_by_number(block_id, true);
@ -240,9 +230,9 @@ where
// The input field returns only the 4 bytes method selector instead of the entire
// calldata byte blob.
for tx in transactions {
if tx.input.len() > 4 {
tx.input = tx.input.slice(..4);
for tx in transactions.iter_mut() {
if tx.input().len() > 4 {
Eth::TransactionCompat::otterscan_api_truncate_input(tx);
}
}
@ -250,19 +240,34 @@ where
let timestamp = Some(block.header.timestamp);
let receipts = receipts
.drain(page_start..page_end)
.map(|receipt| {
let receipt = receipt.inner.map_inner(|receipt| OtsReceipt {
status: receipt
.inner
.receipt
.status
.as_eip658()
.expect("ETH API returned pre-EIP-658 status"),
cumulative_gas_used: receipt.inner.receipt.cumulative_gas_used as u64,
.zip(transactions.iter().map(Eth::TransactionCompat::tx_type))
.map(|(receipt, tx_ty)| {
let inner = OtsReceipt {
status: receipt.status(),
cumulative_gas_used: receipt.cumulative_gas_used() as u64,
logs: None,
logs_bloom: None,
r#type: receipt.r#type,
});
r#type: tx_ty,
};
let receipt = TransactionReceipt {
inner,
transaction_hash: receipt.transaction_hash(),
transaction_index: receipt.transaction_index(),
block_hash: receipt.block_hash(),
block_number: receipt.block_number(),
gas_used: receipt.gas_used(),
effective_gas_price: receipt.effective_gas_price(),
blob_gas_used: receipt.blob_gas_used(),
blob_gas_price: receipt.blob_gas_price(),
from: receipt.from(),
to: receipt.to(),
contract_address: receipt.contract_address(),
state_root: receipt.state_root(),
authorization_list: receipt
.authorization_list()
.map(<[SignedAuthorization]>::to_vec),
};
OtsTransactionReceipt { receipt, timestamp }
})
@ -305,7 +310,7 @@ where
.get_transaction_by_sender_and_nonce(sender, nonce, false)
.await
.map_err(Into::into)?
.map(|tx| tx.hash))
.map(|tx| tx.tx_hash()))
}
/// Handler for `getContractCreator`

View File

@ -1,56 +1,63 @@
use std::{collections::BTreeMap, marker::PhantomData};
use alloy_primitives::Address;
use async_trait::async_trait;
use jsonrpsee::core::RpcResult as Result;
use reth_primitives::TransactionSignedEcRecovered;
use reth_rpc_api::TxPoolApiServer;
use reth_rpc_types::{
txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
Transaction, WithOtherFields,
use reth_rpc_eth_api::{FullEthApiTypes, RpcTransaction};
use reth_rpc_types::txpool::{
TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus,
};
use reth_rpc_types_compat::{transaction::from_recovered, TransactionCompat};
use reth_transaction_pool::{AllPoolTransactions, PoolTransaction, TransactionPool};
use std::collections::BTreeMap;
use tracing::trace;
/// `txpool` API implementation.
///
/// This type provides the functionality for handling `txpool` related requests.
#[derive(Clone)]
pub struct TxPoolApi<Pool> {
pub struct TxPoolApi<Pool, Eth> {
/// An interface to interact with the pool
pool: Pool,
_tx_resp_builder: PhantomData<Eth>,
}
impl<Pool> TxPoolApi<Pool> {
impl<Pool, Eth> TxPoolApi<Pool, Eth> {
/// Creates a new instance of `TxpoolApi`.
pub const fn new(pool: Pool) -> Self {
Self { pool }
Self { pool, _tx_resp_builder: PhantomData }
}
}
impl<Pool> TxPoolApi<Pool>
impl<Pool, Eth> TxPoolApi<Pool, Eth>
where
Pool: TransactionPool + 'static,
Eth: FullEthApiTypes,
{
fn content(&self) -> TxpoolContent<WithOtherFields<Transaction>> {
fn content(&self) -> TxpoolContent<RpcTransaction<Eth::NetworkTypes>> {
#[inline]
fn insert<T: PoolTransaction<Consensus = TransactionSignedEcRecovered>>(
tx: &T,
content: &mut BTreeMap<Address, BTreeMap<String, WithOtherFields<Transaction>>>,
) {
fn insert<Tx, RpcTxB>(
tx: &Tx,
content: &mut BTreeMap<Address, BTreeMap<String, RpcTxB::Transaction>>,
) where
Tx: PoolTransaction<Consensus = TransactionSignedEcRecovered>,
RpcTxB: TransactionCompat,
{
content.entry(tx.sender()).or_default().insert(
tx.nonce().to_string(),
reth_rpc_types_compat::transaction::from_recovered(tx.clone().into_consensus()),
from_recovered::<RpcTxB>(tx.clone().into_consensus()),
);
}
let AllPoolTransactions { pending, queued } = self.pool.all_transactions();
let mut content = TxpoolContent::default();
let mut content = TxpoolContent { pending: BTreeMap::new(), queued: BTreeMap::new() };
for pending in pending {
insert(&pending.transaction, &mut content.pending);
insert::<_, Eth::TransactionCompat>(&pending.transaction, &mut content.pending);
}
for queued in queued {
insert(&queued.transaction, &mut content.queued);
insert::<_, Eth::TransactionCompat>(&queued.transaction, &mut content.queued);
}
content
@ -58,9 +65,10 @@ where
}
#[async_trait]
impl<Pool> TxPoolApiServer for TxPoolApi<Pool>
impl<Pool, Eth> TxPoolApiServer<RpcTransaction<Eth::NetworkTypes>> for TxPoolApi<Pool, Eth>
where
Pool: TransactionPool + 'static,
Eth: FullEthApiTypes + 'static,
{
/// Returns the number of transactions currently pending for inclusion in the next block(s), as
/// well as the ones that are being scheduled for future execution only.
@ -122,7 +130,7 @@ where
async fn txpool_content_from(
&self,
from: Address,
) -> Result<TxpoolContentFrom<WithOtherFields<Transaction>>> {
) -> Result<TxpoolContentFrom<RpcTransaction<Eth::NetworkTypes>>> {
trace!(target: "rpc::eth", ?from, "Serving txpool_contentFrom");
Ok(self.content().remove_from(&from))
}
@ -132,13 +140,13 @@ where
///
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details
/// Handler for `txpool_content`
async fn txpool_content(&self) -> Result<TxpoolContent<WithOtherFields<Transaction>>> {
async fn txpool_content(&self) -> Result<TxpoolContent<RpcTransaction<Eth::NetworkTypes>>> {
trace!(target: "rpc::eth", "Serving txpool_content");
Ok(self.content())
}
}
impl<Pool> std::fmt::Debug for TxPoolApi<Pool> {
impl<Pool, Eth> std::fmt::Debug for TxPoolApi<Pool, Eth> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TxpoolApi").finish_non_exhaustive()
}