From 1b9f5871f551613f61ebd988c73e2ea5380ac31f Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 27 Jun 2024 14:34:17 +0200 Subject: [PATCH] chore(rpc): move impl of eth api server out of `reth-rpc-eth-api` (#9135) Co-authored-by: Matthias Seitz --- Cargo.lock | 63 +- Cargo.toml | 3 + bin/reth/Cargo.toml | 3 + bin/reth/src/lib.rs | 13 +- crates/e2e-test-utils/src/rpc.rs | 9 +- crates/ethereum/node/tests/e2e/dev.rs | 8 +- crates/node-core/Cargo.toml | 2 + crates/node-core/src/args/gas_price_oracle.rs | 2 +- crates/node-core/src/args/rpc_server.rs | 22 +- crates/node-core/src/lib.rs | 2 +- crates/optimism/node/Cargo.toml | 8 +- crates/optimism/node/src/rpc.rs | 19 +- crates/rpc/rpc-api/src/lib.rs | 2 +- crates/rpc/rpc-builder/Cargo.toml | 1 + crates/rpc/rpc-builder/src/auth.rs | 7 +- crates/rpc/rpc-builder/src/config.rs | 10 +- crates/rpc/rpc-builder/src/eth.rs | 13 +- crates/rpc/rpc-builder/src/lib.rs | 10 +- crates/rpc/rpc-eth-api/Cargo.toml | 29 +- crates/rpc/rpc-eth-api/src/api/mod.rs | 318 -------- crates/rpc/rpc-eth-api/src/api/servers/mod.rs | 323 -------- .../rpc/rpc-eth-api/src/api/servers/server.rs | 715 ----------------- .../rpc/rpc-eth-api/src/{api => }/bundle.rs | 0 crates/rpc/rpc-eth-api/src/core.rs | 727 ++++++++++++++++++ .../rpc/rpc-eth-api/src/{api => }/filter.rs | 0 .../helpers/traits => helpers}/block.rs | 20 +- .../rpc-eth-api/src/helpers/blocking_task.rs | 54 ++ .../helpers/traits => helpers}/call.rs | 22 +- .../servers/helpers/traits => helpers}/fee.rs | 10 +- .../servers/helpers/traits => helpers}/mod.rs | 30 +- .../traits => helpers}/pending_block.rs | 10 +- .../helpers/traits => helpers}/receipt.rs | 3 +- .../helpers/traits => helpers}/signer.rs | 3 +- .../helpers/traits => helpers}/spec.rs | 0 .../helpers/traits => helpers}/state.rs | 8 +- .../helpers/traits => helpers}/trace.rs | 10 +- .../helpers/traits => helpers}/transaction.rs | 15 +- crates/rpc/rpc-eth-api/src/lib.rs | 63 +- .../rpc/rpc-eth-api/src/{api => }/pubsub.rs | 0 crates/rpc/rpc-eth-types/Cargo.toml | 68 ++ .../src/cache/config.rs | 8 +- .../src/cache/db.rs | 2 +- .../src/cache/metrics.rs | 0 .../src/cache/mod.rs | 4 +- .../src/cache/multi_consumer.rs | 6 +- .../src/error.rs | 27 +- .../src/fee_history.rs | 7 +- .../src/gas_oracle.rs | 41 +- .../src/id_provider.rs | 8 +- crates/rpc/rpc-eth-types/src/lib.rs | 34 + .../src/logs_utils.rs | 64 +- .../src/pending_block.rs | 4 +- .../src/receipt.rs | 2 +- .../src/revm_utils.rs | 2 +- .../src/transaction.rs | 2 +- .../src/utils.rs | 2 +- crates/rpc/rpc-server-types/Cargo.toml | 11 + crates/rpc/rpc-server-types/src/constants.rs | 14 + crates/rpc/rpc-server-types/src/lib.rs | 3 + .../src/result.rs | 34 +- crates/rpc/rpc-types/Cargo.toml | 8 +- crates/rpc/rpc/Cargo.toml | 17 + crates/rpc/rpc/src/admin.rs | 3 +- crates/rpc/rpc/src/debug.rs | 9 +- .../src/api/servers => rpc/src/eth}/bundle.rs | 10 +- crates/rpc/rpc/src/eth/core.rs | 601 +++++++++++++++ .../src/api/servers => rpc/src/eth}/filter.rs | 62 +- .../servers => rpc/src/eth}/helpers/block.rs | 7 +- .../src/eth/helpers}/blocking_task.rs | 0 .../servers => rpc/src/eth}/helpers/call.rs | 6 +- crates/rpc/rpc/src/eth/helpers/fee.rs | 346 +++++++++ .../servers => rpc/src/eth}/helpers/fees.rs | 8 +- .../servers => rpc/src/eth}/helpers/mod.rs | 1 - .../src/eth}/helpers/optimism.rs | 10 +- .../src/eth}/helpers/pending_block.rs | 7 +- .../src/eth}/helpers/receipt.rs | 7 +- .../servers => rpc/src/eth}/helpers/signer.rs | 7 +- .../servers => rpc/src/eth}/helpers/spec.rs | 7 +- .../servers => rpc/src/eth}/helpers/state.rs | 16 +- .../servers => rpc/src/eth}/helpers/trace.rs | 6 +- .../src/eth}/helpers/transaction.rs | 21 +- crates/rpc/rpc/src/eth/mod.rs | 17 + .../src/api/servers => rpc/src/eth}/pubsub.rs | 9 +- crates/rpc/rpc/src/lib.rs | 16 +- crates/rpc/rpc/src/net.rs | 2 +- crates/rpc/rpc/src/otterscan.rs | 3 +- crates/rpc/rpc/src/reth.rs | 2 +- crates/rpc/rpc/src/trace.rs | 4 +- crates/rpc/rpc/src/web3.rs | 3 +- examples/custom-dev-node/src/main.rs | 5 +- examples/custom-inspector/src/main.rs | 2 +- examples/rpc-db/src/myrpc_ext.rs | 2 +- 92 files changed, 2326 insertions(+), 1798 deletions(-) delete mode 100644 crates/rpc/rpc-eth-api/src/api/mod.rs delete mode 100644 crates/rpc/rpc-eth-api/src/api/servers/mod.rs delete mode 100644 crates/rpc/rpc-eth-api/src/api/servers/server.rs rename crates/rpc/rpc-eth-api/src/{api => }/bundle.rs (100%) create mode 100644 crates/rpc/rpc-eth-api/src/core.rs rename crates/rpc/rpc-eth-api/src/{api => }/filter.rs (100%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/block.rs (94%) create mode 100644 crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/call.rs (99%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/fee.rs (98%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/mod.rs (55%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/pending_block.rs (99%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/receipt.rs (94%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/signer.rs (97%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/spec.rs (100%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/state.rs (99%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/trace.rs (98%) rename crates/rpc/rpc-eth-api/src/{api/servers/helpers/traits => helpers}/transaction.rs (99%) rename crates/rpc/rpc-eth-api/src/{api => }/pubsub.rs (100%) create mode 100644 crates/rpc/rpc-eth-types/Cargo.toml rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/cache/config.rs (80%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/cache/db.rs (99%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/cache/metrics.rs (100%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/cache/mod.rs (99%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/cache/multi_consumer.rs (99%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/error.rs (97%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/fee_history.rs (99%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/gas_oracle.rs (90%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/id_provider.rs (86%) create mode 100644 crates/rpc/rpc-eth-types/src/lib.rs rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/logs_utils.rs (79%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/pending_block.rs (97%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/receipt.rs (99%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/revm_utils.rs (99%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/transaction.rs (97%) rename crates/rpc/{rpc-eth-api => rpc-eth-types}/src/utils.rs (95%) rename crates/rpc/{rpc-eth-api => rpc-server-types}/src/result.rs (80%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/bundle.rs (97%) create mode 100644 crates/rpc/rpc/src/eth/core.rs rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/filter.rs (93%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/block.rs (83%) rename crates/rpc/{rpc-eth-api/src/api/servers/helpers/traits => rpc/src/eth/helpers}/blocking_task.rs (100%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/call.rs (84%) create mode 100644 crates/rpc/rpc/src/eth/helpers/fee.rs rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/fees.rs (85%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/mod.rs (95%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/optimism.rs (96%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/pending_block.rs (89%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/receipt.rs (66%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/signer.rs (98%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/spec.rs (90%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/state.rs (92%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/trace.rs (83%) rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/helpers/transaction.rs (94%) create mode 100644 crates/rpc/rpc/src/eth/mod.rs rename crates/rpc/{rpc-eth-api/src/api/servers => rpc/src/eth}/pubsub.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 4c2408d2a..326850d6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] diff --git a/Cargo.toml b/Cargo.toml index 441b69b2a..32360341f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 88506f563..65c7c4f59 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -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 diff --git a/bin/reth/src/lib.rs b/bin/reth/src/lib.rs index 35cd1357a..c725b033b 100644 --- a/bin/reth/src/lib.rs +++ b/bin/reth/src/lib.rs @@ -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::*; } diff --git a/crates/e2e-test-utils/src/rpc.rs b/crates/e2e-test-utils/src/rpc.rs index 0c55e9c23..b05d5df89 100644 --- a/crates/e2e-test-utils/src/rpc.rs +++ b/crates/e2e-test-utils/src/rpc.rs @@ -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 { pub inner: RpcRegistry, diff --git a/crates/ethereum/node/tests/e2e/dev.rs b/crates/ethereum/node/tests/e2e/dev.rs index 4a95231d4..2b20d781f 100644 --- a/crates/ethereum/node/tests/e2e/dev.rs +++ b/crates/ethereum/node/tests/e2e/dev.rs @@ -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<()> { diff --git a/crates/node-core/Cargo.toml b/crates/node-core/Cargo.toml index 259cfcdb5..ec86bb440 100644 --- a/crates/node-core/Cargo.toml +++ b/crates/node-core/Cargo.toml @@ -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"] diff --git a/crates/node-core/src/args/gas_price_oracle.rs b/crates/node-core/src/args/gas_price_oracle.rs index c719e9c8a..abdd8e142 100644 --- a/crates/node-core/src/args/gas_price_oracle.rs +++ b/crates/node-core/src/args/gas_price_oracle.rs @@ -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, diff --git a/crates/node-core/src/args/rpc_server.rs b/crates/node-core/src/args/rpc_server.rs index 62c675d50..bad1e2421 100644 --- a/crates/node-core/src/args/rpc_server.rs +++ b/crates/node-core/src/args/rpc_server.rs @@ -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::::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(), } diff --git a/crates/node-core/src/lib.rs b/crates/node-core/src/lib.rs index 8fbc0b2f9..27a81cc26 100644 --- a/crates/node-core/src/lib.rs +++ b/crates/node-core/src/lib.rs @@ -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`. diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index f85e7baf6..5d172ec93 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -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" ] diff --git a/crates/optimism/node/src/rpc.rs b/crates/optimism/node/src/rpc.rs index 01cb08c26..d7c3f49ef 100644 --- a/crates/optimism/node/src/rpc.rs +++ b/crates/optimism/node/src/rpc.rs @@ -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::, - ) + ErrorObject::owned(INTERNAL_ERROR_CODE, self.to_string(), None::) } } diff --git a/crates/rpc/rpc-api/src/lib.rs b/crates/rpc/rpc-api/src/lib.rs index 661b7780e..cb84f8388 100644 --- a/crates/rpc/rpc-api/src/lib.rs +++ b/crates/rpc/rpc-api/src/lib.rs @@ -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, }; } diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index 46105030c..9108525d0 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -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 diff --git a/crates/rpc/rpc-builder/src/auth.rs b/crates/rpc/rpc-builder/src/auth.rs index 30d5f3389..952362e0c 100644 --- a/crates/rpc/rpc-builder/src/auth.rs +++ b/crates/rpc/rpc-builder/src/auth.rs @@ -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; diff --git a/crates/rpc/rpc-builder/src/config.rs b/crates/rpc/rpc-builder/src/config.rs index 89ce742e3..fbace8ec7 100644 --- a/crates/rpc/rpc-builder/src/config.rs +++ b/crates/rpc/rpc-builder/src/config.rs @@ -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; diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 62e857e02..7d177ed43 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -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(), } diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 883409331..2800e83d1 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -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(&mut self, f: F) -> R where F: FnOnce(&EthHandlers) -> R, diff --git a/crates/rpc/rpc-eth-api/Cargo.toml b/crates/rpc/rpc-eth-api/Cargo.toml index 88d3efd5f..fb8d84b3f 100644 --- a/crates/rpc/rpc-eth-api/Cargo.toml +++ b/crates/rpc/rpc-eth-api/Cargo.toml @@ -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" ] \ No newline at end of file diff --git a/crates/rpc/rpc-eth-api/src/api/mod.rs b/crates/rpc/rpc-eth-api/src/api/mod.rs deleted file mode 100644 index 63e61254a..000000000 --- a/crates/rpc/rpc-eth-api/src/api/mod.rs +++ /dev/null @@ -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: -#[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; - - /// Returns an object with data about the sync status or false. - #[method(name = "syncing")] - fn syncing(&self) -> RpcResult; - - /// Returns the client coinbase address. - #[method(name = "coinbase")] - async fn author(&self) -> RpcResult
; - - /// Returns a list of addresses owned by client. - #[method(name = "accounts")] - fn accounts(&self) -> RpcResult>; - - /// Returns the number of most recent block. - #[method(name = "blockNumber")] - fn block_number(&self) -> RpcResult; - - /// Returns the chain ID of the current network. - #[method(name = "chainId")] - async fn chain_id(&self) -> RpcResult>; - - /// Returns information about a block by hash. - #[method(name = "getBlockByHash")] - async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult>; - - /// Returns information about a block by number. - #[method(name = "getBlockByNumber")] - async fn block_by_number( - &self, - number: BlockNumberOrTag, - full: bool, - ) -> RpcResult>; - - /// 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>; - - /// 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>; - - /// 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>; - - /// 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>; - - /// Returns all transaction receipts for a given block. - #[method(name = "getBlockReceipts")] - async fn block_receipts( - &self, - block_id: BlockId, - ) -> RpcResult>>; - - /// 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>; - - /// 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>; - - /// 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>; - - /// Returns the information about a transaction requested by transaction hash. - #[method(name = "getTransactionByHash")] - async fn transaction_by_hash(&self, hash: B256) -> RpcResult>; - - /// 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>; - - /// 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>; - - /// 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>; - - /// 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>; - - /// Returns the receipt of a transaction by transaction hash. - #[method(name = "getTransactionReceipt")] - async fn transaction_receipt(&self, hash: B256) -> RpcResult>; - - /// Returns the balance of the account of given address. - #[method(name = "getBalance")] - async fn balance(&self, address: Address, block_number: Option) -> RpcResult; - - /// 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, - ) -> RpcResult; - - /// 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, - ) -> RpcResult; - - /// Returns code at a given address at given block number. - #[method(name = "getCode")] - async fn get_code(&self, address: Address, block_number: Option) -> RpcResult; - - /// Returns the block's header at given number. - #[method(name = "getHeaderByNumber")] - async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult>; - - /// Returns the block's header at given hash. - #[method(name = "getHeaderByHash")] - async fn header_by_hash(&self, hash: B256) -> RpcResult>; - - /// 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, - state_overrides: Option, - block_overrides: Option>, - ) -> RpcResult; - - /// 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, - state_override: Option, - ) -> RpcResult>; - - /// 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, - ) -> RpcResult; - - /// 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, - state_override: Option, - ) -> RpcResult; - - /// Returns the current price per gas in wei. - #[method(name = "gasPrice")] - async fn gas_price(&self) -> RpcResult; - - /// 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; - - /// Introduced in EIP-4844, returns the current blob base fee in wei. - #[method(name = "blobBaseFee")] - async fn blob_base_fee(&self) -> RpcResult; - - /// 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>, - ) -> RpcResult; - - /// Returns whether the client is actively mining new blocks. - #[method(name = "mining")] - async fn is_mining(&self) -> RpcResult; - - /// Returns the number of hashes per second that the node is mining with. - #[method(name = "hashrate")] - async fn hashrate(&self) -> RpcResult; - - /// 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; - - /// 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; - - /// 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; - - /// Sends transaction; will block waiting for signer to return the - /// transaction hash. - #[method(name = "sendTransaction")] - async fn send_transaction(&self, request: TransactionRequest) -> RpcResult; - - /// Sends signed transaction, returning its hash. - #[method(name = "sendRawTransaction")] - async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult; - - /// 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; - - /// 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; - - /// 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; - - /// 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, - block_number: Option, - ) -> RpcResult; -} diff --git a/crates/rpc/rpc-eth-api/src/api/servers/mod.rs b/crates/rpc/rpc-eth-api/src/api/servers/mod.rs deleted file mode 100644 index 5be35304a..000000000 --- a/crates/rpc/rpc-eth-api/src/api/servers/mod.rs +++ /dev/null @@ -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 { - /// All nested fields bundled together. - inner: Arc>, -} - -impl EthApi { - /// 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) { - self.inner.raw_transaction_forwarder.write().replace(forwarder); - } -} - -impl EthApi -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, - gas_cap: impl Into, - blocking_task_pool: BlockingTaskPool, - fee_history_cache: FeeHistoryCache, - evm_config: EvmConfig, - raw_transaction_forwarder: Option>, - ) -> Self { - Self::with_spawner( - provider, - pool, - network, - eth_cache, - gas_oracle, - gas_cap.into().into(), - Box::::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, - gas_cap: u64, - task_spawner: Box, - blocking_task_pool: BlockingTaskPool, - fee_history_cache: FeeHistoryCache, - evm_config: EvmConfig, - raw_transaction_forwarder: Option>, - ) -> 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 { - &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 std::fmt::Debug - for EthApi -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("EthApi").finish_non_exhaustive() - } -} - -impl Clone for EthApi { - 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 $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); - -impl EthApi { - /// 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 { - /// 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>>, - /// The async cache frontend for eth related data - eth_cache: EthStateCache, - /// The async gas oracle frontend for gas price suggestions - gas_oracle: GasPriceOracle, - /// 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, - /// Cached pending block if any - pending_block: Mutex>, - /// 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>>, -} - -impl EthApiInner { - /// 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> { - &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> { - 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 { - &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>> { - &self.signers - } -} diff --git a/crates/rpc/rpc-eth-api/src/api/servers/server.rs b/crates/rpc/rpc-eth-api/src/api/servers/server.rs deleted file mode 100644 index 0701ff70d..000000000 --- a/crates/rpc/rpc-eth-api/src/api/servers/server.rs +++ /dev/null @@ -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 EthApiServer for T -where - Self: EthApiSpec - + EthTransactions - + EthBlocks - + EthState - + EthCall - + EthFees - + Trace - + LoadReceipt, -{ - /// Handler for: `eth_protocolVersion` - async fn protocol_version(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_protocolVersion"); - EthApiSpec::protocol_version(self).await.to_rpc_result() - } - - /// Handler for: `eth_syncing` - fn syncing(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_syncing"); - EthApiSpec::sync_status(self).to_rpc_result() - } - - /// Handler for: `eth_coinbase` - async fn author(&self) -> Result
{ - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_accounts` - fn accounts(&self) -> Result> { - trace!(target: "rpc::eth", "Serving eth_accounts"); - Ok(EthApiSpec::accounts(self)) - } - - /// Handler for: `eth_blockNumber` - fn block_number(&self) -> Result { - 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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>> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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> { - 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) -> Result { - 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, - ) -> Result { - 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, - ) -> Result { - 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) -> Result { - 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> { - 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> { - 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, - state_overrides: Option, - block_overrides: Option>, - ) -> Result { - 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, - state_override: Option, - ) -> Result> { - 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, - ) -> Result { - 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, - state_override: Option, - ) -> Result { - 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 { - 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 { - 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 { - 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>, - ) -> Result { - 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 { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_hashrate` - async fn hashrate(&self) -> Result { - Ok(U256::ZERO) - } - - /// Handler for: `eth_getWork` - async fn get_work(&self) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_submitHashrate` - async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> Result { - Ok(false) - } - - /// Handler for: `eth_submitWork` - async fn submit_work(&self, _nonce: B64, _pow_hash: B256, _mix_digest: B256) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_sendTransaction` - async fn send_transaction(&self, request: TransactionRequest) -> Result { - 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 { - 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 { - 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 { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_signTypedData` - async fn sign_typed_data(&self, address: Address, data: TypedData) -> Result { - 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, - block_number: Option, - ) -> Result { - 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 { - 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, - block_count: u64, - mock_provider: MockEthProvider, - ) -> (EthApi, Vec, Vec) { - 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 = rng.gen::().then(|| rng.gen::() 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 = 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 = as EthApiServer>::fee_history( - ð_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 = as EthApiServer>::fee_history( - ð_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 = as EthApiServer>::fee_history( - ð_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" - ); - } -} diff --git a/crates/rpc/rpc-eth-api/src/api/bundle.rs b/crates/rpc/rpc-eth-api/src/bundle.rs similarity index 100% rename from crates/rpc/rpc-eth-api/src/api/bundle.rs rename to crates/rpc/rpc-eth-api/src/bundle.rs diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs new file mode 100644 index 000000000..834682670 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -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: +#[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; + + /// Returns an object with data about the sync status or false. + #[method(name = "syncing")] + fn syncing(&self) -> RpcResult; + + /// Returns the client coinbase address. + #[method(name = "coinbase")] + async fn author(&self) -> RpcResult
; + + /// Returns a list of addresses owned by client. + #[method(name = "accounts")] + fn accounts(&self) -> RpcResult>; + + /// Returns the number of most recent block. + #[method(name = "blockNumber")] + fn block_number(&self) -> RpcResult; + + /// Returns the chain ID of the current network. + #[method(name = "chainId")] + async fn chain_id(&self) -> RpcResult>; + + /// Returns information about a block by hash. + #[method(name = "getBlockByHash")] + async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult>; + + /// Returns information about a block by number. + #[method(name = "getBlockByNumber")] + async fn block_by_number( + &self, + number: BlockNumberOrTag, + full: bool, + ) -> RpcResult>; + + /// 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>; + + /// 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>; + + /// 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>; + + /// 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>; + + /// Returns all transaction receipts for a given block. + #[method(name = "getBlockReceipts")] + async fn block_receipts( + &self, + block_id: BlockId, + ) -> RpcResult>>; + + /// 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>; + + /// 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>; + + /// 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>; + + /// Returns the information about a transaction requested by transaction hash. + #[method(name = "getTransactionByHash")] + async fn transaction_by_hash(&self, hash: B256) -> RpcResult>; + + /// 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>; + + /// 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>; + + /// 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>; + + /// 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>; + + /// Returns the receipt of a transaction by transaction hash. + #[method(name = "getTransactionReceipt")] + async fn transaction_receipt(&self, hash: B256) -> RpcResult>; + + /// Returns the balance of the account of given address. + #[method(name = "getBalance")] + async fn balance(&self, address: Address, block_number: Option) -> RpcResult; + + /// 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, + ) -> RpcResult; + + /// 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, + ) -> RpcResult; + + /// Returns code at a given address at given block number. + #[method(name = "getCode")] + async fn get_code(&self, address: Address, block_number: Option) -> RpcResult; + + /// Returns the block's header at given number. + #[method(name = "getHeaderByNumber")] + async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult>; + + /// Returns the block's header at given hash. + #[method(name = "getHeaderByHash")] + async fn header_by_hash(&self, hash: B256) -> RpcResult>; + + /// 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, + state_overrides: Option, + block_overrides: Option>, + ) -> RpcResult; + + /// 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, + state_override: Option, + ) -> RpcResult>; + + /// 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, + ) -> RpcResult; + + /// 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, + state_override: Option, + ) -> RpcResult; + + /// Returns the current price per gas in wei. + #[method(name = "gasPrice")] + async fn gas_price(&self) -> RpcResult; + + /// 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; + + /// Introduced in EIP-4844, returns the current blob base fee in wei. + #[method(name = "blobBaseFee")] + async fn blob_base_fee(&self) -> RpcResult; + + /// 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>, + ) -> RpcResult; + + /// Returns whether the client is actively mining new blocks. + #[method(name = "mining")] + async fn is_mining(&self) -> RpcResult; + + /// Returns the number of hashes per second that the node is mining with. + #[method(name = "hashrate")] + async fn hashrate(&self) -> RpcResult; + + /// 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; + + /// 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; + + /// 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; + + /// Sends transaction; will block waiting for signer to return the + /// transaction hash. + #[method(name = "sendTransaction")] + async fn send_transaction(&self, request: TransactionRequest) -> RpcResult; + + /// Sends signed transaction, returning its hash. + #[method(name = "sendRawTransaction")] + async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult; + + /// 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; + + /// 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; + + /// 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; + + /// 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, + block_number: Option, + ) -> RpcResult; +} + +#[async_trait::async_trait] +impl EthApiServer for T +where + Self: EthApiSpec + + EthTransactions + + EthBlocks + + EthState + + EthCall + + EthFees + + Trace + + LoadReceipt, +{ + /// Handler for: `eth_protocolVersion` + async fn protocol_version(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_protocolVersion"); + EthApiSpec::protocol_version(self).await.to_rpc_result() + } + + /// Handler for: `eth_syncing` + fn syncing(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_syncing"); + EthApiSpec::sync_status(self).to_rpc_result() + } + + /// Handler for: `eth_coinbase` + async fn author(&self) -> RpcResult
{ + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_accounts` + fn accounts(&self) -> RpcResult> { + trace!(target: "rpc::eth", "Serving eth_accounts"); + Ok(EthApiSpec::accounts(self)) + } + + /// Handler for: `eth_blockNumber` + fn block_number(&self) -> RpcResult { + 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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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>> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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> { + 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) -> RpcResult { + 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, + ) -> RpcResult { + 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, + ) -> RpcResult { + 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) -> RpcResult { + 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> { + 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> { + 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, + state_overrides: Option, + block_overrides: Option>, + ) -> RpcResult { + 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, + state_override: Option, + ) -> RpcResult> { + 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, + ) -> RpcResult { + 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, + state_override: Option, + ) -> RpcResult { + 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 { + 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 { + 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 { + 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>, + ) -> RpcResult { + 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 { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_hashrate` + async fn hashrate(&self) -> RpcResult { + Ok(U256::ZERO) + } + + /// Handler for: `eth_getWork` + async fn get_work(&self) -> RpcResult { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_submitHashrate` + async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> RpcResult { + Ok(false) + } + + /// Handler for: `eth_submitWork` + async fn submit_work( + &self, + _nonce: B64, + _pow_hash: B256, + _mix_digest: B256, + ) -> RpcResult { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_sendTransaction` + async fn send_transaction(&self, request: TransactionRequest) -> RpcResult { + 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 { + 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 { + 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 { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_signTypedData` + async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult { + 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, + block_number: Option, + ) -> RpcResult { + 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(), + })?) + } +} diff --git a/crates/rpc/rpc-eth-api/src/api/filter.rs b/crates/rpc/rpc-eth-api/src/filter.rs similarity index 100% rename from crates/rpc/rpc-eth-api/src/api/filter.rs rename to crates/rpc/rpc-eth-api/src/filter.rs diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs similarity index 94% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/block.rs rename to crates/rpc/rpc-eth-api/src/helpers/block.rs index 804069f6e..78f1ef9da 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -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, + block_id: BlockId, ) -> impl Future>> + 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, - ) -> EthResult>> { - let block_id = block_id.into(); + fn ommers(&self, block_id: BlockId) -> EthResult>> { 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, + block_id: BlockId, index: Index, ) -> impl Future>> + 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 diff --git a/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs b/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs new file mode 100644 index 000000000..c199d4de6 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs @@ -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(&self, f: F) -> impl Future> + Send + where + F: FnOnce(Self) -> EthResult + 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 + /// . + fn spawn_tracing(&self, f: F) -> impl Future> + Send + where + F: FnOnce(Self) -> EthResult + 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)? } + } +} diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/call.rs rename to crates/rpc/rpc-eth-api/src/helpers/call.rs index ee531b7f9..888b73994 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -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. diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/fee.rs b/crates/rpc/rpc-eth-api/src/helpers/fee.rs similarity index 98% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/fee.rs rename to crates/rpc/rpc-eth-api/src/helpers/fee.rs index 9217b7d5f..54c577ea2 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/fee.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/fee.rs @@ -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. diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs similarity index 55% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/mod.rs rename to crates/rpc/rpc-eth-api/src/helpers/mod.rs index c714a166d..321e9b03e 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/mod.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -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: diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/pending_block.rs rename to crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index f167a82fe..c7036f4be 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -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. /// diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/receipt.rs b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs similarity index 94% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/receipt.rs rename to crates/rpc/rpc-eth-api/src/helpers/receipt.rs index 83c4b9d03..5cd6c03c4 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/receipt.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs @@ -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. diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/signer.rs b/crates/rpc/rpc-eth-api/src/helpers/signer.rs similarity index 97% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/signer.rs rename to crates/rpc/rpc-eth-api/src/helpers/signer.rs index 637708eb7..2a75d9abb 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/signer.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/signer.rs @@ -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 = result::Result; diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/spec.rs b/crates/rpc/rpc-eth-api/src/helpers/spec.rs similarity index 100% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/spec.rs rename to crates/rpc/rpc-eth-api/src/helpers/spec.rs diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/state.rs rename to crates/rpc/rpc-eth-api/src/helpers/state.rs index 220a33e91..80859b929 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -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 { diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs similarity index 98% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/trace.rs rename to crates/rpc/rpc-eth-api/src/helpers/trace.rs index a1eedf5dc..63b210204 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -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 { diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/transaction.rs rename to crates/rpc/rpc-eth-api/src/helpers/transaction.rs index 5c87de1d5..acf0156c6 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -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. diff --git a/crates/rpc/rpc-eth-api/src/lib.rs b/crates/rpc/rpc-eth-api/src/lib.rs index 51cf5dafc..922c6ed77 100644 --- a/crates/rpc/rpc-eth-api/src/lib.rs +++ b/crates/rpc/rpc-eth-api/src/lib.rs @@ -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; diff --git a/crates/rpc/rpc-eth-api/src/api/pubsub.rs b/crates/rpc/rpc-eth-api/src/pubsub.rs similarity index 100% rename from crates/rpc/rpc-eth-api/src/api/pubsub.rs rename to crates/rpc/rpc-eth-api/src/pubsub.rs diff --git a/crates/rpc/rpc-eth-types/Cargo.toml b/crates/rpc/rpc-eth-types/Cargo.toml new file mode 100644 index 000000000..b1c307191 --- /dev/null +++ b/crates/rpc/rpc-eth-types/Cargo.toml @@ -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" +] \ No newline at end of file diff --git a/crates/rpc/rpc-eth-api/src/cache/config.rs b/crates/rpc/rpc-eth-types/src/cache/config.rs similarity index 80% rename from crates/rpc/rpc-eth-api/src/cache/config.rs rename to crates/rpc/rpc-eth-types/src/cache/config.rs index 93207c930..c2d379652 100644 --- a/crates/rpc/rpc-eth-api/src/cache/config.rs +++ b/crates/rpc/rpc-eth-types/src/cache/config.rs @@ -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 { diff --git a/crates/rpc/rpc-eth-api/src/cache/db.rs b/crates/rpc/rpc-eth-types/src/cache/db.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/cache/db.rs rename to crates/rpc/rpc-eth-types/src/cache/db.rs index 74b20defb..47af8e85d 100644 --- a/crates/rpc/rpc-eth-api/src/cache/db.rs +++ b/crates/rpc/rpc-eth-types/src/cache/db.rs @@ -1,6 +1,6 @@ //! Helper types to workaround 'higher-ranked lifetime error' //! in default implementation of -//! [`Call`](crate::servers::Call). +//! `reth_rpc_eth_api::helpers::Call`. use reth_primitives::{B256, U256}; use reth_provider::StateProvider; diff --git a/crates/rpc/rpc-eth-api/src/cache/metrics.rs b/crates/rpc/rpc-eth-types/src/cache/metrics.rs similarity index 100% rename from crates/rpc/rpc-eth-api/src/cache/metrics.rs rename to crates/rpc/rpc-eth-types/src/cache/metrics.rs diff --git a/crates/rpc/rpc-eth-api/src/cache/mod.rs b/crates/rpc/rpc-eth-types/src/cache/mod.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/cache/mod.rs rename to crates/rpc/rpc-eth-types/src/cache/mod.rs index 92e96806b..cda3d7258 100644 --- a/crates/rpc/rpc-eth-api/src/cache/mod.rs +++ b/crates/rpc/rpc-eth-types/src/cache/mod.rs @@ -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< diff --git a/crates/rpc/rpc-eth-api/src/cache/multi_consumer.rs b/crates/rpc/rpc-eth-types/src/cache/multi_consumer.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/cache/multi_consumer.rs rename to crates/rpc/rpc-eth-types/src/cache/multi_consumer.rs index b63795b59..77d861343 100644 --- a/crates/rpc/rpc-eth-api/src/cache/multi_consumer.rs +++ b/crates/rpc/rpc-eth-types/src/cache/multi_consumer.rs @@ -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 where diff --git a/crates/rpc/rpc-eth-api/src/error.rs b/crates/rpc/rpc-eth-types/src/error.rs similarity index 97% rename from crates/rpc/rpc-eth-api/src/error.rs rename to crates/rpc/rpc-eth-types/src/error.rs index 84c150401..4ddbf9a38 100644 --- a/crates/rpc/rpc-eth-api/src/error.rs +++ b/crates/rpc/rpc-eth-types/src/error.rs @@ -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 = Result; @@ -134,7 +136,7 @@ impl EthApiError { } } -impl From for ErrorObject<'static> { +impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(error: EthApiError) -> Self { match error { EthApiError::FailedToDecodeSignedTransaction | @@ -165,9 +167,10 @@ impl From 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 for ErrorObject<'static> { +impl From 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), } -impl From for ErrorObject<'static> { +impl From 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 { +pub fn ensure_success(result: ExecutionResult) -> EthResult { match result { ExecutionResult::Success { output, .. } => Ok(output.into_data()), ExecutionResult::Revert { output, .. } => { diff --git a/crates/rpc/rpc-eth-api/src/fee_history.rs b/crates/rpc/rpc-eth-types/src/fee_history.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/fee_history.rs rename to crates/rpc/rpc-eth-types/src/fee_history.rs index 10c06eab0..6f84511aa 100644 --- a/crates/rpc/rpc-eth-api/src/fee_history.rs +++ b/crates/rpc/rpc-eth-types/src/fee_history.rs @@ -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( /// 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, diff --git a/crates/rpc/rpc-eth-api/src/gas_oracle.rs b/crates/rpc/rpc-eth-types/src/gas_oracle.rs similarity index 90% rename from crates/rpc/rpc-eth-api/src/gas_oracle.rs rename to crates/rpc/rpc-eth-types/src/gas_oracle.rs index 3cc55eb2b..4993c5d78 100644 --- a/crates/rpc/rpc-eth-api/src/gas_oracle.rs +++ b/crates/rpc/rpc-eth-types/src/gas_oracle.rs @@ -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 -/// -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 for GasCap { - fn from(gas_cap: u64) -> Self { - Self(gas_cap) - } -} - -impl From for u64 { - fn from(gas_cap: GasCap) -> Self { - gas_cap.0 - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc/rpc-eth-api/src/id_provider.rs b/crates/rpc/rpc-eth-types/src/id_provider.rs similarity index 86% rename from crates/rpc/rpc-eth-api/src/id_provider.rs rename to crates/rpc/rpc-eth-types/src/id_provider.rs index 0b63da39f..642d87578 100644 --- a/crates/rpc/rpc-eth-api/src/id_provider.rs +++ b/crates/rpc/rpc-eth-types/src/id_provider.rs @@ -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::()) } diff --git a/crates/rpc/rpc-eth-types/src/lib.rs b/crates/rpc/rpc-eth-types/src/lib.rs new file mode 100644 index 000000000..be4e1619c --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/lib.rs @@ -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; diff --git a/crates/rpc/rpc-eth-api/src/logs_utils.rs b/crates/rpc/rpc-eth-types/src/logs_utils.rs similarity index 79% rename from crates/rpc/rpc-eth-api/src/logs_utils.rs rename to crates/rpc/rpc-eth-types/src/logs_utils.rs index f98567c4e..5cd5fa789 100644 --- a/crates/rpc/rpc-eth-api/src/logs_utils.rs +++ b/crates/rpc/rpc-eth-types/src/logs_utils.rs @@ -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 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 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, 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, to_block: Option, start_block: u64, diff --git a/crates/rpc/rpc-eth-api/src/pending_block.rs b/crates/rpc/rpc-eth-types/src/pending_block.rs similarity index 97% rename from crates/rpc/rpc-eth-api/src/pending_block.rs rename to crates/rpc/rpc-eth-types/src/pending_block.rs index a1671b283..7e27a9d6b 100644 --- a/crates/rpc/rpc-eth-api/src/pending_block.rs +++ b/crates/rpc/rpc-eth-types/src/pending_block.rs @@ -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)] diff --git a/crates/rpc/rpc-eth-api/src/receipt.rs b/crates/rpc/rpc-eth-types/src/receipt.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/receipt.rs rename to crates/rpc/rpc-eth-types/src/receipt.rs index ac9944ab8..cd3fd1ed5 100644 --- a/crates/rpc/rpc-eth-api/src/receipt.rs +++ b/crates/rpc/rpc-eth-types/src/receipt.rs @@ -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)] diff --git a/crates/rpc/rpc-eth-api/src/revm_utils.rs b/crates/rpc/rpc-eth-types/src/revm_utils.rs similarity index 99% rename from crates/rpc/rpc-eth-api/src/revm_utils.rs rename to crates/rpc/rpc-eth-types/src/revm_utils.rs index b0d0e6a88..6b30de26c 100644 --- a/crates/rpc/rpc-eth-api/src/revm_utils.rs +++ b/crates/rpc/rpc-eth-types/src/revm_utils.rs @@ -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] diff --git a/crates/rpc/rpc-eth-api/src/transaction.rs b/crates/rpc/rpc-eth-types/src/transaction.rs similarity index 97% rename from crates/rpc/rpc-eth-api/src/transaction.rs rename to crates/rpc/rpc-eth-types/src/transaction.rs index 685f37b93..32c81d396 100644 --- a/crates/rpc/rpc-eth-api/src/transaction.rs +++ b/crates/rpc/rpc-eth-types/src/transaction.rs @@ -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. diff --git a/crates/rpc/rpc-eth-api/src/utils.rs b/crates/rpc/rpc-eth-types/src/utils.rs similarity index 95% rename from crates/rpc/rpc-eth-api/src/utils.rs rename to crates/rpc/rpc-eth-types/src/utils.rs index 6573fb6b7..a35708396 100644 --- a/crates/rpc/rpc-eth-api/src/utils.rs +++ b/crates/rpc/rpc-eth-types/src/utils.rs @@ -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. /// diff --git a/crates/rpc/rpc-server-types/Cargo.toml b/crates/rpc/rpc-server-types/Cargo.toml index ddecc0a49..628654eba 100644 --- a/crates/rpc/rpc-server-types/Cargo.toml +++ b/crates/rpc/rpc-server-types/Cargo.toml @@ -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"] } + diff --git a/crates/rpc/rpc-server-types/src/constants.rs b/crates/rpc/rpc-server-types/src/constants.rs index 3784d7508..807d96a91 100644 --- a/crates/rpc/rpc-server-types/src/constants.rs +++ b/crates/rpc/rpc-server-types/src/constants.rs @@ -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 + /// + pub const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015; } /// Cache specific constants diff --git a/crates/rpc/rpc-server-types/src/lib.rs b/crates/rpc/rpc-server-types/src/lib.rs index 4bdee53f8..c20b57881 100644 --- a/crates/rpc/rpc-server-types/src/lib.rs +++ b/crates/rpc/rpc-server-types/src/lib.rs @@ -10,6 +10,9 @@ /// Common RPC constants. pub mod constants; +pub mod result; mod module; pub use module::{RethRpcModule, RpcModuleSelection}; + +pub use result::ToRpcResult; diff --git a/crates/rpc/rpc-eth-api/src/result.rs b/crates/rpc/rpc-server-types/src/result.rs similarity index 80% rename from crates/rpc/rpc-eth-api/src/result.rs rename to crates/rpc/rpc-server-types/src/result.rs index ac55bb3fe..252c78f24 100644 --- a/crates/rpc/rpc-eth-api/src/result.rs +++ b/crates/rpc/rpc-server-types/src/result.rs @@ -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: Sized { M: Into; /// 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(self, op: F) -> RpcResult where F: FnOnce(Err) -> M, M: Into; /// 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 where F: FnOnce(Err) -> (M, &'a [u8]), @@ -47,7 +47,7 @@ macro_rules! impl_to_rpc_result { ($err:ty) => { impl ToRpcResult for Result { #[inline] - fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult + fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult where F: FnOnce($err) -> (i32, M, Option<&'a [u8]>), M: Into, @@ -62,7 +62,7 @@ macro_rules! impl_to_rpc_result { } #[inline] - fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult + fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult where F: FnOnce($err) -> M, M: Into, @@ -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 + fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult where F: FnOnce($err) -> (M, &'a [u8]), M: Into, @@ -86,7 +86,7 @@ macro_rules! impl_to_rpc_result { } #[inline] - fn with_message(self, msg: &str) -> jsonrpsee::core::RpcResult { + fn with_message(self, msg: &str) -> jsonrpsee_core::RpcResult { 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, -) -> 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) -> jsonrpsee::types::error::ErrorObject<'static> { - rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, None) +pub fn internal_rpc_err(msg: impl Into) -> 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, 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, -) -> 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, 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") }), ) diff --git a/crates/rpc/rpc-types/Cargo.toml b/crates/rpc/rpc-types/Cargo.toml index 648b8b24f..7a6e081a2 100644 --- a/crates/rpc/rpc-types/Cargo.toml +++ b/crates/rpc/rpc-types/Cargo.toml @@ -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"] \ No newline at end of file diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 7082a75fc..118a9a821 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -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", ] diff --git a/crates/rpc/rpc/src/admin.rs b/crates/rpc/rpc/src/admin.rs index 0e1e13a0c..772bc77e3 100644 --- a/crates/rpc/rpc/src/admin.rs +++ b/crates/rpc/rpc/src/admin.rs @@ -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. diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 8fd7c582a..5a098feb7 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -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::{ diff --git a/crates/rpc/rpc-eth-api/src/api/servers/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs similarity index 97% rename from crates/rpc/rpc-eth-api/src/api/servers/bundle.rs rename to crates/rpc/rpc/src/eth/bundle.rs index b272d72a9..b72d548b1 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -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. diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs new file mode 100644 index 000000000..f2eb81851 --- /dev/null +++ b/crates/rpc/rpc/src/eth/core.rs @@ -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 { + /// All nested fields bundled together. + pub(super) inner: Arc>, +} + +impl EthApi { + /// 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) { + self.inner.raw_transaction_forwarder.write().replace(forwarder); + } +} + +impl EthApi +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, + gas_cap: impl Into, + blocking_task_pool: BlockingTaskPool, + fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, + raw_transaction_forwarder: Option>, + ) -> Self { + Self::with_spawner( + provider, + pool, + network, + eth_cache, + gas_oracle, + gas_cap.into().into(), + Box::::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, + gas_cap: u64, + task_spawner: Box, + blocking_task_pool: BlockingTaskPool, + fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, + raw_transaction_forwarder: Option>, + ) -> 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 { + &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 std::fmt::Debug + for EthApi +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EthApi").finish_non_exhaustive() + } +} + +impl Clone for EthApi { + fn clone(&self) -> Self { + Self { inner: Arc::clone(&self.inner) } + } +} + +impl SpawnBlocking + for EthApi +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 EthApi { + /// 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 { + /// 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>>, + /// The async cache frontend for eth related data + eth_cache: EthStateCache, + /// The async gas oracle frontend for gas price suggestions + gas_oracle: GasPriceOracle, + /// 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, + /// Cached pending block if any + pending_block: Mutex>, + /// 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>>, +} + +impl EthApiInner { + /// 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> { + &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> { + 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 { + &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>> { + &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 { + 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, + block_count: u64, + mock_provider: MockEthProvider, + ) -> (EthApi, Vec, Vec) { + 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 = rng.gen::().then(|| rng.gen::() 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 = 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 = as EthApiServer>::fee_history( + ð_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 = as EthApiServer>::fee_history( + ð_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 = as EthApiServer>::fee_history( + ð_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" + ); + } +} diff --git a/crates/rpc/rpc-eth-api/src/api/servers/filter.rs b/crates/rpc/rpc/src/eth/filter.rs similarity index 93% rename from crates/rpc/rpc-eth-api/src/api/servers/filter.rs rename to crates/rpc/rpc/src/eth/filter.rs index 8f2ff382c..1a2e55a52 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/filter.rs +++ b/crates/rpc/rpc/src/eth/filter.rs @@ -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 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 for EthFilterError { - fn from(err: ProviderError) -> Self { - Self::EthAPIError(err.into()) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs similarity index 83% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/block.rs rename to crates/rpc/rpc/src/eth/helpers/block.rs index 2d583161f..2ce6c7ed2 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/block.rs +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -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 EthBlocks for EthApi where diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/blocking_task.rs b/crates/rpc/rpc/src/eth/helpers/blocking_task.rs similarity index 100% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/traits/blocking_task.rs rename to crates/rpc/rpc/src/eth/helpers/blocking_task.rs diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/call.rs b/crates/rpc/rpc/src/eth/helpers/call.rs similarity index 84% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/call.rs rename to crates/rpc/rpc/src/eth/helpers/call.rs index 151cfc91f..c442c46b4 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/call.rs +++ b/crates/rpc/rpc/src/eth/helpers/call.rs @@ -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 EthCall for EthApi where Self: Call + LoadPendingBlock diff --git a/crates/rpc/rpc/src/eth/helpers/fee.rs b/crates/rpc/rpc/src/eth/helpers/fee.rs new file mode 100644 index 000000000..7d795e52f --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/fee.rs @@ -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: + fn gas_price(&self) -> impl Future> + 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> + 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> + 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>, + ) -> impl Future> + 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 = Vec::new(); + let mut gas_used_ratio: Vec = Vec::new(); + + let mut base_fee_per_blob_gas: Vec = Vec::new(); + let mut blob_gas_used_ratio: Vec = Vec::new(); + + let mut rewards: Vec> = 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; + + /// 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, + ) -> impl Future> + 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, + max_priority_fee_per_gas: Option, + ) -> impl Future> + 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, + ) -> impl Future> + 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: + fn gas_price(&self) -> impl Future> + 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> + 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> + Send + where + Self: 'static, + { + self.gas_oracle().suggest_tip_cap() + } +} diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/fees.rs b/crates/rpc/rpc/src/eth/helpers/fees.rs similarity index 85% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/fees.rs rename to crates/rpc/rpc/src/eth/helpers/fees.rs index 351ce9c18..7380f4ea2 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/fees.rs +++ b/crates/rpc/rpc/src/eth/helpers/fees.rs @@ -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 EthFees for EthApi where Self: LoadFee diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/mod.rs b/crates/rpc/rpc/src/eth/helpers/mod.rs similarity index 95% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/mod.rs rename to crates/rpc/rpc/src/eth/helpers/mod.rs index e360df713..4c86e2b5f 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/mod.rs +++ b/crates/rpc/rpc/src/eth/helpers/mod.rs @@ -2,7 +2,6 @@ //! files. pub mod signer; -pub mod traits; mod block; mod call; diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/optimism.rs b/crates/rpc/rpc/src/eth/helpers/optimism.rs similarity index 96% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/optimism.rs rename to crates/rpc/rpc/src/eth/helpers/optimism.rs index 4726a00e8..751c06463 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/optimism.rs +++ b/crates/rpc/rpc/src/eth/helpers/optimism.rs @@ -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)] diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/pending_block.rs b/crates/rpc/rpc/src/eth/helpers/pending_block.rs similarity index 89% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/pending_block.rs rename to crates/rpc/rpc/src/eth/helpers/pending_block.rs index 33db098da..d1a47da75 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/pending_block.rs +++ b/crates/rpc/rpc/src/eth/helpers/pending_block.rs @@ -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 LoadPendingBlock for EthApi diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/receipt.rs b/crates/rpc/rpc/src/eth/helpers/receipt.rs similarity index 66% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/receipt.rs rename to crates/rpc/rpc/src/eth/helpers/receipt.rs index 404b526e4..db1fee781 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/receipt.rs +++ b/crates/rpc/rpc/src/eth/helpers/receipt.rs @@ -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 LoadReceipt for EthApi where @@ -8,6 +11,6 @@ where { #[inline] fn cache(&self) -> &EthStateCache { - &self.inner.eth_cache + self.inner.cache() } } diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/signer.rs b/crates/rpc/rpc/src/eth/helpers/signer.rs similarity index 98% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/signer.rs rename to crates/rpc/rpc/src/eth/helpers/signer.rs index bd2cdc244..a4cb726a2 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/signer.rs +++ b/crates/rpc/rpc/src/eth/helpers/signer.rs @@ -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 { diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/spec.rs b/crates/rpc/rpc/src/eth/helpers/spec.rs similarity index 90% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/spec.rs rename to crates/rpc/rpc/src/eth/helpers/spec.rs index f1ec32374..a93d662ea 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/spec.rs +++ b/crates/rpc/rpc/src/eth/helpers/spec.rs @@ -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 EthApiSpec for EthApi where @@ -36,7 +37,7 @@ where } fn accounts(&self) -> Vec
{ - 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, diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/state.rs b/crates/rpc/rpc/src/eth/helpers/state.rs similarity index 92% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/state.rs rename to crates/rpc/rpc/src/eth/helpers/state.rs index c55c695c3..dd28c6465 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/state.rs +++ b/crates/rpc/rpc/src/eth/helpers/state.rs @@ -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 EthState for EthApi 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] diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/trace.rs b/crates/rpc/rpc/src/eth/helpers/trace.rs similarity index 83% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/trace.rs rename to crates/rpc/rpc/src/eth/helpers/trace.rs index 14b853adb..fe1ee9f13 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/trace.rs +++ b/crates/rpc/rpc/src/eth/helpers/trace.rs @@ -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 Trace for EthApi where diff --git a/crates/rpc/rpc-eth-api/src/api/servers/helpers/transaction.rs b/crates/rpc/rpc/src/eth/helpers/transaction.rs similarity index 94% rename from crates/rpc/rpc-eth-api/src/api/servers/helpers/transaction.rs rename to crates/rpc/rpc/src/eth/helpers/transaction.rs index 1f4afa7a9..9d86be1b2 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/helpers/transaction.rs +++ b/crates/rpc/rpc/src/eth/helpers/transaction.rs @@ -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 EthTransactions for EthApi @@ -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] diff --git a/crates/rpc/rpc/src/eth/mod.rs b/crates/rpc/rpc/src/eth/mod.rs new file mode 100644 index 000000000..4e6a0cbb8 --- /dev/null +++ b/crates/rpc/rpc/src/eth/mod.rs @@ -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; diff --git a/crates/rpc/rpc-eth-api/src/api/servers/pubsub.rs b/crates/rpc/rpc/src/eth/pubsub.rs similarity index 98% rename from crates/rpc/rpc-eth-api/src/api/servers/pubsub.rs rename to crates/rpc/rpc/src/eth/pubsub.rs index a0e886f6d..3585be9f8 100644 --- a/crates/rpc/rpc-eth-api/src/api/servers/pubsub.rs +++ b/crates/rpc/rpc/src/eth/pubsub.rs @@ -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. diff --git a/crates/rpc/rpc/src/lib.rs b/crates/rpc/rpc/src/lib.rs index fbd924473..eec14981b 100644 --- a/crates/rpc/rpc/src/lib.rs +++ b/crates/rpc/rpc/src/lib.rs @@ -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; diff --git a/crates/rpc/rpc/src/net.rs b/crates/rpc/rpc/src/net.rs index c3a1229a5..79e85ac48 100644 --- a/crates/rpc/rpc/src/net.rs +++ b/crates/rpc/rpc/src/net.rs @@ -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. diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 9405ffd3e..4088d71ca 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -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, diff --git a/crates/rpc/rpc/src/reth.rs b/crates/rpc/rpc/src/reth.rs index 11c437e69..33dc74920 100644 --- a/crates/rpc/rpc/src/reth.rs +++ b/crates/rpc/rpc/src/reth.rs @@ -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; diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 2c3e9334a..bf1e7020c 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -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::{ diff --git a/crates/rpc/rpc/src/web3.rs b/crates/rpc/rpc/src/web3.rs index 78464327a..787604e25 100644 --- a/crates/rpc/rpc/src/web3.rs +++ b/crates/rpc/rpc/src/web3.rs @@ -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. /// diff --git a/examples/custom-dev-node/src/main.rs b/examples/custom-dev-node/src/main.rs index 5f346e7a2..24e7b229f 100644 --- a/examples/custom-dev-node/src/main.rs +++ b/examples/custom-dev-node/src/main.rs @@ -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<()> { diff --git a/examples/custom-inspector/src/main.rs b/examples/custom-inspector/src/main.rs index b3f33af07..fd1d82b59 100644 --- a/examples/custom-inspector/src/main.rs +++ b/examples/custom-inspector/src/main.rs @@ -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; diff --git a/examples/rpc-db/src/myrpc_ext.rs b/examples/rpc-db/src/myrpc_ext.rs index d1898b81c..e38b6fc24 100644 --- a/examples/rpc-db/src/myrpc_ext.rs +++ b/examples/rpc-db/src/myrpc_ext.rs @@ -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` ///