chore(rpc): move impl of eth api server out of reth-rpc-eth-api (#9135)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Emilia Hane
2024-06-27 14:34:17 +02:00
committed by GitHub
parent 933a1dea39
commit 1b9f5871f5
92 changed files with 2326 additions and 1798 deletions

63
Cargo.lock generated
View File

@ -6345,6 +6345,8 @@ dependencies = [
"reth-rpc",
"reth-rpc-api",
"reth-rpc-builder",
"reth-rpc-eth-types",
"reth-rpc-server-types",
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-stages",
@ -7604,6 +7606,7 @@ dependencies = [
"reth-prune-types",
"reth-rpc-api",
"reth-rpc-eth-api",
"reth-rpc-eth-types",
"reth-rpc-server-types",
"reth-rpc-types",
"reth-rpc-types-compat",
@ -7687,6 +7690,7 @@ dependencies = [
"clap",
"eyre",
"jsonrpsee",
"jsonrpsee-types",
"parking_lot 0.12.3",
"reqwest",
"reth",
@ -7710,6 +7714,8 @@ dependencies = [
"reth-provider",
"reth-revm",
"reth-rpc",
"reth-rpc-eth-api",
"reth-rpc-eth-types",
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-tracing",
@ -7996,6 +8002,7 @@ dependencies = [
name = "reth-rpc"
version = "1.0.0"
dependencies = [
"alloy-dyn-abi",
"alloy-genesis",
"alloy-primitives",
"alloy-rlp",
@ -8006,12 +8013,17 @@ dependencies = [
"http-body",
"hyper",
"jsonrpsee",
"jsonrpsee-types",
"jsonwebtoken",
"parking_lot 0.12.3",
"pin-project",
"rand 0.8.5",
"reth-chainspec",
"reth-consensus-common",
"reth-errors",
"reth-evm",
"reth-evm-ethereum",
"reth-evm-optimism",
"reth-network-api",
"reth-network-peers",
"reth-primitives",
@ -8020,6 +8032,8 @@ dependencies = [
"reth-rpc-api",
"reth-rpc-engine-api",
"reth-rpc-eth-api",
"reth-rpc-eth-types",
"reth-rpc-server-types",
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-tasks",
@ -8028,8 +8042,13 @@ dependencies = [
"revm",
"revm-inspectors",
"revm-primitives",
"secp256k1",
"serde",
"serde_json",
"tempfile",
"thiserror",
"tokio",
"tokio-stream",
"tower",
"tracing",
"tracing-futures",
@ -8089,6 +8108,7 @@ dependencies = [
"reth-rpc",
"reth-rpc-api",
"reth-rpc-engine-api",
"reth-rpc-eth-types",
"reth-rpc-layer",
"reth-rpc-server-types",
"reth-rpc-types",
@ -8144,25 +8164,48 @@ name = "reth-rpc-eth-api"
version = "1.0.0"
dependencies = [
"alloy-dyn-abi",
"alloy-sol-types",
"async-trait",
"auto_impl",
"derive_more",
"dyn-clone",
"futures",
"jsonrpsee",
"parking_lot 0.12.3",
"reth-chainspec",
"reth-errors",
"reth-evm",
"reth-execution-types",
"reth-primitives",
"reth-provider",
"reth-revm",
"reth-rpc-eth-types",
"reth-rpc-server-types",
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-tasks",
"reth-transaction-pool",
"revm",
"revm-inspectors",
"revm-primitives",
"tokio",
"tracing",
]
[[package]]
name = "reth-rpc-eth-types"
version = "1.0.0"
dependencies = [
"alloy-sol-types",
"derive_more",
"futures",
"jsonrpsee-core",
"jsonrpsee-types",
"metrics",
"parking_lot 0.12.3",
"rand 0.8.5",
"reth-chainspec",
"reth-errors",
"reth-evm",
"reth-evm-ethereum",
"reth-evm-optimism",
"reth-execution-types",
"reth-metrics",
"reth-network-api",
"reth-primitives",
"reth-provider",
"reth-revm",
@ -8170,14 +8213,12 @@ dependencies = [
"reth-rpc-types",
"reth-rpc-types-compat",
"reth-tasks",
"reth-testing-utils",
"reth-transaction-pool",
"reth-trie",
"revm",
"revm-inspectors",
"revm-primitives",
"schnellru",
"secp256k1",
"serde",
"serde_json",
"thiserror",
@ -8208,6 +8249,12 @@ name = "reth-rpc-server-types"
version = "1.0.0"
dependencies = [
"alloy-primitives",
"jsonrpsee-core",
"jsonrpsee-types",
"reth-errors",
"reth-network-api",
"reth-primitives",
"reth-rpc-types",
"serde",
"strum",
]

View File

@ -81,8 +81,10 @@ members = [
"crates/rpc/rpc-builder/",
"crates/rpc/rpc-engine-api/",
"crates/rpc/rpc-eth-api/",
"crates/rpc/rpc-eth-types/",
"crates/rpc/rpc-layer",
"crates/rpc/rpc-testing-util/",
"crates/rpc/rpc-server-types/",
"crates/rpc/rpc-types-compat/",
"crates/rpc/rpc-types/",
"crates/rpc/rpc/",
@ -342,6 +344,7 @@ reth-rpc-builder = { path = "crates/rpc/rpc-builder" }
reth-rpc-engine-api = { path = "crates/rpc/rpc-engine-api" }
reth-rpc-eth-api = { path = "crates/rpc/rpc-eth-api" }
reth-rpc-layer = { path = "crates/rpc/rpc-layer" }
reth-rpc-eth-types = { path = "crates/rpc/rpc-eth-types" }
reth-rpc-server-types = { path = "crates/rpc/rpc-server-types" }
reth-rpc-types = { path = "crates/rpc/rpc-types" }
reth-rpc-types-compat = { path = "crates/rpc/rpc-types-compat" }

View File

@ -37,6 +37,8 @@ reth-rpc.workspace = true
reth-rpc-types.workspace = true
reth-rpc-types-compat.workspace = true
reth-rpc-api = { workspace = true, features = ["client"] }
reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true
reth-network = { workspace = true, features = ["serde"] }
reth-network-p2p.workspace = true
reth-net-banlist.workspace = true
@ -153,6 +155,7 @@ optimism = [
"reth-blockchain-tree/optimism",
"dep:reth-node-optimism",
"reth-node-core/optimism",
"reth-rpc-eth-types/optimism",
]
# no-op feature flag for switching between the `optimism` and default functionality in CI matrices

View File

@ -148,6 +148,15 @@ pub mod rpc {
pub use reth_rpc_types::*;
}
/// Re-exported from `reth_rpc_server_types`.
pub mod server_types {
pub use reth_rpc_server_types::*;
/// Re-exported from `reth_rpc_eth_types`.
pub mod eth {
pub use reth_rpc_eth_types::*;
}
}
/// Re-exported from `reth_rpc_api`.
pub mod api {
pub use reth_rpc_api::*;
@ -159,10 +168,10 @@ pub mod rpc {
/// Re-exported from `reth_rpc::rpc`.
pub mod result {
pub use reth_rpc::result::*;
pub use reth_rpc_server_types::result::*;
}
/// Re-exported from `reth_rpc::eth`.
/// Re-exported from `reth_rpc_types_compat`.
pub mod compat {
pub use reth_rpc_types_compat::*;
}

View File

@ -1,8 +1,13 @@
use alloy_consensus::TxEnvelope;
use alloy_network::eip2718::Decodable2718;
use reth::{api::FullNodeComponents, builder::rpc::RpcRegistry, rpc::api::DebugApiServer};
use reth::{
builder::{rpc::RpcRegistry, FullNodeComponents},
rpc::{
api::{eth::helpers::EthTransactions, DebugApiServer},
server_types::eth::EthResult,
},
};
use reth_primitives::{Bytes, B256};
use reth_rpc::eth::{servers::EthTransactions, EthResult};
pub struct RpcTestContext<Node: FullNodeComponents> {
pub inner: RpcRegistry<Node>,

View File

@ -1,12 +1,14 @@
use crate::utils::EthNode;
use std::sync::Arc;
use alloy_genesis::Genesis;
use alloy_primitives::{b256, hex};
use futures::StreamExt;
use reth::rpc::eth::servers::EthTransactions;
use reth::rpc::api::eth::helpers::EthTransactions;
use reth_chainspec::ChainSpec;
use reth_e2e_test_utils::setup;
use reth_provider::CanonStateSubscriptions;
use std::sync::Arc;
use crate::utils::EthNode;
#[tokio::test]
async fn can_run_dev_node() -> eyre::Result<()> {

View File

@ -21,6 +21,7 @@ reth-storage-errors.workspace = true
reth-provider.workspace = true
reth-network = { workspace = true, features = ["serde"] }
reth-network-p2p.workspace = true
reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true
reth-rpc-types.workspace = true
reth-rpc-types-compat.workspace = true
@ -103,6 +104,7 @@ optimism = [
"reth-rpc-types-compat/optimism",
"reth-beacon-consensus/optimism",
"reth-rpc-eth-api/optimism",
"reth-rpc-eth-types/optimism"
]
jemalloc = ["dep:tikv-jemalloc-ctl"]

View File

@ -1,6 +1,6 @@
use crate::primitives::U256;
use clap::Args;
use reth_rpc_eth_api::GasPriceOracleConfig;
use reth_rpc_eth_types::GasPriceOracleConfig;
use reth_rpc_server_types::constants::gas_oracle::{
DEFAULT_GAS_PRICE_BLOCKS, DEFAULT_GAS_PRICE_PERCENTILE, DEFAULT_IGNORE_GAS_PRICE,
DEFAULT_MAX_GAS_PRICE,

View File

@ -1,22 +1,22 @@
//! clap [Args](clap::Args) for RPC related arguments.
use crate::args::{
types::{MaxU32, ZeroAsNoneU64},
GasPriceOracleArgs, RpcStateCacheArgs,
use std::{
ffi::OsStr,
net::{IpAddr, Ipv4Addr},
path::PathBuf,
};
use alloy_rpc_types_engine::JwtSecret;
use clap::{
builder::{PossibleValue, RangedU64ValueParser, TypedValueParser},
Arg, Args, Command,
};
use rand::Rng;
use reth_rpc_eth_api::RPC_DEFAULT_GAS_CAP;
use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
use std::{
ffi::OsStr,
net::{IpAddr, Ipv4Addr},
path::PathBuf,
use crate::args::{
types::{MaxU32, ZeroAsNoneU64},
GasPriceOracleArgs, RpcStateCacheArgs,
};
/// Default max number of subscriptions per connection.
@ -152,7 +152,7 @@ pub struct RpcServerArgs {
alias = "rpc-gascap",
value_name = "GAS_CAP",
value_parser = RangedU64ValueParser::<u64>::new().range(1..),
default_value_t = RPC_DEFAULT_GAS_CAP.into()
default_value_t = constants::gas_oracle::RPC_DEFAULT_GAS_CAP
)]
pub rpc_gas_cap: u64,
@ -285,7 +285,7 @@ impl Default for RpcServerArgs {
rpc_max_tracing_requests: constants::default_max_tracing_requests(),
rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(),
rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
gas_price_oracle: GasPriceOracleArgs::default(),
rpc_state_cache: RpcStateCacheArgs::default(),
}

View File

@ -43,7 +43,7 @@ pub mod rpc {
/// Re-exported from `reth_rpc::rpc`.
pub mod result {
pub use reth_rpc_eth_api::result::*;
pub use reth_rpc_server_types::result::*;
}
/// Re-exported from `reth_rpc::eth`.

View File

@ -35,6 +35,8 @@ reth-beacon-consensus.workspace = true
reth-optimism-consensus.workspace = true
revm-primitives.workspace = true
reth-discv5.workspace = true
reth-rpc-eth-types.workspace = true
reth-rpc-eth-api.workspace = true
# async
async-trait.workspace = true
@ -44,11 +46,14 @@ tracing.workspace = true
# misc
clap.workspace = true
serde.workspace = true
serde_json.workspace = true
eyre.workspace = true
parking_lot.workspace = true
thiserror.workspace = true
# rpc
jsonrpsee.workspace = true
jsonrpsee-types.workspace = true
serde_json.workspace = true
[dev-dependencies]
reth.workspace = true
@ -71,4 +76,5 @@ optimism = [
"reth-beacon-consensus/optimism",
"reth-revm/optimism",
"reth-auto-seal-consensus/optimism",
"reth-rpc-eth-types/optimism"
]

View File

@ -1,14 +1,13 @@
//! Helpers for optimism specific RPC implementations.
use jsonrpsee::types::ErrorObject;
use reqwest::Client;
use reth_rpc::eth::{
error::{EthApiError, EthResult},
servers::RawTransactionForwarder,
};
use reth_rpc_types::ToRpcError;
use std::sync::{atomic::AtomicUsize, Arc};
use jsonrpsee_types::error::{ErrorObject, INTERNAL_ERROR_CODE};
use reqwest::Client;
use reth_rpc_eth_api::RawTransactionForwarder;
use reth_rpc_eth_types::error::{EthApiError, EthResult};
use reth_rpc_types::ToRpcError;
/// Error type when interacting with the Sequencer
#[derive(Debug, thiserror::Error)]
pub enum SequencerRpcError {
@ -22,11 +21,7 @@ pub enum SequencerRpcError {
impl ToRpcError for SequencerRpcError {
fn to_rpc_error(&self) -> ErrorObject<'static> {
ErrorObject::owned(
jsonrpsee::types::error::INTERNAL_ERROR_CODE,
self.to_string(),
None::<String>,
)
ErrorObject::owned(INTERNAL_ERROR_CODE, self.to_string(), None::<String>)
}
}

View File

@ -51,7 +51,7 @@ pub mod servers {
web3::Web3ApiServer,
};
pub use reth_rpc_eth_api::{
EthApiServer, EthBundleApiServer, EthCallBundleApiServer, EthFilterApiServer,
self as eth, EthApiServer, EthBundleApiServer, EthCallBundleApiServer, EthFilterApiServer,
EthPubSubApiServer,
};
}

View File

@ -20,6 +20,7 @@ reth-provider.workspace = true
reth-rpc.workspace = true
reth-rpc-api.workspace = true
reth-rpc-layer.workspace = true
reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true
reth-tasks = { workspace = true, features = ["rayon"] }
reth-transaction-pool.workspace = true

View File

@ -1,3 +1,5 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use crate::error::{RpcError, ServerKind};
use http::header::AUTHORIZATION;
use jsonrpsee::{
@ -7,14 +9,13 @@ use jsonrpsee::{
Methods,
};
use reth_engine_primitives::EngineTypes;
use reth_rpc::eth::EthSubscriptionIdProvider;
use reth_rpc_api::servers::*;
use reth_rpc_api::*;
use reth_rpc_eth_types::EthSubscriptionIdProvider;
use reth_rpc_layer::{
secret_to_bearer_header, AuthClientLayer, AuthClientService, AuthLayer, JwtAuthValidator,
JwtSecret,
};
use reth_rpc_server_types::constants;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tower::layer::util::Identity;
pub use jsonrpsee::server::ServerBuilder;

View File

@ -4,7 +4,7 @@ use crate::{
};
use jsonrpsee::server::ServerBuilder;
use reth_node_core::{args::RpcServerArgs, utils::get_or_create_jwt_secret_from_path};
use reth_rpc::eth::{EthStateCacheConfig, GasPriceOracleConfig};
use reth_rpc_eth_types::{EthStateCacheConfig, GasPriceOracleConfig};
use reth_rpc_layer::{JwtError, JwtSecret};
use reth_rpc_server_types::RpcModuleSelection;
use std::{net::SocketAddr, path::PathBuf};
@ -214,11 +214,13 @@ impl RethRpcServerConfig for RpcServerArgs {
#[cfg(test)]
mod tests {
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use clap::{Args, Parser};
use reth_node_core::args::RpcServerArgs;
use reth_rpc::eth::RPC_DEFAULT_GAS_CAP;
use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use reth_rpc_server_types::{
constants, constants::gas_oracle::RPC_DEFAULT_GAS_CAP, RethRpcModule, RpcModuleSelection,
};
use crate::config::RethRpcServerConfig;

View File

@ -6,14 +6,15 @@ use reth_provider::{
AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader,
EvmEnvProvider, StateProviderFactory,
};
use reth_rpc::eth::{
cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task,
servers::RawTransactionForwarder, EthApi, EthFilter, EthFilterConfig, EthPubSub, EthStateCache,
use reth_rpc::eth::{EthApi, EthFilter, EthFilterConfig, EthPubSub, RawTransactionForwarder};
use reth_rpc_eth_types::{
cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task, EthStateCache,
EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
GasPriceOracleConfig, RPC_DEFAULT_GAS_CAP,
GasPriceOracleConfig,
};
use reth_rpc_server_types::constants::{
default_max_tracing_requests, DEFAULT_MAX_BLOCKS_PER_FILTER, DEFAULT_MAX_LOGS_PER_RESPONSE,
default_max_tracing_requests, gas_oracle::RPC_DEFAULT_GAS_CAP, DEFAULT_MAX_BLOCKS_PER_FILTER,
DEFAULT_MAX_LOGS_PER_RESPONSE,
};
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
use reth_transaction_pool::TransactionPool;
@ -274,7 +275,7 @@ impl Default for EthConfig {
max_tracing_requests: default_max_tracing_requests(),
max_blocks_per_filter: DEFAULT_MAX_BLOCKS_PER_FILTER,
max_logs_per_response: DEFAULT_MAX_LOGS_PER_RESPONSE,
rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(),
rpc_gas_cap: RPC_DEFAULT_GAS_CAP,
stale_filter_ttl: DEFAULT_STALE_FILTER_TTL,
fee_history_cache: FeeHistoryCacheConfig::default(),
}

View File

@ -178,14 +178,12 @@ use reth_provider::{
ChangeSetReader, EvmEnvProvider, StateProviderFactory,
};
use reth_rpc::{
eth::{
servers::RawTransactionForwarder, EthApi, EthBundle, EthStateCache,
EthSubscriptionIdProvider,
},
eth::{EthApi, EthBundle, RawTransactionForwarder},
AdminApi, DebugApi, EngineEthApi, NetApi, OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi,
Web3Api,
};
use reth_rpc_api::servers::*;
use reth_rpc_api::*;
use reth_rpc_eth_types::{EthStateCache, EthSubscriptionIdProvider};
use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret};
use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool};
@ -998,7 +996,7 @@ where
///
/// This will spawn the required service tasks for [`EthApi`] for:
/// - [`EthStateCache`]
/// - [`reth_rpc::eth::FeeHistoryCache`]
/// - [`FeeHistoryCache`](reth_rpc_eth_types::FeeHistoryCache)
fn with_eth<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&EthHandlers<Provider, Pool, Network, Events, EvmConfig>) -> R,

View File

@ -6,7 +6,7 @@ rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
description = "Reth RPC `eth_` API implementation"
description = "Reth RPC 'eth' namespace API"
[lints]
workspace = true
@ -18,61 +18,40 @@ revm-inspectors = { workspace = true, features = ["js-tracer"] }
revm-primitives = { workspace = true, features = ["dev"] }
reth-errors.workspace = true
reth-evm.workspace = true
reth-metrics.workspace = true
reth-network-api.workspace = true
reth-primitives.workspace = true
reth-provider.workspace = true
reth-revm.workspace = true
reth-rpc-server-types.workspace = true
reth-rpc-types.workspace = true
reth-rpc-types-compat.workspace = true
reth-tasks = { workspace = true, features = ["rayon"] }
reth-trie.workspace = true
reth-transaction-pool.workspace = true
reth-evm-optimism = { workspace = true, optional = true }
reth-chainspec.workspace = true
reth-execution-types.workspace = true
reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true
# ethereum
alloy-dyn-abi = { workspace = true, features = ["eip712"] }
alloy-sol-types.workspace = true
secp256k1.workspace = true
# rpc
jsonrpsee = { workspace = true, features = ["server", "macros"] }
jsonrpsee-types = { workspace = true, optional = true }
serde_json.workspace = true
# async
async-trait.workspace = true
futures.workspace = true
parking_lot.workspace = true
tokio.workspace = true
tokio-stream.workspace = true
# misc
auto_impl.workspace = true
derive_more.workspace = true
dyn-clone.workspace = true
metrics.workspace = true
rand.workspace = true
schnellru.workspace = true
serde.workspace = true
thiserror.workspace = true
tracing.workspace = true
[dev-dependencies]
reth-evm-ethereum.workspace = true
reth-testing-utils.workspace = true
reth-transaction-pool = { workspace = true, features = ["test-utils"] }
reth-provider = { workspace = true, features = ["test-utils"] }
[features]
client = ["jsonrpsee/client", "jsonrpsee/async-client"]
optimism = [
"reth-primitives/optimism",
"reth-evm-optimism",
"revm/optimism",
"reth-provider/optimism",
"jsonrpsee-types",
"reth-rpc-eth-types/optimism"
]

View File

@ -1,318 +0,0 @@
//! `eth_` RPC API.
use alloy_dyn_abi::TypedData;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
use reth_rpc_types::{
serde_helpers::JsonStorageKey, state::StateOverride, AccessListWithGasUsed,
AnyTransactionReceipt, BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse,
FeeHistory, Header, Index, RichBlock, StateContext, SyncStatus, Transaction,
TransactionRequest, Work,
};
pub mod bundle;
pub mod filter;
pub mod pubsub;
pub mod servers;
/// Eth rpc interface: <https://ethereum.github.io/execution-apis/api-documentation/>
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
pub trait EthApi {
/// Returns the protocol version encoded as a string.
#[method(name = "protocolVersion")]
async fn protocol_version(&self) -> RpcResult<U64>;
/// Returns an object with data about the sync status or false.
#[method(name = "syncing")]
fn syncing(&self) -> RpcResult<SyncStatus>;
/// Returns the client coinbase address.
#[method(name = "coinbase")]
async fn author(&self) -> RpcResult<Address>;
/// Returns a list of addresses owned by client.
#[method(name = "accounts")]
fn accounts(&self) -> RpcResult<Vec<Address>>;
/// Returns the number of most recent block.
#[method(name = "blockNumber")]
fn block_number(&self) -> RpcResult<U256>;
/// Returns the chain ID of the current network.
#[method(name = "chainId")]
async fn chain_id(&self) -> RpcResult<Option<U64>>;
/// Returns information about a block by hash.
#[method(name = "getBlockByHash")]
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<RichBlock>>;
/// Returns information about a block by number.
#[method(name = "getBlockByNumber")]
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> RpcResult<Option<RichBlock>>;
/// Returns the number of transactions in a block from a block matching the given block hash.
#[method(name = "getBlockTransactionCountByHash")]
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
/// Returns the number of transactions in a block matching the given block number.
#[method(name = "getBlockTransactionCountByNumber")]
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>>;
/// Returns the number of uncles in a block from a block matching the given block hash.
#[method(name = "getUncleCountByBlockHash")]
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
/// Returns the number of uncles in a block with given block number.
#[method(name = "getUncleCountByBlockNumber")]
async fn block_uncles_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>>;
/// Returns all transaction receipts for a given block.
#[method(name = "getBlockReceipts")]
async fn block_receipts(
&self,
block_id: BlockId,
) -> RpcResult<Option<Vec<AnyTransactionReceipt>>>;
/// Returns an uncle block of the given block and index.
#[method(name = "getUncleByBlockHashAndIndex")]
async fn uncle_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<RichBlock>>;
/// Returns an uncle block of the given block and index.
#[method(name = "getUncleByBlockNumberAndIndex")]
async fn uncle_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<RichBlock>>;
/// Returns the EIP-2718 encoded transaction if it exists.
///
/// If this is a EIP-4844 transaction that is in the pool it will include the sidecar.
#[method(name = "getRawTransactionByHash")]
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>>;
/// Returns the information about a transaction requested by transaction hash.
#[method(name = "getTransactionByHash")]
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Transaction>>;
/// Returns information about a raw transaction by block hash and transaction index position.
#[method(name = "getRawTransactionByBlockHashAndIndex")]
async fn raw_transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Bytes>>;
/// Returns information about a transaction by block hash and transaction index position.
#[method(name = "getTransactionByBlockHashAndIndex")]
async fn transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Transaction>>;
/// Returns information about a raw transaction by block number and transaction index
/// position.
#[method(name = "getRawTransactionByBlockNumberAndIndex")]
async fn raw_transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Bytes>>;
/// Returns information about a transaction by block number and transaction index position.
#[method(name = "getTransactionByBlockNumberAndIndex")]
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Transaction>>;
/// Returns the receipt of a transaction by transaction hash.
#[method(name = "getTransactionReceipt")]
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<AnyTransactionReceipt>>;
/// Returns the balance of the account of given address.
#[method(name = "getBalance")]
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256>;
/// Returns the value from a storage position at a given address
#[method(name = "getStorageAt")]
async fn storage_at(
&self,
address: Address,
index: JsonStorageKey,
block_number: Option<BlockId>,
) -> RpcResult<B256>;
/// Returns the number of transactions sent from an address at given block number.
#[method(name = "getTransactionCount")]
async fn transaction_count(
&self,
address: Address,
block_number: Option<BlockId>,
) -> RpcResult<U256>;
/// Returns code at a given address at given block number.
#[method(name = "getCode")]
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes>;
/// Returns the block's header at given number.
#[method(name = "getHeaderByNumber")]
async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult<Option<Header>>;
/// Returns the block's header at given hash.
#[method(name = "getHeaderByHash")]
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<Header>>;
/// Executes a new message call immediately without creating a transaction on the block chain.
#[method(name = "call")]
async fn call(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes>;
/// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the
/// optionality of state overrides
#[method(name = "callMany")]
async fn call_many(
&self,
bundle: Bundle,
state_context: Option<StateContext>,
state_override: Option<StateOverride>,
) -> RpcResult<Vec<EthCallResponse>>;
/// Generates an access list for a transaction.
///
/// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction.
///
/// An access list contains all storage slots and addresses touched by the transaction, except
/// for the sender account and the chain's precompiles.
///
/// It returns list of addresses and storage keys used by the transaction, plus the gas
/// consumed when the access list is added. That is, it gives you the list of addresses and
/// storage keys that will be used by that transaction, plus the gas consumed if the access
/// list is included. Like eth_estimateGas, this is an estimation; the list could change
/// when the transaction is actually mined. Adding an accessList to your transaction does
/// not necessary result in lower gas usage compared to a transaction without an access
/// list.
#[method(name = "createAccessList")]
async fn create_access_list(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
) -> RpcResult<AccessListWithGasUsed>;
/// Generates and returns an estimate of how much gas is necessary to allow the transaction to
/// complete.
#[method(name = "estimateGas")]
async fn estimate_gas(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_override: Option<StateOverride>,
) -> RpcResult<U256>;
/// Returns the current price per gas in wei.
#[method(name = "gasPrice")]
async fn gas_price(&self) -> RpcResult<U256>;
/// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions.
#[method(name = "maxPriorityFeePerGas")]
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256>;
/// Introduced in EIP-4844, returns the current blob base fee in wei.
#[method(name = "blobBaseFee")]
async fn blob_base_fee(&self) -> RpcResult<U256>;
/// Returns the Transaction fee history
///
/// Introduced in EIP-1559 for getting information on the appropriate priority fee to use.
///
/// Returns transaction base fee per gas and effective priority fee per gas for the
/// requested/supported block range. The returned Fee history for the returned block range
/// can be a subsection of the requested range if not all blocks are available.
#[method(name = "feeHistory")]
async fn fee_history(
&self,
block_count: U64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> RpcResult<FeeHistory>;
/// Returns whether the client is actively mining new blocks.
#[method(name = "mining")]
async fn is_mining(&self) -> RpcResult<bool>;
/// Returns the number of hashes per second that the node is mining with.
#[method(name = "hashrate")]
async fn hashrate(&self) -> RpcResult<U256>;
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met
/// (“target”)
#[method(name = "getWork")]
async fn get_work(&self) -> RpcResult<Work>;
/// Used for submitting mining hashrate.
///
/// Can be used for remote miners to submit their hash rate.
/// It accepts the miner hash rate and an identifier which must be unique between nodes.
/// Returns `true` if the block was successfully submitted, `false` otherwise.
#[method(name = "submitHashrate")]
async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult<bool>;
/// Used for submitting a proof-of-work solution.
#[method(name = "submitWork")]
async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult<bool>;
/// Sends transaction; will block waiting for signer to return the
/// transaction hash.
#[method(name = "sendTransaction")]
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256>;
/// Sends signed transaction, returning its hash.
#[method(name = "sendRawTransaction")]
async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
/// Returns an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n"
/// + len(message) + message))).
#[method(name = "sign")]
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes>;
/// Signs a transaction that can be submitted to the network at a later time using with
/// `sendRawTransaction.`
#[method(name = "signTransaction")]
async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult<Bytes>;
/// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
#[method(name = "signTypedData")]
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes>;
/// Returns the account and storage values of the specified account including the Merkle-proof.
/// This call can be used to verify that the data you are pulling from is not tampered with.
#[method(name = "getProof")]
async fn get_proof(
&self,
address: Address,
keys: Vec<JsonStorageKey>,
block_number: Option<BlockId>,
) -> RpcResult<EIP1186AccountProofResponse>;
}

View File

@ -1,323 +0,0 @@
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait
//! Handles RPC requests for the `eth_` namespace.
use std::sync::Arc;
use reth_primitives::{BlockNumberOrTag, U256};
use reth_provider::{BlockReaderIdExt, ChainSpecProvider};
pub mod bundle;
pub mod filter;
pub mod helpers;
pub mod pubsub;
mod server;
pub use helpers::{
signer::DevSigner,
traits::{
block::{EthBlocks, LoadBlock},
blocking_task::SpawnBlocking,
call::{Call, EthCall},
fee::{EthFees, LoadFee},
pending_block::LoadPendingBlock,
receipt::LoadReceipt,
signer::EthSigner,
spec::EthApiSpec,
state::{EthState, LoadState},
trace::Trace,
transaction::{EthTransactions, LoadTransaction, RawTransactionForwarder},
TraceExt,
},
};
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
use tokio::sync::Mutex;
use crate::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock};
/// `Eth` API implementation.
///
/// This type provides the functionality for handling `eth_` related requests.
/// These are implemented two-fold: Core functionality is implemented as [`EthApiSpec`]
/// trait. Additionally, the required server implementations (e.g.
/// [`EthApiServer`](crate::EthApiServer)) are implemented separately in submodules. The rpc handler
/// implementation can then delegate to the main impls. This way [`EthApi`] is not limited to
/// [`jsonrpsee`] and can be used standalone or in other network handlers (for example ipc).
pub struct EthApi<Provider, Pool, Network, EvmConfig> {
/// All nested fields bundled together.
inner: Arc<EthApiInner<Provider, Pool, Network, EvmConfig>>,
}
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
/// Sets a forwarder for `eth_sendRawTransaction`
///
/// Note: this might be removed in the future in favor of a more generic approach.
pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc<dyn RawTransactionForwarder>) {
self.inner.raw_transaction_forwarder.write().replace(forwarder);
}
}
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
where
Provider: BlockReaderIdExt + ChainSpecProvider,
{
/// Creates a new, shareable instance using the default tokio task spawner.
#[allow(clippy::too_many_arguments)]
pub fn new(
provider: Provider,
pool: Pool,
network: Network,
eth_cache: EthStateCache,
gas_oracle: GasPriceOracle<Provider>,
gas_cap: impl Into<GasCap>,
blocking_task_pool: BlockingTaskPool,
fee_history_cache: FeeHistoryCache,
evm_config: EvmConfig,
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
) -> Self {
Self::with_spawner(
provider,
pool,
network,
eth_cache,
gas_oracle,
gas_cap.into().into(),
Box::<TokioTaskExecutor>::default(),
blocking_task_pool,
fee_history_cache,
evm_config,
raw_transaction_forwarder,
)
}
/// Creates a new, shareable instance.
#[allow(clippy::too_many_arguments)]
pub fn with_spawner(
provider: Provider,
pool: Pool,
network: Network,
eth_cache: EthStateCache,
gas_oracle: GasPriceOracle<Provider>,
gas_cap: u64,
task_spawner: Box<dyn TaskSpawner>,
blocking_task_pool: BlockingTaskPool,
fee_history_cache: FeeHistoryCache,
evm_config: EvmConfig,
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
) -> Self {
// get the block number of the latest block
let latest_block = provider
.header_by_number_or_tag(BlockNumberOrTag::Latest)
.ok()
.flatten()
.map(|header| header.number)
.unwrap_or_default();
let inner = EthApiInner {
provider,
pool,
network,
signers: parking_lot::RwLock::new(Default::default()),
eth_cache,
gas_oracle,
gas_cap,
starting_block: U256::from(latest_block),
task_spawner,
pending_block: Default::default(),
blocking_task_pool,
fee_history_cache,
evm_config,
raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder),
};
Self { inner: Arc::new(inner) }
}
/// Returns the state cache frontend
pub fn cache(&self) -> &EthStateCache {
&self.inner.eth_cache
}
/// Returns the gas oracle frontend
pub fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
&self.inner.gas_oracle
}
/// Returns the configured gas limit cap for `eth_call` and tracing related calls
pub fn gas_cap(&self) -> u64 {
self.inner.gas_cap
}
/// Returns the inner `Provider`
pub fn provider(&self) -> &Provider {
&self.inner.provider
}
/// Returns the inner `Network`
pub fn network(&self) -> &Network {
&self.inner.network
}
/// Returns the inner `Pool`
pub fn pool(&self) -> &Pool {
&self.inner.pool
}
/// Returns fee history cache
pub fn fee_history_cache(&self) -> &FeeHistoryCache {
&self.inner.fee_history_cache
}
}
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
for EthApi<Provider, Pool, Network, EvmConfig>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EthApi").finish_non_exhaustive()
}
}
impl<Provider, Pool, Network, EvmConfig> Clone for EthApi<Provider, Pool, Network, EvmConfig> {
fn clone(&self) -> Self {
Self { inner: Arc::clone(&self.inner) }
}
}
/// Implements [`SpawnBlocking`] for a type, that has similar data layout to [`EthApi`].
#[macro_export]
macro_rules! spawn_blocking_impl {
($network_api:ty) => {
impl<Provider, Pool, Network, EvmConfig> $crate::servers::SpawnBlocking for $network_api
where
Self: Clone + Send + Sync + 'static,
{
#[inline]
fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner {
self.inner.task_spawner()
}
#[inline]
fn tracing_task_pool(&self) -> &reth_tasks::pool::BlockingTaskPool {
self.inner.blocking_task_pool()
}
}
};
}
spawn_blocking_impl!(EthApi<Provider, Pool, Network, EvmConfig>);
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
/// Generates 20 random developer accounts.
/// Used in DEV mode.
pub fn with_dev_accounts(&self) {
let mut signers = self.inner.signers.write();
*signers = DevSigner::random_signers(20);
}
}
/// Container type `EthApi`
#[allow(missing_debug_implementations)]
pub struct EthApiInner<Provider, Pool, Network, EvmConfig> {
/// The transaction pool.
pool: Pool,
/// The provider that can interact with the chain.
provider: Provider,
/// An interface to interact with the network
network: Network,
/// All configured Signers
signers: parking_lot::RwLock<Vec<Box<dyn EthSigner>>>,
/// The async cache frontend for eth related data
eth_cache: EthStateCache,
/// The async gas oracle frontend for gas price suggestions
gas_oracle: GasPriceOracle<Provider>,
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
gas_cap: u64,
/// The block number at which the node started
starting_block: U256,
/// The type that can spawn tasks which would otherwise block.
task_spawner: Box<dyn TaskSpawner>,
/// Cached pending block if any
pending_block: Mutex<Option<PendingBlock>>,
/// A pool dedicated to CPU heavy blocking tasks.
blocking_task_pool: BlockingTaskPool,
/// Cache for block fees history
fee_history_cache: FeeHistoryCache,
/// The type that defines how to configure the EVM
evm_config: EvmConfig,
/// Allows forwarding received raw transactions
raw_transaction_forwarder: parking_lot::RwLock<Option<Arc<dyn RawTransactionForwarder>>>,
}
impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig> {
/// Returns a handle to data on disk.
#[inline]
pub const fn provider(&self) -> &Provider {
&self.provider
}
/// Returns a handle to data in memory.
#[inline]
pub const fn cache(&self) -> &EthStateCache {
&self.eth_cache
}
/// Returns a handle to the pending block.
#[inline]
pub const fn pending_block(&self) -> &Mutex<Option<PendingBlock>> {
&self.pending_block
}
/// Returns a handle to the task spawner.
#[inline]
pub const fn task_spawner(&self) -> &dyn TaskSpawner {
&*self.task_spawner
}
/// Returns a handle to the blocking thread pool.
#[inline]
pub const fn blocking_task_pool(&self) -> &BlockingTaskPool {
&self.blocking_task_pool
}
/// Returns a handle to the EVM config.
#[inline]
pub const fn evm_config(&self) -> &EvmConfig {
&self.evm_config
}
/// Returns a handle to the transaction pool.
#[inline]
pub const fn pool(&self) -> &Pool {
&self.pool
}
/// Returns a handle to the transaction forwarder.
#[inline]
pub fn raw_tx_forwarder(&self) -> Option<Arc<dyn RawTransactionForwarder>> {
self.raw_transaction_forwarder.read().clone()
}
/// Returns the gas cap.
#[inline]
pub const fn gas_cap(&self) -> u64 {
self.gas_cap
}
/// Returns a handle to the gas oracle.
#[inline]
pub const fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
&self.gas_oracle
}
/// Returns a handle to the fee history cache.
#[inline]
pub const fn fee_history_cache(&self) -> &FeeHistoryCache {
&self.fee_history_cache
}
/// Returns a handle to the signers.
#[inline]
pub const fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
&self.signers
}
}

View File

@ -1,715 +0,0 @@
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`] trait. Handles RPC requests for
//! the `eth_` namespace.
use alloy_dyn_abi::TypedData;
use jsonrpsee::core::RpcResult as Result;
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
use reth_rpc_types::{
serde_helpers::JsonStorageKey,
state::{EvmOverrides, StateOverride},
AccessListWithGasUsed, AnyTransactionReceipt, BlockOverrides, Bundle,
EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, Index, RichBlock,
StateContext, SyncStatus, Transaction, TransactionRequest, Work,
};
use tracing::trace;
use crate::{
result::internal_rpc_err,
servers::{
EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadReceipt, Trace,
},
EthApiError, EthApiServer, ToRpcResult,
};
#[async_trait::async_trait]
impl<T> EthApiServer for T
where
Self: EthApiSpec
+ EthTransactions
+ EthBlocks
+ EthState
+ EthCall
+ EthFees
+ Trace
+ LoadReceipt,
{
/// Handler for: `eth_protocolVersion`
async fn protocol_version(&self) -> Result<U64> {
trace!(target: "rpc::eth", "Serving eth_protocolVersion");
EthApiSpec::protocol_version(self).await.to_rpc_result()
}
/// Handler for: `eth_syncing`
fn syncing(&self) -> Result<SyncStatus> {
trace!(target: "rpc::eth", "Serving eth_syncing");
EthApiSpec::sync_status(self).to_rpc_result()
}
/// Handler for: `eth_coinbase`
async fn author(&self) -> Result<Address> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_accounts`
fn accounts(&self) -> Result<Vec<Address>> {
trace!(target: "rpc::eth", "Serving eth_accounts");
Ok(EthApiSpec::accounts(self))
}
/// Handler for: `eth_blockNumber`
fn block_number(&self) -> Result<U256> {
trace!(target: "rpc::eth", "Serving eth_blockNumber");
Ok(U256::from(
EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number,
))
}
/// Handler for: `eth_chainId`
async fn chain_id(&self) -> Result<Option<U64>> {
trace!(target: "rpc::eth", "Serving eth_chainId");
Ok(Some(EthApiSpec::chain_id(self)))
}
/// Handler for: `eth_getBlockByHash`
async fn block_by_hash(&self, hash: B256, full: bool) -> Result<Option<RichBlock>> {
trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash");
Ok(EthBlocks::rpc_block(self, hash.into(), full).await?)
}
/// Handler for: `eth_getBlockByNumber`
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> Result<Option<RichBlock>> {
trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber");
Ok(EthBlocks::rpc_block(self, number.into(), full).await?)
}
/// Handler for: `eth_getBlockTransactionCountByHash`
async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash");
Ok(EthBlocks::block_transaction_count(self, hash).await?.map(U256::from))
}
/// Handler for: `eth_getBlockTransactionCountByNumber`
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> Result<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber");
Ok(EthBlocks::block_transaction_count(self, number).await?.map(U256::from))
}
/// Handler for: `eth_getUncleCountByBlockHash`
async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash");
Ok(EthBlocks::ommers(self, hash)?.map(|ommers| U256::from(ommers.len())))
}
/// Handler for: `eth_getUncleCountByBlockNumber`
async fn block_uncles_count_by_number(&self, number: BlockNumberOrTag) -> Result<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber");
Ok(EthBlocks::ommers(self, number)?.map(|ommers| U256::from(ommers.len())))
}
/// Handler for: `eth_getBlockReceipts`
async fn block_receipts(
&self,
block_id: BlockId,
) -> Result<Option<Vec<AnyTransactionReceipt>>> {
trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts");
Ok(EthBlocks::block_receipts(self, block_id).await?)
}
/// Handler for: `eth_getUncleByBlockHashAndIndex`
async fn uncle_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> Result<Option<RichBlock>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex");
Ok(EthBlocks::ommer_by_block_and_index(self, hash, index).await?)
}
/// Handler for: `eth_getUncleByBlockNumberAndIndex`
async fn uncle_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> Result<Option<RichBlock>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex");
Ok(EthBlocks::ommer_by_block_and_index(self, number, index).await?)
}
/// Handler for: `eth_getRawTransactionByHash`
async fn raw_transaction_by_hash(&self, hash: B256) -> Result<Option<Bytes>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash");
Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?)
}
/// Handler for: `eth_getTransactionByHash`
async fn transaction_by_hash(&self, hash: B256) -> Result<Option<Transaction>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash");
Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into))
}
/// Handler for: `eth_getRawTransactionByBlockHashAndIndex`
async fn raw_transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> Result<Option<Bytes>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex");
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash.into(), index).await?)
}
/// Handler for: `eth_getTransactionByBlockHashAndIndex`
async fn transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> Result<Option<reth_rpc_types::Transaction>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex");
Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash.into(), index).await?)
}
/// Handler for: `eth_getRawTransactionByBlockNumberAndIndex`
async fn raw_transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> Result<Option<Bytes>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex");
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, number.into(), index)
.await?)
}
/// Handler for: `eth_getTransactionByBlockNumberAndIndex`
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> Result<Option<reth_rpc_types::Transaction>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex");
Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index).await?)
}
/// Handler for: `eth_getTransactionReceipt`
async fn transaction_receipt(&self, hash: B256) -> Result<Option<AnyTransactionReceipt>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt");
Ok(EthTransactions::transaction_receipt(self, hash).await?)
}
/// Handler for: `eth_getBalance`
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance");
Ok(EthState::balance(self, address, block_number).await?)
}
/// Handler for: `eth_getStorageAt`
async fn storage_at(
&self,
address: Address,
index: JsonStorageKey,
block_number: Option<BlockId>,
) -> Result<B256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt");
let res: B256 = EthState::storage_at(self, address, index, block_number).await?;
Ok(res)
}
/// Handler for: `eth_getTransactionCount`
async fn transaction_count(
&self,
address: Address,
block_number: Option<BlockId>,
) -> Result<U256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount");
Ok(EthState::transaction_count(self, address, block_number).await?)
}
/// Handler for: `eth_getCode`
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode");
Ok(EthState::get_code(self, address, block_number).await?)
}
/// Handler for: `eth_getHeaderByNumber`
async fn header_by_number(&self, block_number: BlockNumberOrTag) -> Result<Option<Header>> {
trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber");
Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?)
}
/// Handler for: `eth_getHeaderByHash`
async fn header_by_hash(&self, hash: B256) -> Result<Option<Header>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash");
Ok(EthBlocks::rpc_block_header(self, hash.into()).await?)
}
/// Handler for: `eth_call`
async fn call(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>,
) -> Result<Bytes> {
trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call");
Ok(EthCall::call(
self,
request,
block_number,
EvmOverrides::new(state_overrides, block_overrides),
)
.await?)
}
/// Handler for: `eth_callMany`
async fn call_many(
&self,
bundle: Bundle,
state_context: Option<StateContext>,
state_override: Option<StateOverride>,
) -> Result<Vec<EthCallResponse>> {
trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany");
Ok(EthCall::call_many(self, bundle, state_context, state_override).await?)
}
/// Handler for: `eth_createAccessList`
async fn create_access_list(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
) -> Result<AccessListWithGasUsed> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList");
let access_list_with_gas_used =
EthCall::create_access_list_at(self, request, block_number).await?;
Ok(access_list_with_gas_used)
}
/// Handler for: `eth_estimateGas`
async fn estimate_gas(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_override: Option<StateOverride>,
) -> Result<U256> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas");
Ok(EthCall::estimate_gas_at(
self,
request,
block_number.unwrap_or_default(),
state_override,
)
.await?)
}
/// Handler for: `eth_gasPrice`
async fn gas_price(&self) -> Result<U256> {
trace!(target: "rpc::eth", "Serving eth_gasPrice");
return Ok(EthFees::gas_price(self).await?)
}
/// Handler for: `eth_maxPriorityFeePerGas`
async fn max_priority_fee_per_gas(&self) -> Result<U256> {
trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas");
return Ok(EthFees::suggested_priority_fee(self).await?)
}
/// Handler for: `eth_blobBaseFee`
async fn blob_base_fee(&self) -> Result<U256> {
trace!(target: "rpc::eth", "Serving eth_blobBaseFee");
return Ok(EthFees::blob_base_fee(self).await?)
}
// FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further
// caching of it in the LRU cache.
// When new RPC call is executed, the cache gets locked, we check it for the historical fees
// according to the requested block range, and fill any cache misses (in both RPC response
// and cache itself) with the actual data queried from the database.
// To minimize the number of database seeks required to query the missing data, we calculate the
// first non-cached block number and last non-cached block number. After that, we query this
// range of consecutive blocks from the database.
/// Handler for: `eth_feeHistory`
async fn fee_history(
&self,
block_count: U64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> Result<FeeHistory> {
trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory");
return Ok(
EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?
)
}
/// Handler for: `eth_mining`
async fn is_mining(&self) -> Result<bool> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_hashrate`
async fn hashrate(&self) -> Result<U256> {
Ok(U256::ZERO)
}
/// Handler for: `eth_getWork`
async fn get_work(&self) -> Result<Work> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_submitHashrate`
async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> Result<bool> {
Ok(false)
}
/// Handler for: `eth_submitWork`
async fn submit_work(&self, _nonce: B64, _pow_hash: B256, _mix_digest: B256) -> Result<bool> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_sendTransaction`
async fn send_transaction(&self, request: TransactionRequest) -> Result<B256> {
trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction");
Ok(EthTransactions::send_transaction(self, request).await?)
}
/// Handler for: `eth_sendRawTransaction`
async fn send_raw_transaction(&self, tx: Bytes) -> Result<B256> {
trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction");
Ok(EthTransactions::send_raw_transaction(self, tx).await?)
}
/// Handler for: `eth_sign`
async fn sign(&self, address: Address, message: Bytes) -> Result<Bytes> {
trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign");
Ok(EthTransactions::sign(self, address, message).await?)
}
/// Handler for: `eth_signTransaction`
async fn sign_transaction(&self, _transaction: TransactionRequest) -> Result<Bytes> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_signTypedData`
async fn sign_typed_data(&self, address: Address, data: TypedData) -> Result<Bytes> {
trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData");
Ok(EthTransactions::sign_typed_data(self, &data, address)?)
}
/// Handler for: `eth_getProof`
async fn get_proof(
&self,
address: Address,
keys: Vec<JsonStorageKey>,
block_number: Option<BlockId>,
) -> Result<EIP1186AccountProofResponse> {
trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof");
let res = EthState::get_proof(self, address, keys, block_number)?.await;
Ok(res.map_err(|e| match e {
EthApiError::InvalidBlockRange => {
internal_rpc_err("eth_getProof is unimplemented for historical blocks")
}
_ => e.into(),
})?)
}
}
#[cfg(test)]
mod tests {
use jsonrpsee::types::error::INVALID_PARAMS_CODE;
use reth_chainspec::BaseFeeParams;
use reth_evm_ethereum::EthEvmConfig;
use reth_network_api::noop::NoopNetwork;
use reth_primitives::{
constants::ETHEREUM_BLOCK_GAS_LIMIT, Block, BlockNumberOrTag, Header, TransactionSigned,
B256, U64,
};
use reth_provider::{
test_utils::{MockEthProvider, NoopProvider},
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory,
};
use reth_rpc_types::FeeHistory;
use reth_tasks::pool::BlockingTaskPool;
use reth_testing_utils::{generators, generators::Rng};
use reth_transaction_pool::test_utils::{testing_pool, TestPool};
use crate::{
EthApi, EthApiServer, EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
};
fn build_test_eth_api<
P: BlockReaderIdExt
+ BlockReader
+ ChainSpecProvider
+ EvmEnvProvider
+ StateProviderFactory
+ Unpin
+ Clone
+ 'static,
>(
provider: P,
) -> EthApi<P, TestPool, NoopNetwork, EthEvmConfig> {
let evm_config = EthEvmConfig::default();
let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config);
let fee_history_cache =
FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default());
EthApi::new(
provider.clone(),
testing_pool(),
NoopNetwork::default(),
cache.clone(),
GasPriceOracle::new(provider, Default::default(), cache),
ETHEREUM_BLOCK_GAS_LIMIT,
BlockingTaskPool::build().expect("failed to build tracing pool"),
fee_history_cache,
evm_config,
None,
)
}
// Function to prepare the EthApi with mock data
fn prepare_eth_api(
newest_block: u64,
mut oldest_block: Option<B256>,
block_count: u64,
mock_provider: MockEthProvider,
) -> (EthApi<MockEthProvider, TestPool, NoopNetwork, EthEvmConfig>, Vec<u128>, Vec<f64>) {
let mut rng = generators::rng();
// Build mock data
let mut gas_used_ratios = Vec::new();
let mut base_fees_per_gas = Vec::new();
let mut last_header = None;
let mut parent_hash = B256::default();
for i in (0..block_count).rev() {
let hash = rng.gen();
let gas_limit: u64 = rng.gen();
let gas_used: u64 = rng.gen();
// Note: Generates a u32 to avoid overflows later
let base_fee_per_gas: Option<u64> = rng.gen::<bool>().then(|| rng.gen::<u32>() as u64);
let header = Header {
number: newest_block - i,
gas_limit,
gas_used,
base_fee_per_gas,
parent_hash,
..Default::default()
};
last_header = Some(header.clone());
parent_hash = hash;
let mut transactions = vec![];
for _ in 0..100 {
let random_fee: u128 = rng.gen();
if let Some(base_fee_per_gas) = header.base_fee_per_gas {
let transaction = TransactionSigned {
transaction: reth_primitives::Transaction::Eip1559(
reth_primitives::TxEip1559 {
max_priority_fee_per_gas: random_fee,
max_fee_per_gas: random_fee + base_fee_per_gas as u128,
..Default::default()
},
),
..Default::default()
};
transactions.push(transaction);
} else {
let transaction = TransactionSigned {
transaction: reth_primitives::Transaction::Legacy(Default::default()),
..Default::default()
};
transactions.push(transaction);
}
}
mock_provider.add_block(
hash,
Block { header: header.clone(), body: transactions, ..Default::default() },
);
mock_provider.add_header(hash, header);
oldest_block.get_or_insert(hash);
gas_used_ratios.push(gas_used as f64 / gas_limit as f64);
base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default());
}
// Add final base fee (for the next block outside of the request)
let last_header = last_header.unwrap();
base_fees_per_gas.push(BaseFeeParams::ethereum().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,
));
let eth_api = build_test_eth_api(mock_provider);
(eth_api, base_fees_per_gas, gas_used_ratios)
}
/// Invalid block range
#[tokio::test]
async fn test_fee_history_empty() {
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&build_test_eth_api(NoopProvider::default()),
U64::from(1),
BlockNumberOrTag::Latest,
None,
)
.await;
assert!(response.is_err());
let error_object = response.unwrap_err();
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
}
#[tokio::test]
/// Invalid block range (request is before genesis)
async fn test_fee_history_invalid_block_range_before_genesis() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, _, _) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&eth_api,
U64::from(newest_block + 1),
newest_block.into(),
Some(vec![10.0]),
)
.await;
assert!(response.is_err());
let error_object = response.unwrap_err();
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
}
#[tokio::test]
/// Invalid block range (request is in the future)
async fn test_fee_history_invalid_block_range_in_future() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, _, _) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&eth_api,
U64::from(1),
(newest_block + 1000).into(),
Some(vec![10.0]),
)
.await;
assert!(response.is_err());
let error_object = response.unwrap_err();
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
}
#[tokio::test]
/// Requesting no block should result in a default response
async fn test_fee_history_no_block_requested() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, _, _) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&eth_api,
U64::from(0),
newest_block.into(),
None,
)
.await
.unwrap();
assert_eq!(
response,
FeeHistory::default(),
"none: requesting no block should yield a default response"
);
}
#[tokio::test]
/// Requesting a single block should return 1 block (+ base fee for the next block over)
async fn test_fee_history_single_block() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, base_fees_per_gas, gas_used_ratios) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let fee_history =
eth_api.fee_history(U64::from(1), newest_block.into(), None).await.unwrap();
assert_eq!(
fee_history.base_fee_per_gas,
&base_fees_per_gas[base_fees_per_gas.len() - 2..],
"one: base fee per gas is incorrect"
);
assert_eq!(
fee_history.base_fee_per_gas.len(),
2,
"one: should return base fee of the next block as well"
);
assert_eq!(
&fee_history.gas_used_ratio,
&gas_used_ratios[gas_used_ratios.len() - 1..],
"one: gas used ratio is incorrect"
);
assert_eq!(fee_history.oldest_block, newest_block, "one: oldest block is incorrect");
assert!(
fee_history.reward.is_none(),
"one: no percentiles were requested, so there should be no rewards result"
);
}
/// Requesting all blocks should be ok
#[tokio::test]
async fn test_fee_history_all_blocks() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, base_fees_per_gas, gas_used_ratios) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let fee_history =
eth_api.fee_history(U64::from(block_count), newest_block.into(), None).await.unwrap();
assert_eq!(
&fee_history.base_fee_per_gas, &base_fees_per_gas,
"all: base fee per gas is incorrect"
);
assert_eq!(
fee_history.base_fee_per_gas.len() as u64,
block_count + 1,
"all: should return base fee of the next block as well"
);
assert_eq!(
&fee_history.gas_used_ratio, &gas_used_ratios,
"all: gas used ratio is incorrect"
);
assert_eq!(
fee_history.oldest_block,
newest_block - block_count + 1,
"all: oldest block is incorrect"
);
assert!(
fee_history.reward.is_none(),
"all: no percentiles were requested, so there should be no rewards result"
);
}
}

View File

@ -0,0 +1,727 @@
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`] trait. Handles RPC requests for
//! the `eth_` namespace.
use alloy_dyn_abi::TypedData;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
use reth_rpc_eth_types::EthApiError;
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use reth_rpc_types::{
serde_helpers::JsonStorageKey,
state::{EvmOverrides, StateOverride},
AccessListWithGasUsed, AnyTransactionReceipt, BlockOverrides, Bundle,
EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, Index, RichBlock,
StateContext, SyncStatus, Transaction, TransactionRequest, Work,
};
use tracing::trace;
use crate::helpers::{
EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadReceipt, Trace,
};
/// Eth rpc interface: <https://ethereum.github.io/execution-apis/api-documentation/>
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
pub trait EthApi {
/// Returns the protocol version encoded as a string.
#[method(name = "protocolVersion")]
async fn protocol_version(&self) -> RpcResult<U64>;
/// Returns an object with data about the sync status or false.
#[method(name = "syncing")]
fn syncing(&self) -> RpcResult<SyncStatus>;
/// Returns the client coinbase address.
#[method(name = "coinbase")]
async fn author(&self) -> RpcResult<Address>;
/// Returns a list of addresses owned by client.
#[method(name = "accounts")]
fn accounts(&self) -> RpcResult<Vec<Address>>;
/// Returns the number of most recent block.
#[method(name = "blockNumber")]
fn block_number(&self) -> RpcResult<U256>;
/// Returns the chain ID of the current network.
#[method(name = "chainId")]
async fn chain_id(&self) -> RpcResult<Option<U64>>;
/// Returns information about a block by hash.
#[method(name = "getBlockByHash")]
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<RichBlock>>;
/// Returns information about a block by number.
#[method(name = "getBlockByNumber")]
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> RpcResult<Option<RichBlock>>;
/// Returns the number of transactions in a block from a block matching the given block hash.
#[method(name = "getBlockTransactionCountByHash")]
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
/// Returns the number of transactions in a block matching the given block number.
#[method(name = "getBlockTransactionCountByNumber")]
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>>;
/// Returns the number of uncles in a block from a block matching the given block hash.
#[method(name = "getUncleCountByBlockHash")]
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
/// Returns the number of uncles in a block with given block number.
#[method(name = "getUncleCountByBlockNumber")]
async fn block_uncles_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>>;
/// Returns all transaction receipts for a given block.
#[method(name = "getBlockReceipts")]
async fn block_receipts(
&self,
block_id: BlockId,
) -> RpcResult<Option<Vec<AnyTransactionReceipt>>>;
/// Returns an uncle block of the given block and index.
#[method(name = "getUncleByBlockHashAndIndex")]
async fn uncle_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<RichBlock>>;
/// Returns an uncle block of the given block and index.
#[method(name = "getUncleByBlockNumberAndIndex")]
async fn uncle_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<RichBlock>>;
/// Returns the EIP-2718 encoded transaction if it exists.
///
/// If this is a EIP-4844 transaction that is in the pool it will include the sidecar.
#[method(name = "getRawTransactionByHash")]
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>>;
/// Returns the information about a transaction requested by transaction hash.
#[method(name = "getTransactionByHash")]
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Transaction>>;
/// Returns information about a raw transaction by block hash and transaction index position.
#[method(name = "getRawTransactionByBlockHashAndIndex")]
async fn raw_transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Bytes>>;
/// Returns information about a transaction by block hash and transaction index position.
#[method(name = "getTransactionByBlockHashAndIndex")]
async fn transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Transaction>>;
/// Returns information about a raw transaction by block number and transaction index
/// position.
#[method(name = "getRawTransactionByBlockNumberAndIndex")]
async fn raw_transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Bytes>>;
/// Returns information about a transaction by block number and transaction index position.
#[method(name = "getTransactionByBlockNumberAndIndex")]
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Transaction>>;
/// Returns the receipt of a transaction by transaction hash.
#[method(name = "getTransactionReceipt")]
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<AnyTransactionReceipt>>;
/// Returns the balance of the account of given address.
#[method(name = "getBalance")]
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256>;
/// Returns the value from a storage position at a given address
#[method(name = "getStorageAt")]
async fn storage_at(
&self,
address: Address,
index: JsonStorageKey,
block_number: Option<BlockId>,
) -> RpcResult<B256>;
/// Returns the number of transactions sent from an address at given block number.
#[method(name = "getTransactionCount")]
async fn transaction_count(
&self,
address: Address,
block_number: Option<BlockId>,
) -> RpcResult<U256>;
/// Returns code at a given address at given block number.
#[method(name = "getCode")]
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes>;
/// Returns the block's header at given number.
#[method(name = "getHeaderByNumber")]
async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult<Option<Header>>;
/// Returns the block's header at given hash.
#[method(name = "getHeaderByHash")]
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<Header>>;
/// Executes a new message call immediately without creating a transaction on the block chain.
#[method(name = "call")]
async fn call(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes>;
/// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the
/// optionality of state overrides
#[method(name = "callMany")]
async fn call_many(
&self,
bundle: Bundle,
state_context: Option<StateContext>,
state_override: Option<StateOverride>,
) -> RpcResult<Vec<EthCallResponse>>;
/// Generates an access list for a transaction.
///
/// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction.
///
/// An access list contains all storage slots and addresses touched by the transaction, except
/// for the sender account and the chain's precompiles.
///
/// It returns list of addresses and storage keys used by the transaction, plus the gas
/// consumed when the access list is added. That is, it gives you the list of addresses and
/// storage keys that will be used by that transaction, plus the gas consumed if the access
/// list is included. Like eth_estimateGas, this is an estimation; the list could change
/// when the transaction is actually mined. Adding an accessList to your transaction does
/// not necessary result in lower gas usage compared to a transaction without an access
/// list.
#[method(name = "createAccessList")]
async fn create_access_list(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
) -> RpcResult<AccessListWithGasUsed>;
/// Generates and returns an estimate of how much gas is necessary to allow the transaction to
/// complete.
#[method(name = "estimateGas")]
async fn estimate_gas(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_override: Option<StateOverride>,
) -> RpcResult<U256>;
/// Returns the current price per gas in wei.
#[method(name = "gasPrice")]
async fn gas_price(&self) -> RpcResult<U256>;
/// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions.
#[method(name = "maxPriorityFeePerGas")]
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256>;
/// Introduced in EIP-4844, returns the current blob base fee in wei.
#[method(name = "blobBaseFee")]
async fn blob_base_fee(&self) -> RpcResult<U256>;
/// Returns the Transaction fee history
///
/// Introduced in EIP-1559 for getting information on the appropriate priority fee to use.
///
/// Returns transaction base fee per gas and effective priority fee per gas for the
/// requested/supported block range. The returned Fee history for the returned block range
/// can be a subsection of the requested range if not all blocks are available.
#[method(name = "feeHistory")]
async fn fee_history(
&self,
block_count: U64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> RpcResult<FeeHistory>;
/// Returns whether the client is actively mining new blocks.
#[method(name = "mining")]
async fn is_mining(&self) -> RpcResult<bool>;
/// Returns the number of hashes per second that the node is mining with.
#[method(name = "hashrate")]
async fn hashrate(&self) -> RpcResult<U256>;
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met
/// (“target”)
#[method(name = "getWork")]
async fn get_work(&self) -> RpcResult<Work>;
/// Used for submitting mining hashrate.
///
/// Can be used for remote miners to submit their hash rate.
/// It accepts the miner hash rate and an identifier which must be unique between nodes.
/// Returns `true` if the block was successfully submitted, `false` otherwise.
#[method(name = "submitHashrate")]
async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult<bool>;
/// Used for submitting a proof-of-work solution.
#[method(name = "submitWork")]
async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult<bool>;
/// Sends transaction; will block waiting for signer to return the
/// transaction hash.
#[method(name = "sendTransaction")]
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256>;
/// Sends signed transaction, returning its hash.
#[method(name = "sendRawTransaction")]
async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
/// Returns an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n"
/// + len(message) + message))).
#[method(name = "sign")]
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes>;
/// Signs a transaction that can be submitted to the network at a later time using with
/// `sendRawTransaction.`
#[method(name = "signTransaction")]
async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult<Bytes>;
/// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
#[method(name = "signTypedData")]
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes>;
/// Returns the account and storage values of the specified account including the Merkle-proof.
/// This call can be used to verify that the data you are pulling from is not tampered with.
#[method(name = "getProof")]
async fn get_proof(
&self,
address: Address,
keys: Vec<JsonStorageKey>,
block_number: Option<BlockId>,
) -> RpcResult<EIP1186AccountProofResponse>;
}
#[async_trait::async_trait]
impl<T> EthApiServer for T
where
Self: EthApiSpec
+ EthTransactions
+ EthBlocks
+ EthState
+ EthCall
+ EthFees
+ Trace
+ LoadReceipt,
{
/// Handler for: `eth_protocolVersion`
async fn protocol_version(&self) -> RpcResult<U64> {
trace!(target: "rpc::eth", "Serving eth_protocolVersion");
EthApiSpec::protocol_version(self).await.to_rpc_result()
}
/// Handler for: `eth_syncing`
fn syncing(&self) -> RpcResult<SyncStatus> {
trace!(target: "rpc::eth", "Serving eth_syncing");
EthApiSpec::sync_status(self).to_rpc_result()
}
/// Handler for: `eth_coinbase`
async fn author(&self) -> RpcResult<Address> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_accounts`
fn accounts(&self) -> RpcResult<Vec<Address>> {
trace!(target: "rpc::eth", "Serving eth_accounts");
Ok(EthApiSpec::accounts(self))
}
/// Handler for: `eth_blockNumber`
fn block_number(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_blockNumber");
Ok(U256::from(
EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number,
))
}
/// Handler for: `eth_chainId`
async fn chain_id(&self) -> RpcResult<Option<U64>> {
trace!(target: "rpc::eth", "Serving eth_chainId");
Ok(Some(EthApiSpec::chain_id(self)))
}
/// Handler for: `eth_getBlockByHash`
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<RichBlock>> {
trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash");
Ok(EthBlocks::rpc_block(self, hash.into(), full).await?)
}
/// Handler for: `eth_getBlockByNumber`
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> RpcResult<Option<RichBlock>> {
trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber");
Ok(EthBlocks::rpc_block(self, number.into(), full).await?)
}
/// Handler for: `eth_getBlockTransactionCountByHash`
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash");
Ok(EthBlocks::block_transaction_count(self, hash.into()).await?.map(U256::from))
}
/// Handler for: `eth_getBlockTransactionCountByNumber`
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber");
Ok(EthBlocks::block_transaction_count(self, number.into()).await?.map(U256::from))
}
/// Handler for: `eth_getUncleCountByBlockHash`
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash");
Ok(EthBlocks::ommers(self, hash.into())?.map(|ommers| U256::from(ommers.len())))
}
/// Handler for: `eth_getUncleCountByBlockNumber`
async fn block_uncles_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber");
Ok(EthBlocks::ommers(self, number.into())?.map(|ommers| U256::from(ommers.len())))
}
/// Handler for: `eth_getBlockReceipts`
async fn block_receipts(
&self,
block_id: BlockId,
) -> RpcResult<Option<Vec<AnyTransactionReceipt>>> {
trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts");
Ok(EthBlocks::block_receipts(self, block_id).await?)
}
/// Handler for: `eth_getUncleByBlockHashAndIndex`
async fn uncle_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<RichBlock>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex");
Ok(EthBlocks::ommer_by_block_and_index(self, hash.into(), index).await?)
}
/// Handler for: `eth_getUncleByBlockNumberAndIndex`
async fn uncle_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<RichBlock>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex");
Ok(EthBlocks::ommer_by_block_and_index(self, number.into(), index).await?)
}
/// Handler for: `eth_getRawTransactionByHash`
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash");
Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?)
}
/// Handler for: `eth_getTransactionByHash`
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Transaction>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash");
Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into))
}
/// Handler for: `eth_getRawTransactionByBlockHashAndIndex`
async fn raw_transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Bytes>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex");
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash.into(), index).await?)
}
/// Handler for: `eth_getTransactionByBlockHashAndIndex`
async fn transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<reth_rpc_types::Transaction>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex");
Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash.into(), index).await?)
}
/// Handler for: `eth_getRawTransactionByBlockNumberAndIndex`
async fn raw_transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Bytes>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex");
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, number.into(), index)
.await?)
}
/// Handler for: `eth_getTransactionByBlockNumberAndIndex`
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<reth_rpc_types::Transaction>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex");
Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index).await?)
}
/// Handler for: `eth_getTransactionReceipt`
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<AnyTransactionReceipt>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt");
Ok(EthTransactions::transaction_receipt(self, hash).await?)
}
/// Handler for: `eth_getBalance`
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance");
Ok(EthState::balance(self, address, block_number).await?)
}
/// Handler for: `eth_getStorageAt`
async fn storage_at(
&self,
address: Address,
index: JsonStorageKey,
block_number: Option<BlockId>,
) -> RpcResult<B256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt");
let res: B256 = EthState::storage_at(self, address, index, block_number).await?;
Ok(res)
}
/// Handler for: `eth_getTransactionCount`
async fn transaction_count(
&self,
address: Address,
block_number: Option<BlockId>,
) -> RpcResult<U256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount");
Ok(EthState::transaction_count(self, address, block_number).await?)
}
/// Handler for: `eth_getCode`
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode");
Ok(EthState::get_code(self, address, block_number).await?)
}
/// Handler for: `eth_getHeaderByNumber`
async fn header_by_number(&self, block_number: BlockNumberOrTag) -> RpcResult<Option<Header>> {
trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber");
Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?)
}
/// Handler for: `eth_getHeaderByHash`
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<Header>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash");
Ok(EthBlocks::rpc_block_header(self, hash.into()).await?)
}
/// Handler for: `eth_call`
async fn call(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call");
Ok(EthCall::call(
self,
request,
block_number,
EvmOverrides::new(state_overrides, block_overrides),
)
.await?)
}
/// Handler for: `eth_callMany`
async fn call_many(
&self,
bundle: Bundle,
state_context: Option<StateContext>,
state_override: Option<StateOverride>,
) -> RpcResult<Vec<EthCallResponse>> {
trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany");
Ok(EthCall::call_many(self, bundle, state_context, state_override).await?)
}
/// Handler for: `eth_createAccessList`
async fn create_access_list(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
) -> RpcResult<AccessListWithGasUsed> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList");
let access_list_with_gas_used =
EthCall::create_access_list_at(self, request, block_number).await?;
Ok(access_list_with_gas_used)
}
/// Handler for: `eth_estimateGas`
async fn estimate_gas(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_override: Option<StateOverride>,
) -> RpcResult<U256> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas");
Ok(EthCall::estimate_gas_at(
self,
request,
block_number.unwrap_or_default(),
state_override,
)
.await?)
}
/// Handler for: `eth_gasPrice`
async fn gas_price(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_gasPrice");
return Ok(EthFees::gas_price(self).await?)
}
/// Handler for: `eth_maxPriorityFeePerGas`
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas");
return Ok(EthFees::suggested_priority_fee(self).await?)
}
/// Handler for: `eth_blobBaseFee`
async fn blob_base_fee(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_blobBaseFee");
return Ok(EthFees::blob_base_fee(self).await?)
}
// FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further
// caching of it in the LRU cache.
// When new RPC call is executed, the cache gets locked, we check it for the historical fees
// according to the requested block range, and fill any cache misses (in both RPC response
// and cache itself) with the actual data queried from the database.
// To minimize the number of database seeks required to query the missing data, we calculate the
// first non-cached block number and last non-cached block number. After that, we query this
// range of consecutive blocks from the database.
/// Handler for: `eth_feeHistory`
async fn fee_history(
&self,
block_count: U64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> RpcResult<FeeHistory> {
trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory");
return Ok(
EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?
)
}
/// Handler for: `eth_mining`
async fn is_mining(&self) -> RpcResult<bool> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_hashrate`
async fn hashrate(&self) -> RpcResult<U256> {
Ok(U256::ZERO)
}
/// Handler for: `eth_getWork`
async fn get_work(&self) -> RpcResult<Work> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_submitHashrate`
async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> RpcResult<bool> {
Ok(false)
}
/// Handler for: `eth_submitWork`
async fn submit_work(
&self,
_nonce: B64,
_pow_hash: B256,
_mix_digest: B256,
) -> RpcResult<bool> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_sendTransaction`
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256> {
trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction");
Ok(EthTransactions::send_transaction(self, request).await?)
}
/// Handler for: `eth_sendRawTransaction`
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256> {
trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction");
Ok(EthTransactions::send_raw_transaction(self, tx).await?)
}
/// Handler for: `eth_sign`
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign");
Ok(EthTransactions::sign(self, address, message).await?)
}
/// Handler for: `eth_signTransaction`
async fn sign_transaction(&self, _transaction: TransactionRequest) -> RpcResult<Bytes> {
Err(internal_rpc_err("unimplemented"))
}
/// Handler for: `eth_signTypedData`
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData");
Ok(EthTransactions::sign_typed_data(self, &data, address)?)
}
/// Handler for: `eth_getProof`
async fn get_proof(
&self,
address: Address,
keys: Vec<JsonStorageKey>,
block_number: Option<BlockId>,
) -> RpcResult<EIP1186AccountProofResponse> {
trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof");
let res = EthState::get_proof(self, address, keys, block_number)?.await;
Ok(res.map_err(|e| match e {
EthApiError::InvalidBlockRange => {
internal_rpc_err("eth_getProof is unimplemented for historical blocks")
}
_ => e.into(),
})?)
}
}

View File

@ -5,13 +5,11 @@ use std::sync::Arc;
use futures::Future;
use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta};
use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider};
use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder};
use reth_rpc_types::{AnyTransactionReceipt, Header, Index, RichBlock};
use reth_rpc_types_compat::block::{from_block, uncle_block_from_header};
use crate::{
servers::{LoadPendingBlock, LoadReceipt, SpawnBlocking},
EthApiError, EthResult, EthStateCache, ReceiptBuilder,
};
use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking};
/// Block related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
/// `eth_` namespace.
@ -64,10 +62,8 @@ pub trait EthBlocks: LoadBlock {
/// Returns `None` if the block does not exist
fn block_transaction_count(
&self,
block_id: impl Into<BlockId>,
block_id: BlockId,
) -> impl Future<Output = EthResult<Option<usize>>> + Send {
let block_id = block_id.into();
async move {
if block_id.is_pending() {
// Pending block can be fetched directly without need for caching
@ -155,11 +151,7 @@ pub trait EthBlocks: LoadBlock {
/// Returns uncle headers of given block.
///
/// Returns an empty vec if there are none.
fn ommers(
&self,
block_id: impl Into<BlockId>,
) -> EthResult<Option<Vec<reth_primitives::Header>>> {
let block_id = block_id.into();
fn ommers(&self, block_id: BlockId) -> EthResult<Option<Vec<reth_primitives::Header>>> {
Ok(LoadBlock::provider(self).ommers_by_id(block_id)?)
}
@ -168,11 +160,9 @@ pub trait EthBlocks: LoadBlock {
/// Returns `None` if index out of range.
fn ommer_by_block_and_index(
&self,
block_id: impl Into<BlockId>,
block_id: BlockId,
index: Index,
) -> impl Future<Output = EthResult<Option<RichBlock>>> + Send {
let block_id = block_id.into();
async move {
let uncles = if block_id.is_pending() {
// Pending block can be fetched directly without need for caching

View File

@ -0,0 +1,54 @@
//! Spawns a blocking task. CPU heavy tasks are executed with the `rayon` library. IO heavy tasks
//! are executed on the `tokio` runtime.
use futures::Future;
use reth_rpc_eth_types::{EthApiError, EthResult};
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
use tokio::sync::oneshot;
/// Executes code on a blocking thread.
pub trait SpawnBlocking: Clone + Send + Sync + 'static {
/// Returns a handle for spawning IO heavy blocking tasks.
///
/// Runtime access in default trait method implementations.
fn io_task_spawner(&self) -> impl TaskSpawner;
/// Returns a handle for spawning CPU heavy blocking tasks.
///
/// Thread pool access in default trait method implementations.
fn tracing_task_pool(&self) -> &BlockingTaskPool;
/// Executes the future on a new blocking task.
///
/// Note: This is expected for futures that are dominated by blocking IO operations, for tracing
/// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing).
fn spawn_blocking_io<F, R>(&self, f: F) -> impl Future<Output = EthResult<R>> + Send
where
F: FnOnce(Self) -> EthResult<R> + Send + 'static,
R: Send + 'static,
{
let (tx, rx) = oneshot::channel();
let this = self.clone();
self.io_task_spawner().spawn_blocking(Box::pin(async move {
let res = async move { f(this) }.await;
let _ = tx.send(res);
}));
async move { rx.await.map_err(|_| EthApiError::InternalEthError)? }
}
/// Executes a blocking task on the tracing pool.
///
/// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon`
/// under the hood, for blocking IO futures use [`spawn_blocking`](Self::spawn_blocking_io). See
/// <https://ryhl.io/blog/async-what-is-blocking/>.
fn spawn_tracing<F, R>(&self, f: F) -> impl Future<Output = EthResult<R>> + Send
where
F: FnOnce(Self) -> EthResult<R> + Send + 'static,
R: Send + 'static,
{
let this = self.clone();
let fut = self.tracing_task_pool().spawn(move || f(this));
async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? }
}
}

View File

@ -13,6 +13,16 @@ use reth_primitives::{
};
use reth_provider::StateProvider;
use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef};
use reth_rpc_eth_types::{
cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
error::ensure_success,
revm_utils::{
apply_state_overrides, build_call_evm_env, caller_gas_allowance,
cap_tx_gas_limit_with_caller_allowance, get_precompiles, prepare_call_env,
},
EthApiError, EthResult, RevertError, RpcInvalidTransactionError, StateCacheDb,
};
use reth_rpc_server_types::constants::gas_oracle::{ESTIMATE_GAS_ERROR_RATIO, MIN_TRANSACTION_GAS};
use reth_rpc_types::{
state::{EvmOverrides, StateOverride},
AccessListWithGasUsed, BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo,
@ -22,17 +32,7 @@ use revm::{Database, DatabaseCommit};
use revm_inspectors::access_list::AccessListInspector;
use tracing::trace;
use crate::{
cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
error::ensure_success,
revm_utils::{
apply_state_overrides, build_call_evm_env, caller_gas_allowance,
cap_tx_gas_limit_with_caller_allowance, get_precompiles, prepare_call_env,
},
servers::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace},
EthApiError, EthResult, RevertError, RpcInvalidTransactionError, StateCacheDb,
ESTIMATE_GAS_ERROR_RATIO, MIN_TRANSACTION_GAS,
};
use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace};
/// Execution related functions for the [`EthApiServer`](crate::EthApiServer) trait in
/// the `eth_` namespace.

View File

@ -3,14 +3,14 @@
use futures::Future;
use reth_primitives::U256;
use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider};
use reth_rpc_eth_types::{
fee_history::calculate_reward_percentiles_for_block, EthApiError, EthResult, EthStateCache,
FeeHistoryCache, FeeHistoryEntry, GasPriceOracle, RpcInvalidTransactionError,
};
use reth_rpc_types::{BlockNumberOrTag, FeeHistory};
use tracing::debug;
use crate::{
fee_history::calculate_reward_percentiles_for_block, servers::LoadBlock, EthApiError,
EthResult, EthStateCache, FeeHistoryCache, FeeHistoryEntry, GasPriceOracle,
RpcInvalidTransactionError,
};
use super::LoadBlock;
/// Fee related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
/// `eth_` namespace.

View File

@ -6,16 +6,13 @@
//! trait.
//!
//! Traits with `Eth` prefix, compose specific data needed to serve RPC requests in the `eth`
//! namespace. They use `Load` traits as building blocks.
//! [`EthTransactions`](crate::servers::EthTransactions) also writes data (submits transactions).
//! Based on the `eth_` request method semantics, request methods are divided into:
//! [`EthTransactions`](crate::servers::EthTransactions), [`EthBlocks`](crate::servers::EthBlocks),
//! [`EthFees`](crate::servers::EthFees), [`EthState`](crate::servers::EthState) and
//! [`EthCall`](crate::servers::EthCall). Default implementation of the `Eth` traits, is done w.r.t.
//! L1.
//! namespace. They use `Load` traits as building blocks. [`EthTransactions`] also writes data
//! (submits transactions). Based on the `eth_` request method semantics, request methods are
//! divided into: [`EthTransactions`], [`EthBlocks`], [`EthFees`], [`EthState`] and [`EthCall`].
//! Default implementation of the `Eth` traits, is done w.r.t. L1.
//!
//! [`EthApiServer`](crate::EthApiServer), is implemented for any type that implements
//! all the `Eth` traits, e.g. [`EthApi`](crate::EthApi).
//! all the `Eth` traits, e.g. `reth_rpc::EthApi`.
pub mod block;
pub mod blocking_task;
@ -29,12 +26,17 @@ pub mod state;
pub mod trace;
pub mod transaction;
use block::LoadBlock;
use blocking_task::SpawnBlocking;
use call::Call;
use pending_block::LoadPendingBlock;
use trace::Trace;
use transaction::LoadTransaction;
pub use block::{EthBlocks, LoadBlock};
pub use blocking_task::SpawnBlocking;
pub use call::{Call, EthCall};
pub use fee::{EthFees, LoadFee};
pub use pending_block::LoadPendingBlock;
pub use receipt::LoadReceipt;
pub use signer::EthSigner;
pub use spec::EthApiSpec;
pub use state::{EthState, LoadState};
pub use trace::Trace;
pub use transaction::{EthTransactions, LoadTransaction};
/// Extension trait that bundles traits needed for tracing transactions.
pub trait TraceExt:

View File

@ -24,16 +24,16 @@ use reth_provider::{
use reth_revm::{
database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments,
};
use reth_rpc_eth_types::{
pending_block::{pre_block_beacon_root_contract_call, pre_block_blockhashes_update},
EthApiError, EthResult, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin,
};
use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool};
use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State};
use tokio::sync::Mutex;
use tracing::debug;
use crate::{
pending_block::{pre_block_beacon_root_contract_call, pre_block_blockhashes_update},
servers::SpawnBlocking,
EthApiError, EthResult, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin,
};
use super::SpawnBlocking;
/// Loads a pending block from database.
///

View File

@ -3,10 +3,9 @@
use futures::Future;
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned};
use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder};
use reth_rpc_types::AnyTransactionReceipt;
use crate::{EthApiError, EthResult, EthStateCache, ReceiptBuilder};
/// Assembles transaction receipt data w.r.t to network.
///
/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods.

View File

@ -5,10 +5,9 @@ use std::result;
use alloy_dyn_abi::TypedData;
use dyn_clone::DynClone;
use reth_primitives::{Address, Signature, TransactionSigned};
use reth_rpc_eth_types::SignError;
use reth_rpc_types::TypedTransactionRequest;
use crate::SignError;
/// Result returned by [`EthSigner`] methods.
pub type Result<T> = result::Result<T, SignError>;

View File

@ -7,15 +7,15 @@ use reth_primitives::{
B256, U256,
};
use reth_provider::{BlockIdReader, StateProvider, StateProviderBox, StateProviderFactory};
use reth_rpc_eth_types::{
EthApiError, EthResult, EthStateCache, PendingBlockEnv, RpcInvalidTransactionError,
};
use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse};
use reth_rpc_types_compat::proof::from_primitive_account_proof;
use reth_transaction_pool::{PoolTransaction, TransactionPool};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId};
use crate::{
servers::{EthApiSpec, LoadPendingBlock, SpawnBlocking},
EthApiError, EthResult, EthStateCache, PendingBlockEnv, RpcInvalidTransactionError,
};
use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking};
/// Helper methods for `eth_` methods relating to state (accounts).
pub trait EthState: LoadState + SpawnBlocking {

View File

@ -4,16 +4,16 @@ use futures::Future;
use reth_evm::ConfigureEvm;
use reth_primitives::{revm::env::tx_env_with_recovered, B256};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_eth_types::{
cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
EthApiError, EthResult,
};
use reth_rpc_types::{BlockId, TransactionInfo};
use revm::{db::CacheDB, Database, DatabaseCommit, GetInspector, Inspector};
use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig};
use revm_primitives::{EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState};
use crate::{
cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
servers::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction},
EthApiError, EthResult, StateCacheDb,
};
use super::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction};
/// Executes CPU heavy tasks.
pub trait Trace: LoadState {

View File

@ -10,6 +10,10 @@ use reth_primitives::{
SealedBlockWithSenders, TransactionMeta, TransactionSigned, TxHash, TxKind, B256, U256,
};
use reth_provider::{BlockReaderIdExt, ReceiptProvider, TransactionsProvider};
use reth_rpc_eth_types::{
utils::recover_raw_transaction, EthApiError, EthResult, EthStateCache, SignError,
TransactionSource,
};
use reth_rpc_types::{
transaction::{
EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest,
@ -20,14 +24,9 @@ use reth_rpc_types::{
use reth_rpc_types_compat::transaction::from_recovered_with_block_context;
use reth_transaction_pool::{TransactionOrigin, TransactionPool};
use crate::{
servers::{
Call, EthApiSpec, EthSigner, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt,
SpawnBlocking,
},
utils::recover_raw_transaction,
EthApiError, EthResult, EthStateCache, SignError, TransactionSource,
};
use super::EthSigner;
use super::{Call, EthApiSpec, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, SpawnBlocking};
/// Transaction related functions for the [`EthApiServer`](crate::EthApiServer) trait in
/// the `eth_` namespace.

View File

@ -12,51 +12,22 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
pub mod api;
pub mod cache;
pub mod error;
pub mod fee_history;
pub mod gas_oracle;
pub mod id_provider;
pub mod logs_utils;
pub mod pending_block;
pub mod receipt;
pub mod result;
pub mod revm_utils;
pub mod transaction;
pub mod utils;
pub mod bundle;
pub mod core;
pub mod filter;
pub mod helpers;
pub mod pubsub;
pub use bundle::{EthBundleApiServer, EthCallBundleApiServer};
pub use core::EthApiServer;
pub use filter::EthFilterApiServer;
pub use pubsub::EthPubSubApiServer;
pub use helpers::transaction::RawTransactionForwarder;
#[cfg(feature = "client")]
pub use api::{
bundle::{EthBundleApiClient, EthCallBundleApiClient},
filter::EthFilterApiClient,
EthApiClient,
};
pub use api::{
bundle::{EthBundleApiServer, EthCallBundleApiServer},
filter::EthFilterApiServer,
pubsub::EthPubSubApiServer,
servers::{
self,
bundle::EthBundle,
filter::{EthFilter, EthFilterConfig},
pubsub::EthPubSub,
EthApi,
},
EthApiServer,
};
pub use cache::{
config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache,
EthStateCache,
};
pub use error::{EthApiError, EthResult, RevertError, RpcInvalidTransactionError, SignError};
pub use fee_history::{FeeHistoryCache, FeeHistoryCacheConfig, FeeHistoryEntry};
pub use gas_oracle::{
GasCap, GasPriceOracle, GasPriceOracleConfig, GasPriceOracleResult, ESTIMATE_GAS_ERROR_RATIO,
MIN_TRANSACTION_GAS, RPC_DEFAULT_GAS_CAP,
};
pub use id_provider::EthSubscriptionIdProvider;
pub use pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin};
pub use receipt::ReceiptBuilder;
pub use result::ToRpcResult;
pub use transaction::TransactionSource;
pub use bundle::{EthBundleApiClient, EthCallBundleApiClient};
#[cfg(feature = "client")]
pub use core::EthApiClient;
#[cfg(feature = "client")]
pub use filter::EthFilterApiClient;

View File

@ -0,0 +1,68 @@
[package]
name = "reth-rpc-eth-types"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
description = "Types supporting implementation of 'eth' namespace RPC server API"
[lints]
workspace = true
[dependencies]
reth-chainspec.workspace = true
reth-errors.workspace = true
reth-evm.workspace = true
reth-execution-types.workspace = true
reth-metrics.workspace = true
reth-primitives.workspace = true
reth-provider.workspace = true
reth-revm.workspace = true
reth-rpc-server-types.workspace = true
reth-rpc-types.workspace = true
reth-rpc-types-compat.workspace = true
reth-tasks.workspace = true
reth-transaction-pool.workspace = true
reth-trie.workspace = true
# ethereum
alloy-sol-types.workspace = true
revm.workspace = true
revm-inspectors = { workspace = true, features = ["js-tracer"] }
revm-primitives = { workspace = true, features = ["dev"] }
# rpc
jsonrpsee-core.workspace = true
jsonrpsee-types.workspace = true
# async
futures.workspace = true
tokio.workspace = true
tokio-stream.workspace = true
# metrics
metrics.workspace = true
# misc
serde = { workspace = true, features = ["derive"] }
thiserror.workspace = true
derive_more.workspace = true
schnellru.workspace = true
rand.workspace = true
tracing.workspace = true
[dev-dependencies]
serde_json.workspace = true
[features]
optimism = [
"reth-primitives/optimism",
"reth-provider/optimism",
"reth-revm/optimism",
"reth-chainspec/optimism",
"reth-execution-types/optimism",
"reth-revm/optimism",
"revm/optimism"
]

View File

@ -1,9 +1,13 @@
//! Configuration for RPC cache.
use reth_rpc_server_types::constants::cache::*;
use serde::{Deserialize, Serialize};
/// Settings for the [`EthStateCache`](crate::EthStateCache).
use reth_rpc_server_types::constants::cache::{
DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_ENV_CACHE_MAX_LEN,
DEFAULT_RECEIPT_CACHE_MAX_LEN,
};
/// Settings for the [`EthStateCache`](super::EthStateCache).
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EthStateCacheConfig {

View File

@ -1,6 +1,6 @@
//! Helper types to workaround 'higher-ranked lifetime error'
//! <https://github.com/rust-lang/rust/issues/100013> in default implementation of
//! [`Call`](crate::servers::Call).
//! `reth_rpc_eth_api::helpers::Call`.
use reth_primitives::{B256, U256};
use reth_provider::StateProvider;

View File

@ -26,7 +26,7 @@ use tokio::sync::{
};
use tokio_stream::wrappers::UnboundedReceiverStream;
use crate::{EthStateCacheConfig, MultiConsumerLruCache};
use super::{EthStateCacheConfig, MultiConsumerLruCache};
pub mod config;
pub mod db;
@ -276,7 +276,7 @@ impl EthStateCache {
/// handles messages and does LRU lookups and never blocking IO.
///
/// Caution: The channel for the data is _unbounded_ it is assumed that this is mainly used by the
/// [`EthApi`](crate::EthApi) which is typically invoked by the RPC server, which already uses
/// `reth_rpc::EthApi` which is typically invoked by the RPC server, which already uses
/// permits to limit concurrent requests.
#[must_use = "Type does nothing unless spawned"]
pub(crate) struct EthStateCacheService<

View File

@ -1,14 +1,16 @@
//! Metered cache, which also provides storage for senders in order to queue queries that result in
//! a cache miss.
use super::metrics::CacheMetrics;
use schnellru::{ByLength, Limiter, LruMap};
use std::{
collections::{hash_map::Entry, HashMap},
fmt::{self, Debug, Formatter},
hash::Hash,
};
use schnellru::{ByLength, Limiter, LruMap};
use super::metrics::CacheMetrics;
/// A multi-consumer LRU cache.
pub struct MultiConsumerLruCache<K, V, L, S>
where

View File

@ -1,10 +1,13 @@
//! Implementation specific Errors for the `eth_` namespace.
use crate::result::{internal_rpc_err, invalid_params_rpc_err, rpc_err, rpc_error_with_code};
use std::time::Duration;
use alloy_sol_types::decode_revert_reason;
use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObject};
use reth_errors::RethError;
use reth_primitives::{revm_primitives::InvalidHeader, Address, Bytes};
use reth_rpc_server_types::result::{
internal_rpc_err, invalid_params_rpc_err, rpc_err, rpc_error_with_code,
};
use reth_rpc_types::{
error::EthRpcErrorCode, request::TransactionInputError, BlockError, ToRpcError,
};
@ -14,7 +17,6 @@ use reth_transaction_pool::error::{
};
use revm::primitives::{EVMError, ExecutionResult, HaltReason, OutOfGasError};
use revm_inspectors::tracing::{js::JsInspectorError, MuxError};
use std::time::Duration;
/// Result alias
pub type EthResult<T> = Result<T, EthApiError>;
@ -134,7 +136,7 @@ impl EthApiError {
}
}
impl From<EthApiError> for ErrorObject<'static> {
impl From<EthApiError> for jsonrpsee_types::error::ErrorObject<'static> {
fn from(error: EthApiError) -> Self {
match error {
EthApiError::FailedToDecodeSignedTransaction |
@ -165,9 +167,10 @@ impl From<EthApiError> for ErrorObject<'static> {
EthApiError::Unsupported(msg) => internal_rpc_err(msg),
EthApiError::InternalJsTracerError(msg) => internal_rpc_err(msg),
EthApiError::InvalidParams(msg) => invalid_params_rpc_err(msg),
err @ EthApiError::ExecutionTimedOut(_) => {
rpc_error_with_code(CALL_EXECUTION_FAILED_CODE, err.to_string())
}
err @ EthApiError::ExecutionTimedOut(_) => rpc_error_with_code(
jsonrpsee_types::error::CALL_EXECUTION_FAILED_CODE,
err.to_string(),
),
err @ EthApiError::InternalBlockingTaskError | err @ EthApiError::InternalEthError => {
internal_rpc_err(err.to_string())
}
@ -386,7 +389,7 @@ impl RpcInvalidTransactionError {
/// Converts the halt error
///
/// Takes the configured gas limit of the transaction which is attached to the error
pub(crate) const fn halt(reason: HaltReason, gas_limit: u64) -> Self {
pub const fn halt(reason: HaltReason, gas_limit: u64) -> Self {
match reason {
HaltReason::OutOfGas(err) => Self::out_of_gas(err, gas_limit),
HaltReason::NonceOverflow => Self::NonceMaxValue,
@ -395,7 +398,7 @@ impl RpcInvalidTransactionError {
}
/// Converts the out of gas error
pub(crate) const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self {
pub const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self {
match reason {
OutOfGasError::Basic => Self::BasicOutOfGas(gas_limit),
OutOfGasError::Memory | OutOfGasError::MemoryLimit => Self::MemoryOutOfGas(gas_limit),
@ -405,7 +408,7 @@ impl RpcInvalidTransactionError {
}
}
impl From<RpcInvalidTransactionError> for ErrorObject<'static> {
impl From<RpcInvalidTransactionError> for jsonrpsee_types::error::ErrorObject<'static> {
fn from(err: RpcInvalidTransactionError) -> Self {
match err {
RpcInvalidTransactionError::Revert(revert) => {
@ -580,7 +583,7 @@ pub enum RpcPoolError {
Other(Box<dyn std::error::Error + Send + Sync>),
}
impl From<RpcPoolError> for ErrorObject<'static> {
impl From<RpcPoolError> for jsonrpsee_types::error::ErrorObject<'static> {
fn from(error: RpcPoolError) -> Self {
match error {
RpcPoolError::Invalid(err) => err.into(),
@ -655,7 +658,7 @@ pub enum SignError {
/// Converts the evm [`ExecutionResult`] into a result where `Ok` variant is the output bytes if it
/// is [`ExecutionResult::Success`].
pub(crate) fn ensure_success(result: ExecutionResult) -> EthResult<Bytes> {
pub fn ensure_success(result: ExecutionResult) -> EthResult<Bytes> {
match result {
ExecutionResult::Success { output, .. } => Ok(output.into_data()),
ExecutionResult::Revert { output, .. } => {

View File

@ -18,12 +18,13 @@ use reth_primitives::{
Receipt, SealedBlock, TransactionSigned, B256,
};
use reth_provider::{BlockReaderIdExt, CanonStateNotification, ChainSpecProvider};
use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY;
use reth_rpc_types::TxGasAndReward;
use serde::{Deserialize, Serialize};
use tracing::trace;
use crate::{EthApiError, EthStateCache};
use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY;
use super::{EthApiError, EthStateCache};
/// Contains cached fee history entries for blocks.
///
@ -265,7 +266,7 @@ pub async fn fee_history_cache_new_blocks_task<St, Provider>(
/// the corresponding rewards for the transactions at each percentile.
///
/// The results are returned as a vector of U256 values.
pub(crate) fn calculate_reward_percentiles_for_block(
pub fn calculate_reward_percentiles_for_block(
percentiles: &[f64],
gas_used: u64,
base_fee_per_gas: u64,

View File

@ -3,30 +3,25 @@
use std::fmt::{self, Debug, Formatter};
use derive_more::{Deref, DerefMut};
use derive_more::{Deref, DerefMut, From, Into};
use reth_primitives::{constants::GWEI_TO_WEI, BlockNumberOrTag, B256, U256};
use reth_provider::BlockReaderIdExt;
use reth_rpc_server_types::constants::gas_oracle::*;
use reth_rpc_server_types::constants;
use schnellru::{ByLength, LruMap};
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
use tracing::warn;
use crate::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError};
use reth_rpc_server_types::constants::gas_oracle::{
DEFAULT_GAS_PRICE_BLOCKS, DEFAULT_GAS_PRICE_PERCENTILE, DEFAULT_IGNORE_GAS_PRICE,
DEFAULT_MAX_GAS_PRICE, MAX_HEADER_HISTORY, SAMPLE_NUMBER,
};
/// The default gas limit for `eth_call` and adjacent calls.
///
/// This is different from the default to regular 30M block gas limit
/// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow for
/// more complex calls.
pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(50_000_000);
use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError};
/// Gas per transaction not creating a contract.
pub const MIN_TRANSACTION_GAS: u64 = 21_000u64;
/// Allowed error ratio for gas estimation
/// Taken from Geth's implementation in order to pass the hive tests
/// <https://github.com/ethereum/go-ethereum/blob/a5a4fa7032bb248f5a7c40f4e8df2b131c4186a4/internal/ethapi/api.go#L56>
pub const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015;
/// The default gas limit for `eth_call` and adjacent calls. See
/// [`RPC_DEFAULT_GAS_CAP`](constants::gas_oracle::RPC_DEFAULT_GAS_CAP).
pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(constants::gas_oracle::RPC_DEFAULT_GAS_CAP);
/// Settings for the [`GasPriceOracle`]
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
@ -300,8 +295,8 @@ impl Default for GasPriceOracleResult {
}
/// The wrapper type for gas limit
#[derive(Debug, Clone, Copy)]
pub struct GasCap(u64);
#[derive(Debug, Clone, Copy, From, Into)]
pub struct GasCap(pub u64);
impl Default for GasCap {
fn default() -> Self {
@ -309,18 +304,6 @@ impl Default for GasCap {
}
}
impl From<u64> for GasCap {
fn from(gas_cap: u64) -> Self {
Self(gas_cap)
}
}
impl From<GasCap> for u64 {
fn from(gas_cap: GasCap) -> Self {
gas_cap.0
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -1,19 +1,19 @@
//! Helper type for [`EthPubSubApiServer`](crate::EthPubSubApiServer) implementation.
//! Helper type for `reth_rpc_eth_api::EthPubSubApiServer` implementation.
//!
//! Generates IDs for tracking subscriptions.
use std::fmt::Write;
use jsonrpsee::types::SubscriptionId;
use jsonrpsee_types::SubscriptionId;
/// An [`IdProvider`](jsonrpsee::core::traits::IdProvider) for ethereum subscription ids.
/// An [`IdProvider`](jsonrpsee_core::traits::IdProvider) for ethereum subscription ids.
///
/// Returns new hex-string [QUANTITY](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding) ids
#[derive(Debug, Clone, Copy, Default)]
#[non_exhaustive]
pub struct EthSubscriptionIdProvider;
impl jsonrpsee::core::traits::IdProvider for EthSubscriptionIdProvider {
impl jsonrpsee_core::traits::IdProvider for EthSubscriptionIdProvider {
fn next_id(&self) -> SubscriptionId<'static> {
to_quantity(rand::random::<u128>())
}

View File

@ -0,0 +1,34 @@
//! Reth RPC server types, used in server implementation of `eth` namespace API.
#![doc(
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
pub mod cache;
pub mod error;
pub mod fee_history;
pub mod gas_oracle;
pub mod id_provider;
pub mod logs_utils;
pub mod pending_block;
pub mod receipt;
pub mod revm_utils;
pub mod transaction;
pub mod utils;
pub use cache::{
config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache,
EthStateCache,
};
pub use error::{EthApiError, EthResult, RevertError, RpcInvalidTransactionError, SignError};
pub use fee_history::{FeeHistoryCache, FeeHistoryCacheConfig, FeeHistoryEntry};
pub use gas_oracle::{GasCap, GasPriceOracle, GasPriceOracleConfig, GasPriceOracleResult};
pub use id_provider::EthSubscriptionIdProvider;
pub use logs_utils::EthFilterError;
pub use pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin};
pub use receipt::ReceiptBuilder;
pub use transaction::TransactionSource;

View File

@ -1,16 +1,66 @@
//! Helper functions for [`EthFilterApiServer`](crate::EthFilterApiServer) implementation.
//! Helper functions for `reth_rpc_eth_api::EthFilterApiServer` implementation.
//!
//! Log parsing for building filter.
use reth_chainspec::ChainInfo;
use reth_primitives::{BlockNumHash, Receipt, TxHash};
use reth_provider::{BlockReader, ProviderError};
use reth_rpc_types::{FilteredParams, Log};
use reth_rpc_server_types::result::rpc_error_with_code;
use reth_rpc_types::{FilterId, FilteredParams, Log};
use crate::servers::filter::EthFilterError;
use crate::EthApiError;
/// Errors that can occur in the handler implementation
#[derive(Debug, thiserror::Error)]
pub enum EthFilterError {
/// Filter not found.
#[error("filter not found")]
FilterNotFound(FilterId),
/// Invalid block range.
#[error("invalid block range params")]
InvalidBlockRangeParams,
/// Query scope is too broad.
#[error("query exceeds max block range {0}")]
QueryExceedsMaxBlocks(u64),
/// Query result is too large.
#[error("query exceeds max results {0}")]
QueryExceedsMaxResults(usize),
/// Error serving request in `eth_` namespace.
#[error(transparent)]
EthAPIError(#[from] EthApiError),
/// Error thrown when a spawned task failed to deliver a response.
#[error("internal filter error")]
InternalError,
}
// convert the error
impl From<EthFilterError> for jsonrpsee_types::error::ErrorObject<'static> {
fn from(err: EthFilterError) -> Self {
match err {
EthFilterError::FilterNotFound(_) => {
rpc_error_with_code(jsonrpsee_types::error::INVALID_PARAMS_CODE, "filter not found")
}
err @ EthFilterError::InternalError => {
rpc_error_with_code(jsonrpsee_types::error::INTERNAL_ERROR_CODE, err.to_string())
}
EthFilterError::EthAPIError(err) => err.into(),
err @ EthFilterError::InvalidBlockRangeParams |
err @ EthFilterError::QueryExceedsMaxBlocks(_) |
err @ EthFilterError::QueryExceedsMaxResults(_) => {
rpc_error_with_code(jsonrpsee_types::error::INVALID_PARAMS_CODE, err.to_string())
}
}
}
}
impl From<ProviderError> for EthFilterError {
fn from(err: ProviderError) -> Self {
Self::EthAPIError(err.into())
}
}
/// Returns all matching of a block's receipts when the transaction hashes are known.
pub(crate) fn matching_block_logs_with_tx_hashes<'a, I>(
pub fn matching_block_logs_with_tx_hashes<'a, I>(
filter: &FilteredParams,
block_num_hash: BlockNumHash,
tx_hashes_and_receipts: I,
@ -47,7 +97,7 @@ where
/// Appends all matching logs of a block's receipts.
/// If the log matches, look up the corresponding transaction hash.
pub(crate) fn append_matching_block_logs(
pub fn append_matching_block_logs(
all_logs: &mut Vec<Log>,
provider: impl BlockReader,
filter: &FilteredParams,
@ -114,7 +164,7 @@ pub(crate) fn append_matching_block_logs(
}
/// Returns true if the log matches the filter and should be included
pub(crate) fn log_matches_filter(
pub fn log_matches_filter(
block: BlockNumHash,
log: &reth_primitives::Log,
params: &FilteredParams,
@ -131,7 +181,7 @@ pub(crate) fn log_matches_filter(
}
/// Computes the block range based on the filter range and current block numbers
pub(crate) fn get_filter_block_range(
pub fn get_filter_block_range(
from_block: Option<u64>,
to_block: Option<u64>,
start_block: u64,

View File

@ -1,4 +1,4 @@
//! Helper types for [`EthApiServer`](crate::EthApiServer) implementation.
//! Helper types for `reth_rpc_eth_api::EthApiServer` implementation.
//!
//! Types used in block building.
@ -14,7 +14,7 @@ use revm_primitives::{
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg,
};
use crate::{EthApiError, EthResult};
use super::{EthApiError, EthResult};
/// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block
#[derive(Debug, Clone, Constructor)]

View File

@ -7,7 +7,7 @@ use reth_rpc_types::{
};
use revm_primitives::calc_blob_gasprice;
use crate::{EthApiError, EthResult};
use super::{EthApiError, EthResult};
/// Receipt response builder.
#[derive(Debug)]

View File

@ -19,7 +19,7 @@ use revm::{
};
use tracing::trace;
use crate::{EthApiError, EthResult, RpcInvalidTransactionError};
use super::{EthApiError, EthResult, RpcInvalidTransactionError};
/// Returns the addresses of the precompiles corresponding to the `SpecId`.
#[inline]

View File

@ -1,4 +1,4 @@
//! Helper types for [`EthApiServer`](crate::EthApiServer) implementation.
//! Helper types for `reth_rpc_eth_api::EthApiServer` implementation.
//!
//! Transaction wrapper that labels transaction with its origin.

View File

@ -2,7 +2,7 @@
use reth_primitives::{Bytes, PooledTransactionsElement, PooledTransactionsElementEcRecovered};
use crate::{EthApiError, EthResult};
use super::{EthApiError, EthResult};
/// Recovers a [`PooledTransactionsElementEcRecovered`] from an enveloped encoded byte stream.
///

View File

@ -12,9 +12,20 @@ description = "RPC server types and constants"
workspace = true
[dependencies]
reth-errors.workspace = true
reth-network-api.workspace = true
reth-primitives.workspace = true
reth-rpc-types.workspace = true
# ethereum
alloy-primitives.workspace = true
# rpc
jsonrpsee-core.workspace = true
jsonrpsee-types.workspace = true
# misc
strum = { workspace = true, features = ["derive"] }
serde = { workspace = true, features = ["derive"] }

View File

@ -64,6 +64,20 @@ pub mod gas_oracle {
/// The default minimum gas price, under which the sample will be ignored
pub const DEFAULT_IGNORE_GAS_PRICE: U256 = U256::from_limbs([2u64, 0, 0, 0]);
/// The default gas limit for `eth_call` and adjacent calls.
///
/// This is different from the default to regular 30M block gas limit
/// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow
/// for more complex calls.
pub const RPC_DEFAULT_GAS_CAP: u64 = 50_000_000;
/// Gas per transaction not creating a contract.
pub const MIN_TRANSACTION_GAS: u64 = 21_000u64;
/// Allowed error ratio for gas estimation
/// Taken from Geth's implementation in order to pass the hive tests
/// <https://github.com/ethereum/go-ethereum/blob/a5a4fa7032bb248f5a7c40f4e8df2b131c4186a4/internal/ethapi/api.go#L56>
pub const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015;
}
/// Cache specific constants

View File

@ -10,6 +10,9 @@
/// Common RPC constants.
pub mod constants;
pub mod result;
mod module;
pub use module::{RethRpcModule, RpcModuleSelection};
pub use result::ToRpcResult;

View File

@ -2,7 +2,7 @@
use std::fmt::Display;
use jsonrpsee::core::RpcResult;
use jsonrpsee_core::RpcResult;
use reth_rpc_types::engine::PayloadError;
/// Helper trait to easily convert various `Result` types into [`RpcResult`]
@ -22,14 +22,14 @@ pub trait ToRpcResult<Ok, Err>: Sized {
M: Into<String>;
/// Converts this type into an [`RpcResult`] with the
/// [`jsonrpsee::types::error::INTERNAL_ERROR_CODE` and the given message.
/// [`jsonrpsee_types::error::INTERNAL_ERROR_CODE`] and the given message.
fn map_internal_err<F, M>(self, op: F) -> RpcResult<Ok>
where
F: FnOnce(Err) -> M,
M: Into<String>;
/// Converts this type into an [`RpcResult`] with the
/// [`jsonrpsee::types::error::INTERNAL_ERROR_CODE`] and given message and data.
/// [`jsonrpsee_types::error::INTERNAL_ERROR_CODE`] and given message and data.
fn map_internal_err_with_data<'a, F, M>(self, op: F) -> RpcResult<Ok>
where
F: FnOnce(Err) -> (M, &'a [u8]),
@ -47,7 +47,7 @@ macro_rules! impl_to_rpc_result {
($err:ty) => {
impl<Ok> ToRpcResult<Ok, $err> for Result<Ok, $err> {
#[inline]
fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult<Ok>
fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
where
F: FnOnce($err) -> (i32, M, Option<&'a [u8]>),
M: Into<String>,
@ -62,7 +62,7 @@ macro_rules! impl_to_rpc_result {
}
#[inline]
fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult<Ok>
fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
where
F: FnOnce($err) -> M,
M: Into<String>,
@ -71,7 +71,7 @@ macro_rules! impl_to_rpc_result {
}
#[inline]
fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult<Ok>
fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
where
F: FnOnce($err) -> (M, &'a [u8]),
M: Into<String>,
@ -86,7 +86,7 @@ macro_rules! impl_to_rpc_result {
}
#[inline]
fn with_message(self, msg: &str) -> jsonrpsee::core::RpcResult<Ok> {
fn with_message(self, msg: &str) -> jsonrpsee_core::RpcResult<Ok> {
match self {
Ok(t) => Ok(t),
Err(err) => {
@ -107,28 +107,28 @@ impl_to_rpc_result!(reth_network_api::NetworkError);
/// Constructs an invalid params JSON-RPC error.
pub fn invalid_params_rpc_err(
msg: impl Into<String>,
) -> jsonrpsee::types::error::ErrorObject<'static> {
rpc_err(jsonrpsee::types::error::INVALID_PARAMS_CODE, msg, None)
) -> jsonrpsee_types::error::ErrorObject<'static> {
rpc_err(jsonrpsee_types::error::INVALID_PARAMS_CODE, msg, None)
}
/// Constructs an internal JSON-RPC error.
pub fn internal_rpc_err(msg: impl Into<String>) -> jsonrpsee::types::error::ErrorObject<'static> {
rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, None)
pub fn internal_rpc_err(msg: impl Into<String>) -> jsonrpsee_types::error::ErrorObject<'static> {
rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, None)
}
/// Constructs an internal JSON-RPC error with data
pub fn internal_rpc_err_with_data(
msg: impl Into<String>,
data: &[u8],
) -> jsonrpsee::types::error::ErrorObject<'static> {
rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, Some(data))
) -> jsonrpsee_types::error::ErrorObject<'static> {
rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, Some(data))
}
/// Constructs an internal JSON-RPC error with code and message
pub fn rpc_error_with_code(
code: i32,
msg: impl Into<String>,
) -> jsonrpsee::types::error::ErrorObject<'static> {
) -> jsonrpsee_types::error::ErrorObject<'static> {
rpc_err(code, msg, None)
}
@ -137,12 +137,12 @@ pub fn rpc_err(
code: i32,
msg: impl Into<String>,
data: Option<&[u8]>,
) -> jsonrpsee::types::error::ErrorObject<'static> {
jsonrpsee::types::error::ErrorObject::owned(
) -> jsonrpsee_types::error::ErrorObject<'static> {
jsonrpsee_types::error::ErrorObject::owned(
code,
msg.into(),
data.map(|data| {
jsonrpsee::core::to_json_raw_value(&reth_primitives::hex::encode_prefixed(data))
jsonrpsee_core::to_json_raw_value(&reth_primitives::hex::encode_prefixed(data))
.expect("serializing String can't fail")
}),
)

View File

@ -29,11 +29,6 @@ serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
jsonrpsee-types = { workspace = true, optional = true }
[features]
default = ["jsonrpsee-types"]
arbitrary = ["alloy-primitives/arbitrary", "alloy-rpc-types/arbitrary"]
[dev-dependencies]
# misc
alloy-primitives = { workspace = true, features = ["rand", "rlp", "serde", "arbitrary"] }
@ -44,3 +39,6 @@ rand.workspace = true
similar-asserts.workspace = true
bytes.workspace = true
[features]
default = ["jsonrpsee-types"]
arbitrary = ["alloy-primitives/arbitrary", "alloy-rpc-types/arbitrary"]

View File

@ -29,8 +29,13 @@ reth-consensus-common.workspace = true
reth-rpc-types-compat.workspace = true
revm-inspectors = { workspace = true, features = ["js-tracer"] }
reth-network-peers.workspace = true
reth-evm.workspace = true
reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true
reth-evm-optimism = { workspace = true, optional = true }
# eth
alloy-dyn-abi.workspace = true
alloy-rlp.workspace = true
alloy-primitives.workspace = true
alloy-genesis.workspace = true
@ -40,6 +45,7 @@ revm = { workspace = true, features = [
"optional_no_base_fee",
] }
revm-primitives = { workspace = true, features = ["serde"] }
secp256k1.workspace = true
# rpc
jsonrpsee.workspace = true
@ -47,21 +53,29 @@ http.workspace = true
http-body.workspace = true
hyper.workspace = true
jsonwebtoken.workspace = true
serde_json.workspace = true
jsonrpsee-types = { workspace = true, optional = true }
# async
async-trait.workspace = true
tokio = { workspace = true, features = ["sync"] }
tokio-stream.workspace = true
tower.workspace = true
pin-project.workspace = true
parking_lot.workspace = true
# misc
tracing.workspace = true
tracing-futures = "0.2"
futures.workspace = true
rand.workspace = true
serde.workspace = true
thiserror.workspace = true
[dev-dependencies]
reth-evm-ethereum.workspace = true
reth-testing-utils.workspace = true
jsonrpsee-types.workspace = true
jsonrpsee = { workspace = true, features = ["client"] }
assert_matches.workspace = true
@ -75,4 +89,7 @@ optimism = [
"reth-rpc-api/optimism",
"reth-rpc-eth-api/optimism",
"reth-revm/optimism",
"jsonrpsee-types",
"reth-evm-optimism",
"reth-rpc-eth-types/optimism",
]

View File

@ -8,13 +8,12 @@ use reth_chainspec::ChainSpec;
use reth_network_api::{NetworkInfo, PeerKind, Peers};
use reth_network_peers::{AnyNode, NodeRecord};
use reth_rpc_api::AdminApiServer;
use reth_rpc_server_types::ToRpcResult;
use reth_rpc_types::{
admin::{EthProtocolInfo, NodeInfo, Ports, ProtocolInfo},
PeerEthProtocolInfo, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo,
};
use crate::result::ToRpcResult;
/// `admin` API implementation.
///
/// This type provides the functionality for handling `admin` related requests.

View File

@ -13,12 +13,9 @@ use reth_provider::{
};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_api::DebugApiServer;
use reth_rpc_eth_api::{
result::internal_rpc_err,
revm_utils::prepare_call_env,
servers::{EthApiSpec, EthTransactions, TraceExt},
EthApiError, EthResult, StateCacheDb, ToRpcResult,
};
use reth_rpc_eth_api::helpers::{EthApiSpec, EthTransactions, TraceExt};
use reth_rpc_eth_types::{revm_utils::prepare_call_env, EthApiError, EthResult, StateCacheDb};
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use reth_rpc_types::{
state::EvmOverrides,
trace::geth::{

View File

@ -18,10 +18,12 @@ use revm::{
};
use revm_primitives::{EnvKzgSettings, EnvWithHandlerCfg, MAX_BLOB_GAS_PER_BLOCK};
use crate::{
servers::{Call, EthTransactions, LoadPendingBlock},
utils::recover_raw_transaction,
EthApiError, EthCallBundleApiServer, EthResult, RpcInvalidTransactionError,
use reth_rpc_eth_api::{
helpers::{Call, EthTransactions, LoadPendingBlock},
EthCallBundleApiServer,
};
use reth_rpc_eth_types::{
utils::recover_raw_transaction, EthApiError, EthResult, RpcInvalidTransactionError,
};
/// `Eth` bundle implementation.

View File

@ -0,0 +1,601 @@
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait
//! Handles RPC requests for the `eth_` namespace.
use std::sync::Arc;
use reth_primitives::{BlockNumberOrTag, U256};
use reth_provider::{BlockReaderIdExt, ChainSpecProvider};
use reth_rpc_eth_api::{
helpers::{EthSigner, SpawnBlocking},
RawTransactionForwarder,
};
use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock};
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
use tokio::sync::Mutex;
use crate::eth::DevSigner;
/// `Eth` API implementation.
///
/// This type provides the functionality for handling `eth_` related requests.
/// These are implemented two-fold: Core functionality is implemented as
/// [`EthApiSpec`](reth_rpc_eth_api::helpers::EthApiSpec) trait. Additionally, the required server
/// implementations (e.g. [`EthApiServer`](reth_rpc_eth_api::EthApiServer)) are implemented
/// separately in submodules. The rpc handler implementation can then delegate to the main impls.
/// This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone or in other
/// network handlers (for example ipc).
pub struct EthApi<Provider, Pool, Network, EvmConfig> {
/// All nested fields bundled together.
pub(super) inner: Arc<EthApiInner<Provider, Pool, Network, EvmConfig>>,
}
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
/// Sets a forwarder for `eth_sendRawTransaction`
///
/// Note: this might be removed in the future in favor of a more generic approach.
pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc<dyn RawTransactionForwarder>) {
self.inner.raw_transaction_forwarder.write().replace(forwarder);
}
}
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
where
Provider: BlockReaderIdExt + ChainSpecProvider,
{
/// Creates a new, shareable instance using the default tokio task spawner.
#[allow(clippy::too_many_arguments)]
pub fn new(
provider: Provider,
pool: Pool,
network: Network,
eth_cache: EthStateCache,
gas_oracle: GasPriceOracle<Provider>,
gas_cap: impl Into<GasCap>,
blocking_task_pool: BlockingTaskPool,
fee_history_cache: FeeHistoryCache,
evm_config: EvmConfig,
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
) -> Self {
Self::with_spawner(
provider,
pool,
network,
eth_cache,
gas_oracle,
gas_cap.into().into(),
Box::<TokioTaskExecutor>::default(),
blocking_task_pool,
fee_history_cache,
evm_config,
raw_transaction_forwarder,
)
}
/// Creates a new, shareable instance.
#[allow(clippy::too_many_arguments)]
pub fn with_spawner(
provider: Provider,
pool: Pool,
network: Network,
eth_cache: EthStateCache,
gas_oracle: GasPriceOracle<Provider>,
gas_cap: u64,
task_spawner: Box<dyn TaskSpawner>,
blocking_task_pool: BlockingTaskPool,
fee_history_cache: FeeHistoryCache,
evm_config: EvmConfig,
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
) -> Self {
// get the block number of the latest block
let latest_block = provider
.header_by_number_or_tag(BlockNumberOrTag::Latest)
.ok()
.flatten()
.map(|header| header.number)
.unwrap_or_default();
let inner = EthApiInner {
provider,
pool,
network,
signers: parking_lot::RwLock::new(Default::default()),
eth_cache,
gas_oracle,
gas_cap,
starting_block: U256::from(latest_block),
task_spawner,
pending_block: Default::default(),
blocking_task_pool,
fee_history_cache,
evm_config,
raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder),
};
Self { inner: Arc::new(inner) }
}
/// Returns the state cache frontend
pub fn cache(&self) -> &EthStateCache {
&self.inner.eth_cache
}
/// Returns the gas oracle frontend
pub fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
&self.inner.gas_oracle
}
/// Returns the configured gas limit cap for `eth_call` and tracing related calls
pub fn gas_cap(&self) -> u64 {
self.inner.gas_cap
}
/// Returns the inner `Provider`
pub fn provider(&self) -> &Provider {
&self.inner.provider
}
/// Returns the inner `Network`
pub fn network(&self) -> &Network {
&self.inner.network
}
/// Returns the inner `Pool`
pub fn pool(&self) -> &Pool {
&self.inner.pool
}
/// Returns fee history cache
pub fn fee_history_cache(&self) -> &FeeHistoryCache {
&self.inner.fee_history_cache
}
}
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
for EthApi<Provider, Pool, Network, EvmConfig>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EthApi").finish_non_exhaustive()
}
}
impl<Provider, Pool, Network, EvmConfig> Clone for EthApi<Provider, Pool, Network, EvmConfig> {
fn clone(&self) -> Self {
Self { inner: Arc::clone(&self.inner) }
}
}
impl<Provider, Pool, Network, EvmConfig> SpawnBlocking
for EthApi<Provider, Pool, Network, EvmConfig>
where
Self: Clone + Send + Sync + 'static,
{
#[inline]
fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner {
self.inner.task_spawner()
}
#[inline]
fn tracing_task_pool(&self) -> &reth_tasks::pool::BlockingTaskPool {
self.inner.blocking_task_pool()
}
}
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
/// Generates 20 random developer accounts.
/// Used in DEV mode.
pub fn with_dev_accounts(&self) {
let mut signers = self.inner.signers.write();
*signers = DevSigner::random_signers(20);
}
}
/// Container type `EthApi`
#[allow(missing_debug_implementations)]
pub struct EthApiInner<Provider, Pool, Network, EvmConfig> {
/// The transaction pool.
pool: Pool,
/// The provider that can interact with the chain.
provider: Provider,
/// An interface to interact with the network
network: Network,
/// All configured Signers
signers: parking_lot::RwLock<Vec<Box<dyn EthSigner>>>,
/// The async cache frontend for eth related data
eth_cache: EthStateCache,
/// The async gas oracle frontend for gas price suggestions
gas_oracle: GasPriceOracle<Provider>,
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
gas_cap: u64,
/// The block number at which the node started
starting_block: U256,
/// The type that can spawn tasks which would otherwise block.
task_spawner: Box<dyn TaskSpawner>,
/// Cached pending block if any
pending_block: Mutex<Option<PendingBlock>>,
/// A pool dedicated to CPU heavy blocking tasks.
blocking_task_pool: BlockingTaskPool,
/// Cache for block fees history
fee_history_cache: FeeHistoryCache,
/// The type that defines how to configure the EVM
evm_config: EvmConfig,
/// Allows forwarding received raw transactions
raw_transaction_forwarder: parking_lot::RwLock<Option<Arc<dyn RawTransactionForwarder>>>,
}
impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig> {
/// Returns a handle to data on disk.
#[inline]
pub const fn provider(&self) -> &Provider {
&self.provider
}
/// Returns a handle to data in memory.
#[inline]
pub const fn cache(&self) -> &EthStateCache {
&self.eth_cache
}
/// Returns a handle to the pending block.
#[inline]
pub const fn pending_block(&self) -> &Mutex<Option<PendingBlock>> {
&self.pending_block
}
/// Returns a handle to the task spawner.
#[inline]
pub const fn task_spawner(&self) -> &dyn TaskSpawner {
&*self.task_spawner
}
/// Returns a handle to the blocking thread pool.
#[inline]
pub const fn blocking_task_pool(&self) -> &BlockingTaskPool {
&self.blocking_task_pool
}
/// Returns a handle to the EVM config.
#[inline]
pub const fn evm_config(&self) -> &EvmConfig {
&self.evm_config
}
/// Returns a handle to the transaction pool.
#[inline]
pub const fn pool(&self) -> &Pool {
&self.pool
}
/// Returns a handle to the transaction forwarder.
#[inline]
pub fn raw_tx_forwarder(&self) -> Option<Arc<dyn RawTransactionForwarder>> {
self.raw_transaction_forwarder.read().clone()
}
/// Returns the gas cap.
#[inline]
pub const fn gas_cap(&self) -> u64 {
self.gas_cap
}
/// Returns a handle to the gas oracle.
#[inline]
pub const fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
&self.gas_oracle
}
/// Returns a handle to the fee history cache.
#[inline]
pub const fn fee_history_cache(&self) -> &FeeHistoryCache {
&self.fee_history_cache
}
/// Returns a handle to the signers.
#[inline]
pub const fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
&self.signers
}
/// Returns the starting block.
#[inline]
pub const fn starting_block(&self) -> U256 {
self.starting_block
}
}
#[cfg(test)]
mod tests {
use jsonrpsee_types::error::INVALID_PARAMS_CODE;
use reth_chainspec::BaseFeeParams;
use reth_evm_ethereum::EthEvmConfig;
use reth_network_api::noop::NoopNetwork;
use reth_primitives::{
constants::ETHEREUM_BLOCK_GAS_LIMIT, Block, BlockNumberOrTag, Header, TransactionSigned,
B256, U64,
};
use reth_provider::{
test_utils::{MockEthProvider, NoopProvider},
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory,
};
use reth_rpc_eth_api::EthApiServer;
use reth_rpc_eth_types::{
EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
};
use reth_rpc_types::FeeHistory;
use reth_tasks::pool::BlockingTaskPool;
use reth_testing_utils::{generators, generators::Rng};
use reth_transaction_pool::test_utils::{testing_pool, TestPool};
use crate::EthApi;
fn build_test_eth_api<
P: BlockReaderIdExt
+ BlockReader
+ ChainSpecProvider
+ EvmEnvProvider
+ StateProviderFactory
+ Unpin
+ Clone
+ 'static,
>(
provider: P,
) -> EthApi<P, TestPool, NoopNetwork, EthEvmConfig> {
let evm_config = EthEvmConfig::default();
let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config);
let fee_history_cache =
FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default());
EthApi::new(
provider.clone(),
testing_pool(),
NoopNetwork::default(),
cache.clone(),
GasPriceOracle::new(provider, Default::default(), cache),
ETHEREUM_BLOCK_GAS_LIMIT,
BlockingTaskPool::build().expect("failed to build tracing pool"),
fee_history_cache,
evm_config,
None,
)
}
// Function to prepare the EthApi with mock data
fn prepare_eth_api(
newest_block: u64,
mut oldest_block: Option<B256>,
block_count: u64,
mock_provider: MockEthProvider,
) -> (EthApi<MockEthProvider, TestPool, NoopNetwork, EthEvmConfig>, Vec<u128>, Vec<f64>) {
let mut rng = generators::rng();
// Build mock data
let mut gas_used_ratios = Vec::new();
let mut base_fees_per_gas = Vec::new();
let mut last_header = None;
let mut parent_hash = B256::default();
for i in (0..block_count).rev() {
let hash = rng.gen();
let gas_limit: u64 = rng.gen();
let gas_used: u64 = rng.gen();
// Note: Generates a u32 to avoid overflows later
let base_fee_per_gas: Option<u64> = rng.gen::<bool>().then(|| rng.gen::<u32>() as u64);
let header = Header {
number: newest_block - i,
gas_limit,
gas_used,
base_fee_per_gas,
parent_hash,
..Default::default()
};
last_header = Some(header.clone());
parent_hash = hash;
let mut transactions = vec![];
for _ in 0..100 {
let random_fee: u128 = rng.gen();
if let Some(base_fee_per_gas) = header.base_fee_per_gas {
let transaction = TransactionSigned {
transaction: reth_primitives::Transaction::Eip1559(
reth_primitives::TxEip1559 {
max_priority_fee_per_gas: random_fee,
max_fee_per_gas: random_fee + base_fee_per_gas as u128,
..Default::default()
},
),
..Default::default()
};
transactions.push(transaction);
} else {
let transaction = TransactionSigned {
transaction: reth_primitives::Transaction::Legacy(Default::default()),
..Default::default()
};
transactions.push(transaction);
}
}
mock_provider.add_block(
hash,
Block { header: header.clone(), body: transactions, ..Default::default() },
);
mock_provider.add_header(hash, header);
oldest_block.get_or_insert(hash);
gas_used_ratios.push(gas_used as f64 / gas_limit as f64);
base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default());
}
// Add final base fee (for the next block outside of the request)
let last_header = last_header.unwrap();
base_fees_per_gas.push(BaseFeeParams::ethereum().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,
));
let eth_api = build_test_eth_api(mock_provider);
(eth_api, base_fees_per_gas, gas_used_ratios)
}
/// Invalid block range
#[tokio::test]
async fn test_fee_history_empty() {
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&build_test_eth_api(NoopProvider::default()),
U64::from(1),
BlockNumberOrTag::Latest,
None,
)
.await;
assert!(response.is_err());
let error_object = response.unwrap_err();
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
}
#[tokio::test]
/// Invalid block range (request is before genesis)
async fn test_fee_history_invalid_block_range_before_genesis() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, _, _) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&eth_api,
U64::from(newest_block + 1),
newest_block.into(),
Some(vec![10.0]),
)
.await;
assert!(response.is_err());
let error_object = response.unwrap_err();
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
}
#[tokio::test]
/// Invalid block range (request is in the future)
async fn test_fee_history_invalid_block_range_in_future() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, _, _) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&eth_api,
U64::from(1),
(newest_block + 1000).into(),
Some(vec![10.0]),
)
.await;
assert!(response.is_err());
let error_object = response.unwrap_err();
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
}
#[tokio::test]
/// Requesting no block should result in a default response
async fn test_fee_history_no_block_requested() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, _, _) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
&eth_api,
U64::from(0),
newest_block.into(),
None,
)
.await
.unwrap();
assert_eq!(
response,
FeeHistory::default(),
"none: requesting no block should yield a default response"
);
}
#[tokio::test]
/// Requesting a single block should return 1 block (+ base fee for the next block over)
async fn test_fee_history_single_block() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, base_fees_per_gas, gas_used_ratios) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let fee_history =
eth_api.fee_history(U64::from(1), newest_block.into(), None).await.unwrap();
assert_eq!(
fee_history.base_fee_per_gas,
&base_fees_per_gas[base_fees_per_gas.len() - 2..],
"one: base fee per gas is incorrect"
);
assert_eq!(
fee_history.base_fee_per_gas.len(),
2,
"one: should return base fee of the next block as well"
);
assert_eq!(
&fee_history.gas_used_ratio,
&gas_used_ratios[gas_used_ratios.len() - 1..],
"one: gas used ratio is incorrect"
);
assert_eq!(fee_history.oldest_block, newest_block, "one: oldest block is incorrect");
assert!(
fee_history.reward.is_none(),
"one: no percentiles were requested, so there should be no rewards result"
);
}
/// Requesting all blocks should be ok
#[tokio::test]
async fn test_fee_history_all_blocks() {
let block_count = 10;
let newest_block = 1337;
let oldest_block = None;
let (eth_api, base_fees_per_gas, gas_used_ratios) =
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
let fee_history =
eth_api.fee_history(U64::from(block_count), newest_block.into(), None).await.unwrap();
assert_eq!(
&fee_history.base_fee_per_gas, &base_fees_per_gas,
"all: base fee per gas is incorrect"
);
assert_eq!(
fee_history.base_fee_per_gas.len() as u64,
block_count + 1,
"all: should return base fee of the next block as well"
);
assert_eq!(
&fee_history.gas_used_ratio, &gas_used_ratios,
"all: gas used ratio is incorrect"
);
assert_eq!(
fee_history.oldest_block,
newest_block - block_count + 1,
"all: oldest block is incorrect"
);
assert!(
fee_history.reward.is_none(),
"all: no percentiles were requested, so there should be no rewards result"
);
}
}

View File

@ -14,6 +14,12 @@ use jsonrpsee::{core::RpcResult, server::IdProvider};
use reth_chainspec::ChainInfo;
use reth_primitives::{IntoRecoveredTransaction, TxHash};
use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError};
use reth_rpc_eth_api::EthFilterApiServer;
use reth_rpc_eth_types::{
logs_utils::{self, append_matching_block_logs},
EthApiError, EthFilterError, EthStateCache, EthSubscriptionIdProvider,
};
use reth_rpc_server_types::ToRpcResult;
use reth_rpc_types::{
BlockNumHash, Filter, FilterBlockOption, FilterChanges, FilterId, FilteredParams, Log,
PendingTransactionFilterKind,
@ -26,12 +32,6 @@ use tokio::{
};
use tracing::trace;
use crate::{
logs_utils::{self, append_matching_block_logs},
result::rpc_error_with_code,
EthApiError, EthFilterApiServer, EthStateCache, EthSubscriptionIdProvider, ToRpcResult,
};
/// The maximum number of headers we read at once when handling a range filter.
const MAX_HEADERS_RANGE: u64 = 1_000; // with ~530bytes per header this is ~500kb
@ -706,56 +706,6 @@ impl Iterator for BlockRangeInclusiveIter {
}
}
/// Errors that can occur in the handler implementation
#[derive(Debug, thiserror::Error)]
pub enum EthFilterError {
/// Filter not found.
#[error("filter not found")]
FilterNotFound(FilterId),
/// Invalid block range.
#[error("invalid block range params")]
InvalidBlockRangeParams,
/// Query scope is too broad.
#[error("query exceeds max block range {0}")]
QueryExceedsMaxBlocks(u64),
/// Query result is too large.
#[error("query exceeds max results {0}")]
QueryExceedsMaxResults(usize),
/// Error serving request in `eth_` namespace.
#[error(transparent)]
EthAPIError(#[from] EthApiError),
/// Error thrown when a spawned task failed to deliver a response.
#[error("internal filter error")]
InternalError,
}
// convert the error
impl From<EthFilterError> for jsonrpsee::types::error::ErrorObject<'static> {
fn from(err: EthFilterError) -> Self {
match err {
EthFilterError::FilterNotFound(_) => rpc_error_with_code(
jsonrpsee::types::error::INVALID_PARAMS_CODE,
"filter not found",
),
err @ EthFilterError::InternalError => {
rpc_error_with_code(jsonrpsee::types::error::INTERNAL_ERROR_CODE, err.to_string())
}
EthFilterError::EthAPIError(err) => err.into(),
err @ EthFilterError::InvalidBlockRangeParams |
err @ EthFilterError::QueryExceedsMaxBlocks(_) |
err @ EthFilterError::QueryExceedsMaxResults(_) => {
rpc_error_with_code(jsonrpsee::types::error::INVALID_PARAMS_CODE, err.to_string())
}
}
}
}
impl From<ProviderError> for EthFilterError {
fn from(err: ProviderError) -> Self {
Self::EthAPIError(err.into())
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -1,11 +1,10 @@
//! Contains RPC handler implementations specific to blocks.
use reth_provider::{BlockReaderIdExt, HeaderProvider};
use reth_rpc_eth_api::helpers::{EthBlocks, LoadBlock, LoadPendingBlock, SpawnBlocking};
use reth_rpc_eth_types::EthStateCache;
use crate::{
servers::{EthBlocks, LoadBlock, LoadPendingBlock, SpawnBlocking},
EthApi, EthStateCache,
};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthBlocks for EthApi<Provider, Pool, Network, EvmConfig>
where

View File

@ -1,11 +1,9 @@
//! Contains RPC handler implementations specific to endpoints that call/execute within evm.
use reth_evm::ConfigureEvm;
use reth_rpc_eth_api::helpers::{Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking};
use crate::{
servers::{Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking},
EthApi,
};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthCall for EthApi<Provider, Pool, Network, EvmConfig> where
Self: Call + LoadPendingBlock

View File

@ -0,0 +1,346 @@
//! Loads fee history from database. Helper trait for `eth_` fee and transaction RPC methods.
use futures::Future;
use reth_primitives::U256;
use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider};
use reth_rpc_types::{BlockNumberOrTag, FeeHistory};
use tracing::debug;
use crate::{
fee_history::calculate_reward_percentiles_for_block, api::LoadBlock, EthApiError,
EthResult, EthStateCache, FeeHistoryCache, FeeHistoryEntry, GasPriceOracle,
RpcInvalidTransactionError,
};
/// Fee related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
/// `eth_` namespace.
pub trait EthFees: LoadFee {
/// Returns a suggestion for a gas price for legacy transactions.
///
/// See also: <https://github.com/ethereum/pm/issues/328#issuecomment-853234014>
fn gas_price(&self) -> impl Future<Output = EthResult<U256>> + Send
where
Self: LoadBlock,
{
LoadFee::gas_price(self)
}
/// Returns a suggestion for a base fee for blob transactions.
fn blob_base_fee(&self) -> impl Future<Output = EthResult<U256>> + Send
where
Self: LoadBlock,
{
LoadFee::blob_base_fee(self)
}
/// Returns a suggestion for the priority fee (the tip)
fn suggested_priority_fee(&self) -> impl Future<Output = EthResult<U256>> + Send
where
Self: 'static,
{
LoadFee::suggested_priority_fee(self)
}
/// Reports the fee history, for the given amount of blocks, up until the given newest block.
///
/// If `reward_percentiles` are provided the [`FeeHistory`] will include the _approximated_
/// rewards for the requested range.
fn fee_history(
&self,
mut block_count: u64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> impl Future<Output = EthResult<FeeHistory>> + Send {
async move {
if block_count == 0 {
return Ok(FeeHistory::default())
}
// See https://github.com/ethereum/go-ethereum/blob/2754b197c935ee63101cbbca2752338246384fec/eth/gasprice/feehistory.go#L218C8-L225
let max_fee_history = if reward_percentiles.is_none() {
self.gas_oracle().config().max_header_history
} else {
self.gas_oracle().config().max_block_history
};
if block_count > max_fee_history {
debug!(
requested = block_count,
truncated = max_fee_history,
"Sanitizing fee history block count"
);
block_count = max_fee_history
}
let Some(end_block) =
LoadFee::provider(self).block_number_for_id(newest_block.into())?
else {
return Err(EthApiError::UnknownBlockNumber)
};
// need to add 1 to the end block to get the correct (inclusive) range
let end_block_plus = end_block + 1;
// Ensure that we would not be querying outside of genesis
if end_block_plus < block_count {
block_count = end_block_plus;
}
// If reward percentiles were specified, we
// need to validate that they are monotonically
// increasing and 0 <= p <= 100
// Note: The types used ensure that the percentiles are never < 0
if let Some(percentiles) = &reward_percentiles {
if percentiles.windows(2).any(|w| w[0] > w[1] || w[0] > 100.) {
return Err(EthApiError::InvalidRewardPercentiles)
}
}
// Fetch the headers and ensure we got all of them
//
// Treat a request for 1 block as a request for `newest_block..=newest_block`,
// otherwise `newest_block - 2
// NOTE: We ensured that block count is capped
let start_block = end_block_plus - block_count;
// Collect base fees, gas usage ratios and (optionally) reward percentile data
let mut base_fee_per_gas: Vec<u128> = Vec::new();
let mut gas_used_ratio: Vec<f64> = Vec::new();
let mut base_fee_per_blob_gas: Vec<u128> = Vec::new();
let mut blob_gas_used_ratio: Vec<f64> = Vec::new();
let mut rewards: Vec<Vec<u128>> = Vec::new();
// Check if the requested range is within the cache bounds
let fee_entries = self.fee_history_cache().get_history(start_block, end_block).await;
if let Some(fee_entries) = fee_entries {
if fee_entries.len() != block_count as usize {
return Err(EthApiError::InvalidBlockRange)
}
for entry in &fee_entries {
base_fee_per_gas.push(entry.base_fee_per_gas as u128);
gas_used_ratio.push(entry.gas_used_ratio);
base_fee_per_blob_gas.push(entry.base_fee_per_blob_gas.unwrap_or_default());
blob_gas_used_ratio.push(entry.blob_gas_used_ratio);
if let Some(percentiles) = &reward_percentiles {
let mut block_rewards = Vec::with_capacity(percentiles.len());
for &percentile in percentiles {
block_rewards.push(self.approximate_percentile(entry, percentile));
}
rewards.push(block_rewards);
}
}
let last_entry = fee_entries.last().expect("is not empty");
// Also need to include the `base_fee_per_gas` and `base_fee_per_blob_gas` for the
// next block
base_fee_per_gas
.push(last_entry.next_block_base_fee(&LoadFee::provider(self).chain_spec())
as u128);
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)?;
if headers.len() != block_count as usize {
return Err(EthApiError::InvalidBlockRange)
}
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?
.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());
};
Ok(FeeHistory {
base_fee_per_gas,
gas_used_ratio,
base_fee_per_blob_gas,
blob_gas_used_ratio,
oldest_block: start_block,
reward: reward_percentiles.map(|_| rewards),
})
}
}
/// Approximates reward at a given percentile for a specific block
/// Based on the configured resolution
fn approximate_percentile(&self, entry: &FeeHistoryEntry, requested_percentile: f64) -> u128 {
let resolution = self.fee_history_cache().resolution();
let rounded_percentile =
(requested_percentile * resolution as f64).round() / resolution as f64;
let clamped_percentile = rounded_percentile.clamp(0.0, 100.0);
// Calculate the index in the precomputed rewards array
let index = (clamped_percentile / (1.0 / resolution as f64)).round() as usize;
// Fetch the reward from the FeeHistoryEntry
entry.rewards.get(index).cloned().unwrap_or_default()
}
}
/// Loads fee from database.
///
/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` fees RPC methods.
pub trait LoadFee: LoadBlock {
// Returns a handle for reading data from disk.
///
/// Data access in default (L1) trait method implementations.
fn provider(&self) -> impl BlockIdReader + HeaderProvider + ChainSpecProvider;
/// Returns a handle for reading data from memory.
///
/// Data access in default (L1) trait method implementations.
fn cache(&self) -> &EthStateCache;
/// Returns a handle for reading gas price.
///
/// Data access in default (L1) trait method implementations.
fn gas_oracle(&self) -> &GasPriceOracle<impl BlockReaderIdExt>;
/// Returns a handle for reading fee history data from memory.
///
/// Data access in default (L1) trait method implementations.
fn fee_history_cache(&self) -> &FeeHistoryCache;
/// Returns the gas price if it is set, otherwise fetches a suggested gas price for legacy
/// transactions.
fn legacy_gas_price(
&self,
gas_price: Option<U256>,
) -> impl Future<Output = EthResult<U256>> + Send {
async move {
match gas_price {
Some(gas_price) => Ok(gas_price),
None => {
// fetch a suggested gas price
self.gas_price().await
}
}
}
}
/// Returns the EIP-1559 fees if they are set, otherwise fetches a suggested gas price for
/// EIP-1559 transactions.
///
/// Returns (`max_fee`, `priority_fee`)
fn eip1559_fees(
&self,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
) -> impl Future<Output = EthResult<(U256, U256)>> + Send {
async move {
let max_fee_per_gas = match max_fee_per_gas {
Some(max_fee_per_gas) => max_fee_per_gas,
None => {
// fetch pending base fee
let base_fee = self
.block(BlockNumberOrTag::Pending)
.await?
.ok_or(EthApiError::UnknownBlockNumber)?
.base_fee_per_gas
.ok_or_else(|| {
EthApiError::InvalidTransaction(
RpcInvalidTransactionError::TxTypeNotSupported,
)
})?;
U256::from(base_fee)
}
};
let max_priority_fee_per_gas = match max_priority_fee_per_gas {
Some(max_priority_fee_per_gas) => max_priority_fee_per_gas,
None => self.suggested_priority_fee().await?,
};
Ok((max_fee_per_gas, max_priority_fee_per_gas))
}
}
/// Returns the EIP-4844 blob fee if it is set, otherwise fetches a blob fee.
fn eip4844_blob_fee(
&self,
blob_fee: Option<U256>,
) -> impl Future<Output = EthResult<U256>> + Send {
async move {
match blob_fee {
Some(blob_fee) => Ok(blob_fee),
None => self.blob_base_fee().await,
}
}
}
/// Returns a suggestion for a gas price for legacy transactions.
///
/// See also: <https://github.com/ethereum/pm/issues/328#issuecomment-853234014>
fn gas_price(&self) -> impl Future<Output = EthResult<U256>> + Send {
let header = self.block(BlockNumberOrTag::Latest);
let suggested_tip = self.suggested_priority_fee();
async move {
let (header, suggested_tip) = futures::try_join!(header, suggested_tip)?;
let base_fee = header.and_then(|h| h.base_fee_per_gas).unwrap_or_default();
Ok(suggested_tip + U256::from(base_fee))
}
}
/// Returns a suggestion for a base fee for blob transactions.
fn blob_base_fee(&self) -> impl Future<Output = EthResult<U256>> + Send {
async move {
self.block(BlockNumberOrTag::Latest)
.await?
.and_then(|h: reth_primitives::SealedBlock| h.next_block_blob_fee())
.ok_or(EthApiError::ExcessBlobGasNotSet)
.map(U256::from)
}
}
/// Returns a suggestion for the priority fee (the tip)
fn suggested_priority_fee(&self) -> impl Future<Output = EthResult<U256>> + Send
where
Self: 'static,
{
self.gas_oracle().suggest_tip_cap()
}
}

View File

@ -2,10 +2,10 @@
use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider};
use crate::{
servers::{EthFees, LoadBlock, LoadFee},
EthApi, EthStateCache, FeeHistoryCache, GasPriceOracle,
};
use reth_rpc_eth_api::helpers::{EthFees, LoadBlock, LoadFee};
use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasPriceOracle};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthFees for EthApi<Provider, Pool, Network, EvmConfig> where
Self: LoadFee

View File

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

View File

@ -15,11 +15,11 @@ use reth_transaction_pool::TransactionPool;
use revm::L1BlockInfo;
use revm_primitives::{BlockEnv, ExecutionResult};
use crate::{
result::internal_rpc_err,
servers::{LoadPendingBlock, LoadReceipt, SpawnBlocking},
EthApi, EthApiError, EthResult, EthStateCache, PendingBlock, ReceiptBuilder,
};
use reth_rpc_eth_api::helpers::{LoadPendingBlock, LoadReceipt, SpawnBlocking};
use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, PendingBlock, ReceiptBuilder};
use reth_rpc_server_types::result::internal_rpc_err;
use crate::EthApi;
/// L1 fee and data gas for a transaction, along with the L1 block info.
#[derive(Debug, Default, Clone)]

View File

@ -2,12 +2,11 @@
use reth_evm::ConfigureEvm;
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
use reth_rpc_eth_api::helpers::{LoadPendingBlock, SpawnBlocking};
use reth_rpc_eth_types::PendingBlock;
use reth_transaction_pool::TransactionPool;
use crate::{
servers::{LoadPendingBlock, SpawnBlocking},
EthApi, PendingBlock,
};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> LoadPendingBlock
for EthApi<Provider, Pool, Network, EvmConfig>

View File

@ -1,6 +1,9 @@
//! Builds an RPC receipt response w.r.t. data layout of network.
use crate::{servers::LoadReceipt, EthApi, EthStateCache};
use reth_rpc_eth_api::helpers::LoadReceipt;
use reth_rpc_eth_types::EthStateCache;
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> LoadReceipt for EthApi<Provider, Pool, Network, EvmConfig>
where
@ -8,6 +11,6 @@ where
{
#[inline]
fn cache(&self) -> &EthStateCache {
&self.inner.eth_cache
self.inner.cache()
}
}

View File

@ -6,15 +6,12 @@ use alloy_dyn_abi::TypedData;
use reth_primitives::{
eip191_hash_message, sign_message, Address, Signature, TransactionSigned, B256,
};
use reth_rpc_eth_api::helpers::{signer::Result, EthSigner};
use reth_rpc_eth_types::SignError;
use reth_rpc_types::TypedTransactionRequest;
use reth_rpc_types_compat::transaction::to_primitive_transaction;
use secp256k1::SecretKey;
use crate::{
servers::{helpers::traits::signer::Result, EthSigner},
SignError,
};
/// Holds developer keys
#[derive(Debug, Clone)]
pub struct DevSigner {

View File

@ -4,10 +4,11 @@ use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
use reth_primitives::{Address, U256, U64};
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
use reth_rpc_eth_api::helpers::EthApiSpec;
use reth_rpc_types::{SyncInfo, SyncStatus};
use reth_transaction_pool::TransactionPool;
use crate::{servers::EthApiSpec, EthApi};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthApiSpec for EthApi<Provider, Pool, Network, EvmConfig>
where
@ -36,7 +37,7 @@ where
}
fn accounts(&self) -> Vec<Address> {
self.inner.signers.read().iter().flat_map(|s| s.accounts()).collect()
self.inner.signers().read().iter().flat_map(|s| s.accounts()).collect()
}
fn is_syncing(&self) -> bool {
@ -50,7 +51,7 @@ where
self.provider().chain_info().map(|info| info.best_number).unwrap_or_default(),
);
SyncStatus::Info(SyncInfo {
starting_block: self.inner.starting_block,
starting_block: self.inner.starting_block(),
current_block,
highest_block: current_block,
warp_chunks_amount: None,

View File

@ -3,10 +3,10 @@
use reth_provider::StateProviderFactory;
use reth_transaction_pool::TransactionPool;
use crate::{
servers::{EthState, LoadState, SpawnBlocking},
EthApi, EthStateCache,
};
use reth_rpc_eth_api::helpers::{EthState, LoadState, SpawnBlocking};
use reth_rpc_eth_types::EthStateCache;
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthState for EthApi<Provider, Pool, Network, EvmConfig> where
Self: LoadState + SpawnBlocking
@ -43,13 +43,13 @@ mod tests {
constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, StorageKey, StorageValue, U256,
};
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider};
use reth_rpc_eth_api::helpers::EthState;
use reth_rpc_eth_types::{
EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
};
use reth_tasks::pool::BlockingTaskPool;
use reth_transaction_pool::test_utils::testing_pool;
use crate::{
servers::EthState, EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
};
use super::*;
#[tokio::test]

View File

@ -1,11 +1,9 @@
//! Contains RPC handler implementations specific to tracing.
use reth_evm::ConfigureEvm;
use reth_rpc_eth_api::helpers::{LoadState, Trace};
use crate::{
servers::{LoadState, Trace},
EthApi,
};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> Trace for EthApi<Provider, Pool, Network, EvmConfig>
where

View File

@ -1,14 +1,14 @@
//! Contains RPC handler implementations specific to transactions
use reth_provider::{BlockReaderIdExt, TransactionsProvider};
use reth_rpc_eth_api::{
helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking},
RawTransactionForwarder,
};
use reth_rpc_eth_types::EthStateCache;
use reth_transaction_pool::TransactionPool;
use crate::{
servers::{
EthSigner, EthTransactions, LoadTransaction, RawTransactionForwarder, SpawnBlocking,
},
EthApi, EthStateCache,
};
use crate::EthApi;
impl<Provider, Pool, Network, EvmConfig> EthTransactions
for EthApi<Provider, Pool, Network, EvmConfig>
@ -64,14 +64,13 @@ mod tests {
use reth_network_api::noop::NoopNetwork;
use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex, Bytes};
use reth_provider::test_utils::NoopProvider;
use reth_rpc_eth_api::helpers::EthTransactions;
use reth_rpc_eth_types::{
EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
};
use reth_tasks::pool::BlockingTaskPool;
use reth_transaction_pool::{test_utils::testing_pool, TransactionPool};
use crate::{
servers::EthTransactions, EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig,
GasPriceOracle,
};
use super::*;
#[tokio::test]

View File

@ -0,0 +1,17 @@
//! Sever implementation of `eth` namespace API.
pub mod bundle;
pub mod core;
pub mod filter;
pub mod helpers;
pub mod pubsub;
/// Implementation of `eth` namespace API.
pub use bundle::EthBundle;
pub use core::EthApi;
pub use filter::{EthFilter, EthFilterConfig};
pub use pubsub::EthPubSub;
pub use helpers::signer::DevSigner;
pub use reth_rpc_eth_api::RawTransactionForwarder;

View File

@ -9,6 +9,9 @@ use jsonrpsee::{
use reth_network_api::NetworkInfo;
use reth_primitives::{IntoRecoveredTransaction, TxHash};
use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider};
use reth_rpc_eth_api::pubsub::EthPubSubApiServer;
use reth_rpc_eth_types::logs_utils;
use reth_rpc_server_types::result::{internal_rpc_err, invalid_params_rpc_err};
use reth_rpc_types::{
pubsub::{
Params, PubSubSyncStatus, SubscriptionKind, SubscriptionResult as EthSubscriptionResult,
@ -24,12 +27,6 @@ use tokio_stream::{
Stream,
};
use crate::{
logs_utils,
result::{internal_rpc_err, invalid_params_rpc_err},
EthPubSubApiServer,
};
/// `Eth` pubsub RPC implementation.
///
/// This handles `eth_subscribe` RPC calls.

View File

@ -11,12 +11,11 @@
//! and can reduce overall performance of all concurrent requests handled via the jsonrpsee server.
//!
//! To avoid this, all blocking or CPU intensive handlers must be spawned to a separate task. See
//! the [`EthApi`](reth_rpc_eth_api::EthApi) handler implementations for examples. The rpc-api
//! traits make no use of the available jsonrpsee `blocking` attribute to give implementers more
//! freedom because the `blocking` attribute and async handlers are mutually exclusive. However, as
//! mentioned above, a lot of handlers make use of async functions, caching for example, but are
//! also using blocking disk-io, hence these calls are spawned as futures to a blocking task
//! manually.
//! the [`EthApi`] handler implementations for examples. The rpc-api traits make no use of the
//! available jsonrpsee `blocking` attribute to give implementers more freedom because the
//! `blocking` attribute and async handlers are mutually exclusive. However, as mentioned above, a
//! lot of handlers make use of async functions, caching for example, but are also using blocking
//! disk-io, hence these calls are spawned as futures to a blocking task manually.
#![doc(
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
@ -36,6 +35,7 @@ use tower as _;
mod admin;
mod debug;
mod engine;
pub mod eth;
mod net;
mod otterscan;
mod reth;
@ -46,6 +46,7 @@ mod web3;
pub use admin::AdminApi;
pub use debug::DebugApi;
pub use engine::{EngineApi, EngineEthApi};
pub use eth::{EthApi, EthBundle, EthFilter, EthPubSub};
pub use net::NetApi;
pub use otterscan::OtterscanApi;
pub use reth::RethApi;
@ -53,6 +54,3 @@ pub use rpc::RPCApi;
pub use trace::TraceApi;
pub use txpool::TxPoolApi;
pub use web3::Web3Api;
pub use reth_rpc_eth_api as eth;
pub use reth_rpc_eth_api::result;

View File

@ -2,7 +2,7 @@ use jsonrpsee::core::RpcResult as Result;
use reth_network_api::PeersInfo;
use reth_primitives::U64;
use reth_rpc_api::NetApiServer;
use reth_rpc_eth_api::servers::EthApiSpec;
use reth_rpc_eth_api::helpers::EthApiSpec;
use reth_rpc_types::PeerCount;
/// `Net` API implementation.

View File

@ -3,7 +3,8 @@ use async_trait::async_trait;
use jsonrpsee::core::RpcResult;
use reth_primitives::{Address, BlockId, BlockNumberOrTag, TxHash, B256};
use reth_rpc_api::{EthApiServer, OtterscanServer};
use reth_rpc_eth_api::{result::internal_rpc_err, servers::TraceExt};
use reth_rpc_eth_api::helpers::TraceExt;
use reth_rpc_server_types::result::internal_rpc_err;
use reth_rpc_types::{
trace::otterscan::{
BlockDetails, ContractCreator, InternalOperation, OperationType, OtsBlockTransactions,

View File

@ -6,7 +6,7 @@ use reth_errors::RethResult;
use reth_primitives::{Address, BlockId, U256};
use reth_provider::{BlockReaderIdExt, ChangeSetReader, StateProviderFactory};
use reth_rpc_api::RethApiServer;
use reth_rpc_eth_api::{EthApiError, EthResult};
use reth_rpc_eth_types::{EthApiError, EthResult};
use reth_tasks::TaskSpawner;
use tokio::sync::oneshot;

View File

@ -9,10 +9,10 @@ use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, Bytes, Header,
use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_api::TraceApiServer;
use reth_rpc_eth_api::{
use reth_rpc_eth_api::helpers::TraceExt;
use reth_rpc_eth_types::{
error::{EthApiError, EthResult},
revm_utils::prepare_call_env,
servers::TraceExt,
utils::recover_raw_transaction,
};
use reth_rpc_types::{

View File

@ -3,8 +3,7 @@ use jsonrpsee::core::RpcResult;
use reth_network_api::NetworkInfo;
use reth_primitives::{keccak256, Bytes, B256};
use reth_rpc_api::Web3ApiServer;
use crate::result::ToRpcResult;
use reth_rpc_server_types::ToRpcResult;
/// `web3` API implementation.
///

View File

@ -3,18 +3,19 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
use std::sync::Arc;
use futures_util::StreamExt;
use reth::{
builder::{NodeBuilder, NodeHandle},
providers::CanonStateSubscriptions,
rpc::eth::servers::EthTransactions,
rpc::api::eth::helpers::EthTransactions,
tasks::TaskManager,
};
use reth_chainspec::ChainSpec;
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
use reth_node_ethereum::EthereumNode;
use reth_primitives::{b256, hex, Genesis};
use std::sync::Arc;
#[tokio::main]
async fn main() -> eyre::Result<()> {

View File

@ -21,7 +21,7 @@ use reth::{
interpreter::{Interpreter, OpCode},
Database, Evm, EvmContext, Inspector,
},
rpc::{compat::transaction::transaction_to_call_request, eth::servers::Call},
rpc::{api::eth::helpers::Call, compat::transaction::transaction_to_call_request},
transaction_pool::TransactionPool,
};
use reth_node_ethereum::node::EthereumNode;

View File

@ -3,7 +3,7 @@ use reth::{primitives::Block, providers::BlockReaderIdExt};
// Rpc related imports
use jsonrpsee::proc_macros::rpc;
use reth::rpc::eth::error::EthResult;
use reth::rpc::server_types::eth::EthResult;
/// trait interface for a custom rpc namespace: `MyRpc`
///