mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(rpc): remove use of extensible transaction + receipt types (#9774)
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -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",
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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> {
|
||||
|
||||
@ -60,7 +60,6 @@ reth-tracing.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
|
||||
## ethereum
|
||||
alloy-network.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
|
||||
## async
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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::{
|
||||
|
||||
@ -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")]
|
||||
|
||||
@ -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>>;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")]
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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>>,
|
||||
>
|
||||
{
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 })
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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() };
|
||||
|
||||
@ -14,3 +14,5 @@ pub mod block;
|
||||
pub mod engine;
|
||||
pub mod proof;
|
||||
pub mod transaction;
|
||||
|
||||
pub use transaction::TransactionCompat;
|
||||
|
||||
@ -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`]
|
||||
|
||||
@ -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>,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
//! files.
|
||||
|
||||
pub mod signer;
|
||||
pub mod types;
|
||||
|
||||
mod block;
|
||||
mod call;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
{
|
||||
|
||||
85
crates/rpc/rpc/src/eth/helpers/types.rs
Normal file
85
crates/rpc/rpc/src/eth/helpers/types.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user