mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(rpc): move impl of eth api server out of reth-rpc-eth-api (#9135)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -1,8 +1,13 @@
|
||||
use alloy_consensus::TxEnvelope;
|
||||
use alloy_network::eip2718::Decodable2718;
|
||||
use reth::{api::FullNodeComponents, builder::rpc::RpcRegistry, rpc::api::DebugApiServer};
|
||||
use reth::{
|
||||
builder::{rpc::RpcRegistry, FullNodeComponents},
|
||||
rpc::{
|
||||
api::{eth::helpers::EthTransactions, DebugApiServer},
|
||||
server_types::eth::EthResult,
|
||||
},
|
||||
};
|
||||
use reth_primitives::{Bytes, B256};
|
||||
use reth_rpc::eth::{servers::EthTransactions, EthResult};
|
||||
|
||||
pub struct RpcTestContext<Node: FullNodeComponents> {
|
||||
pub inner: RpcRegistry<Node>,
|
||||
|
||||
@ -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<()> {
|
||||
|
||||
@ -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"]
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
//! clap [Args](clap::Args) for RPC related arguments.
|
||||
|
||||
use crate::args::{
|
||||
types::{MaxU32, ZeroAsNoneU64},
|
||||
GasPriceOracleArgs, RpcStateCacheArgs,
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use alloy_rpc_types_engine::JwtSecret;
|
||||
use clap::{
|
||||
builder::{PossibleValue, RangedU64ValueParser, TypedValueParser},
|
||||
Arg, Args, Command,
|
||||
};
|
||||
use rand::Rng;
|
||||
use reth_rpc_eth_api::RPC_DEFAULT_GAS_CAP;
|
||||
|
||||
use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection};
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
|
||||
use crate::args::{
|
||||
types::{MaxU32, ZeroAsNoneU64},
|
||||
GasPriceOracleArgs, RpcStateCacheArgs,
|
||||
};
|
||||
|
||||
/// Default max number of subscriptions per connection.
|
||||
@ -152,7 +152,7 @@ pub struct RpcServerArgs {
|
||||
alias = "rpc-gascap",
|
||||
value_name = "GAS_CAP",
|
||||
value_parser = RangedU64ValueParser::<u64>::new().range(1..),
|
||||
default_value_t = RPC_DEFAULT_GAS_CAP.into()
|
||||
default_value_t = constants::gas_oracle::RPC_DEFAULT_GAS_CAP
|
||||
)]
|
||||
pub rpc_gas_cap: u64,
|
||||
|
||||
@ -285,7 +285,7 @@ impl Default for RpcServerArgs {
|
||||
rpc_max_tracing_requests: constants::default_max_tracing_requests(),
|
||||
rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(),
|
||||
rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(),
|
||||
rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(),
|
||||
rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
|
||||
gas_price_oracle: GasPriceOracleArgs::default(),
|
||||
rpc_state_cache: RpcStateCacheArgs::default(),
|
||||
}
|
||||
|
||||
@ -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`.
|
||||
|
||||
@ -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"
|
||||
]
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
//! Helpers for optimism specific RPC implementations.
|
||||
|
||||
use jsonrpsee::types::ErrorObject;
|
||||
use reqwest::Client;
|
||||
use reth_rpc::eth::{
|
||||
error::{EthApiError, EthResult},
|
||||
servers::RawTransactionForwarder,
|
||||
};
|
||||
use reth_rpc_types::ToRpcError;
|
||||
use std::sync::{atomic::AtomicUsize, Arc};
|
||||
|
||||
use jsonrpsee_types::error::{ErrorObject, INTERNAL_ERROR_CODE};
|
||||
use reqwest::Client;
|
||||
use reth_rpc_eth_api::RawTransactionForwarder;
|
||||
use reth_rpc_eth_types::error::{EthApiError, EthResult};
|
||||
use reth_rpc_types::ToRpcError;
|
||||
|
||||
/// Error type when interacting with the Sequencer
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SequencerRpcError {
|
||||
@ -22,11 +21,7 @@ pub enum SequencerRpcError {
|
||||
|
||||
impl ToRpcError for SequencerRpcError {
|
||||
fn to_rpc_error(&self) -> ErrorObject<'static> {
|
||||
ErrorObject::owned(
|
||||
jsonrpsee::types::error::INTERNAL_ERROR_CODE,
|
||||
self.to_string(),
|
||||
None::<String>,
|
||||
)
|
||||
ErrorObject::owned(INTERNAL_ERROR_CODE, self.to_string(), None::<String>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
|
||||
@ -178,14 +178,12 @@ use reth_provider::{
|
||||
ChangeSetReader, EvmEnvProvider, StateProviderFactory,
|
||||
};
|
||||
use reth_rpc::{
|
||||
eth::{
|
||||
servers::RawTransactionForwarder, EthApi, EthBundle, EthStateCache,
|
||||
EthSubscriptionIdProvider,
|
||||
},
|
||||
eth::{EthApi, EthBundle, RawTransactionForwarder},
|
||||
AdminApi, DebugApi, EngineEthApi, NetApi, OtterscanApi, RPCApi, RethApi, TraceApi, TxPoolApi,
|
||||
Web3Api,
|
||||
};
|
||||
use reth_rpc_api::servers::*;
|
||||
use reth_rpc_api::*;
|
||||
use reth_rpc_eth_types::{EthStateCache, EthSubscriptionIdProvider};
|
||||
use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret};
|
||||
use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor};
|
||||
use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool};
|
||||
@ -998,7 +996,7 @@ where
|
||||
///
|
||||
/// This will spawn the required service tasks for [`EthApi`] for:
|
||||
/// - [`EthStateCache`]
|
||||
/// - [`reth_rpc::eth::FeeHistoryCache`]
|
||||
/// - [`FeeHistoryCache`](reth_rpc_eth_types::FeeHistoryCache)
|
||||
fn with_eth<F, R>(&mut self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&EthHandlers<Provider, Pool, Network, Events, EvmConfig>) -> R,
|
||||
|
||||
@ -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"
|
||||
]
|
||||
@ -1,318 +0,0 @@
|
||||
//! `eth_` RPC API.
|
||||
|
||||
use alloy_dyn_abi::TypedData;
|
||||
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
|
||||
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
|
||||
use reth_rpc_types::{
|
||||
serde_helpers::JsonStorageKey, state::StateOverride, AccessListWithGasUsed,
|
||||
AnyTransactionReceipt, BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse,
|
||||
FeeHistory, Header, Index, RichBlock, StateContext, SyncStatus, Transaction,
|
||||
TransactionRequest, Work,
|
||||
};
|
||||
|
||||
pub mod bundle;
|
||||
pub mod filter;
|
||||
pub mod pubsub;
|
||||
pub mod servers;
|
||||
|
||||
/// Eth rpc interface: <https://ethereum.github.io/execution-apis/api-documentation/>
|
||||
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
|
||||
#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
|
||||
pub trait EthApi {
|
||||
/// Returns the protocol version encoded as a string.
|
||||
#[method(name = "protocolVersion")]
|
||||
async fn protocol_version(&self) -> RpcResult<U64>;
|
||||
|
||||
/// Returns an object with data about the sync status or false.
|
||||
#[method(name = "syncing")]
|
||||
fn syncing(&self) -> RpcResult<SyncStatus>;
|
||||
|
||||
/// Returns the client coinbase address.
|
||||
#[method(name = "coinbase")]
|
||||
async fn author(&self) -> RpcResult<Address>;
|
||||
|
||||
/// Returns a list of addresses owned by client.
|
||||
#[method(name = "accounts")]
|
||||
fn accounts(&self) -> RpcResult<Vec<Address>>;
|
||||
|
||||
/// Returns the number of most recent block.
|
||||
#[method(name = "blockNumber")]
|
||||
fn block_number(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the chain ID of the current network.
|
||||
#[method(name = "chainId")]
|
||||
async fn chain_id(&self) -> RpcResult<Option<U64>>;
|
||||
|
||||
/// Returns information about a block by hash.
|
||||
#[method(name = "getBlockByHash")]
|
||||
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns information about a block by number.
|
||||
#[method(name = "getBlockByNumber")]
|
||||
async fn block_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
full: bool,
|
||||
) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns the number of transactions in a block from a block matching the given block hash.
|
||||
#[method(name = "getBlockTransactionCountByHash")]
|
||||
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns the number of transactions in a block matching the given block number.
|
||||
#[method(name = "getBlockTransactionCountByNumber")]
|
||||
async fn block_transaction_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns the number of uncles in a block from a block matching the given block hash.
|
||||
#[method(name = "getUncleCountByBlockHash")]
|
||||
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns the number of uncles in a block with given block number.
|
||||
#[method(name = "getUncleCountByBlockNumber")]
|
||||
async fn block_uncles_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns all transaction receipts for a given block.
|
||||
#[method(name = "getBlockReceipts")]
|
||||
async fn block_receipts(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> RpcResult<Option<Vec<AnyTransactionReceipt>>>;
|
||||
|
||||
/// Returns an uncle block of the given block and index.
|
||||
#[method(name = "getUncleByBlockHashAndIndex")]
|
||||
async fn uncle_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns an uncle block of the given block and index.
|
||||
#[method(name = "getUncleByBlockNumberAndIndex")]
|
||||
async fn uncle_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns the EIP-2718 encoded transaction if it exists.
|
||||
///
|
||||
/// If this is a EIP-4844 transaction that is in the pool it will include the sidecar.
|
||||
#[method(name = "getRawTransactionByHash")]
|
||||
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>>;
|
||||
|
||||
/// Returns the information about a transaction requested by transaction hash.
|
||||
#[method(name = "getTransactionByHash")]
|
||||
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Transaction>>;
|
||||
|
||||
/// Returns information about a raw transaction by block hash and transaction index position.
|
||||
#[method(name = "getRawTransactionByBlockHashAndIndex")]
|
||||
async fn raw_transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Bytes>>;
|
||||
|
||||
/// Returns information about a transaction by block hash and transaction index position.
|
||||
#[method(name = "getTransactionByBlockHashAndIndex")]
|
||||
async fn transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Transaction>>;
|
||||
|
||||
/// Returns information about a raw transaction by block number and transaction index
|
||||
/// position.
|
||||
#[method(name = "getRawTransactionByBlockNumberAndIndex")]
|
||||
async fn raw_transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Bytes>>;
|
||||
|
||||
/// Returns information about a transaction by block number and transaction index position.
|
||||
#[method(name = "getTransactionByBlockNumberAndIndex")]
|
||||
async fn transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Transaction>>;
|
||||
|
||||
/// Returns the receipt of a transaction by transaction hash.
|
||||
#[method(name = "getTransactionReceipt")]
|
||||
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<AnyTransactionReceipt>>;
|
||||
|
||||
/// Returns the balance of the account of given address.
|
||||
#[method(name = "getBalance")]
|
||||
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the value from a storage position at a given address
|
||||
#[method(name = "getStorageAt")]
|
||||
async fn storage_at(
|
||||
&self,
|
||||
address: Address,
|
||||
index: JsonStorageKey,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<B256>;
|
||||
|
||||
/// Returns the number of transactions sent from an address at given block number.
|
||||
#[method(name = "getTransactionCount")]
|
||||
async fn transaction_count(
|
||||
&self,
|
||||
address: Address,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<U256>;
|
||||
|
||||
/// Returns code at a given address at given block number.
|
||||
#[method(name = "getCode")]
|
||||
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes>;
|
||||
|
||||
/// Returns the block's header at given number.
|
||||
#[method(name = "getHeaderByNumber")]
|
||||
async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult<Option<Header>>;
|
||||
|
||||
/// Returns the block's header at given hash.
|
||||
#[method(name = "getHeaderByHash")]
|
||||
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<Header>>;
|
||||
|
||||
/// Executes a new message call immediately without creating a transaction on the block chain.
|
||||
#[method(name = "call")]
|
||||
async fn call(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
block_overrides: Option<Box<BlockOverrides>>,
|
||||
) -> RpcResult<Bytes>;
|
||||
|
||||
/// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the
|
||||
/// optionality of state overrides
|
||||
#[method(name = "callMany")]
|
||||
async fn call_many(
|
||||
&self,
|
||||
bundle: Bundle,
|
||||
state_context: Option<StateContext>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> RpcResult<Vec<EthCallResponse>>;
|
||||
|
||||
/// Generates an access list for a transaction.
|
||||
///
|
||||
/// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction.
|
||||
///
|
||||
/// An access list contains all storage slots and addresses touched by the transaction, except
|
||||
/// for the sender account and the chain's precompiles.
|
||||
///
|
||||
/// It returns list of addresses and storage keys used by the transaction, plus the gas
|
||||
/// consumed when the access list is added. That is, it gives you the list of addresses and
|
||||
/// storage keys that will be used by that transaction, plus the gas consumed if the access
|
||||
/// list is included. Like eth_estimateGas, this is an estimation; the list could change
|
||||
/// when the transaction is actually mined. Adding an accessList to your transaction does
|
||||
/// not necessary result in lower gas usage compared to a transaction without an access
|
||||
/// list.
|
||||
#[method(name = "createAccessList")]
|
||||
async fn create_access_list(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<AccessListWithGasUsed>;
|
||||
|
||||
/// Generates and returns an estimate of how much gas is necessary to allow the transaction to
|
||||
/// complete.
|
||||
#[method(name = "estimateGas")]
|
||||
async fn estimate_gas(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the current price per gas in wei.
|
||||
#[method(name = "gasPrice")]
|
||||
async fn gas_price(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions.
|
||||
#[method(name = "maxPriorityFeePerGas")]
|
||||
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Introduced in EIP-4844, returns the current blob base fee in wei.
|
||||
#[method(name = "blobBaseFee")]
|
||||
async fn blob_base_fee(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the Transaction fee history
|
||||
///
|
||||
/// Introduced in EIP-1559 for getting information on the appropriate priority fee to use.
|
||||
///
|
||||
/// Returns transaction base fee per gas and effective priority fee per gas for the
|
||||
/// requested/supported block range. The returned Fee history for the returned block range
|
||||
/// can be a subsection of the requested range if not all blocks are available.
|
||||
#[method(name = "feeHistory")]
|
||||
async fn fee_history(
|
||||
&self,
|
||||
block_count: U64,
|
||||
newest_block: BlockNumberOrTag,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> RpcResult<FeeHistory>;
|
||||
|
||||
/// Returns whether the client is actively mining new blocks.
|
||||
#[method(name = "mining")]
|
||||
async fn is_mining(&self) -> RpcResult<bool>;
|
||||
|
||||
/// Returns the number of hashes per second that the node is mining with.
|
||||
#[method(name = "hashrate")]
|
||||
async fn hashrate(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met
|
||||
/// (“target”)
|
||||
#[method(name = "getWork")]
|
||||
async fn get_work(&self) -> RpcResult<Work>;
|
||||
|
||||
/// Used for submitting mining hashrate.
|
||||
///
|
||||
/// Can be used for remote miners to submit their hash rate.
|
||||
/// It accepts the miner hash rate and an identifier which must be unique between nodes.
|
||||
/// Returns `true` if the block was successfully submitted, `false` otherwise.
|
||||
#[method(name = "submitHashrate")]
|
||||
async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult<bool>;
|
||||
|
||||
/// Used for submitting a proof-of-work solution.
|
||||
#[method(name = "submitWork")]
|
||||
async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult<bool>;
|
||||
|
||||
/// Sends transaction; will block waiting for signer to return the
|
||||
/// transaction hash.
|
||||
#[method(name = "sendTransaction")]
|
||||
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256>;
|
||||
|
||||
/// Sends signed transaction, returning its hash.
|
||||
#[method(name = "sendRawTransaction")]
|
||||
async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
|
||||
|
||||
/// Returns an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n"
|
||||
/// + len(message) + message))).
|
||||
#[method(name = "sign")]
|
||||
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes>;
|
||||
|
||||
/// Signs a transaction that can be submitted to the network at a later time using with
|
||||
/// `sendRawTransaction.`
|
||||
#[method(name = "signTransaction")]
|
||||
async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult<Bytes>;
|
||||
|
||||
/// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
|
||||
#[method(name = "signTypedData")]
|
||||
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes>;
|
||||
|
||||
/// Returns the account and storage values of the specified account including the Merkle-proof.
|
||||
/// This call can be used to verify that the data you are pulling from is not tampered with.
|
||||
#[method(name = "getProof")]
|
||||
async fn get_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
keys: Vec<JsonStorageKey>,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<EIP1186AccountProofResponse>;
|
||||
}
|
||||
@ -1,323 +0,0 @@
|
||||
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait
|
||||
//! Handles RPC requests for the `eth_` namespace.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use reth_primitives::{BlockNumberOrTag, U256};
|
||||
use reth_provider::{BlockReaderIdExt, ChainSpecProvider};
|
||||
|
||||
pub mod bundle;
|
||||
pub mod filter;
|
||||
pub mod helpers;
|
||||
pub mod pubsub;
|
||||
|
||||
mod server;
|
||||
|
||||
pub use helpers::{
|
||||
signer::DevSigner,
|
||||
traits::{
|
||||
block::{EthBlocks, LoadBlock},
|
||||
blocking_task::SpawnBlocking,
|
||||
call::{Call, EthCall},
|
||||
fee::{EthFees, LoadFee},
|
||||
pending_block::LoadPendingBlock,
|
||||
receipt::LoadReceipt,
|
||||
signer::EthSigner,
|
||||
spec::EthApiSpec,
|
||||
state::{EthState, LoadState},
|
||||
trace::Trace,
|
||||
transaction::{EthTransactions, LoadTransaction, RawTransactionForwarder},
|
||||
TraceExt,
|
||||
},
|
||||
};
|
||||
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock};
|
||||
|
||||
/// `Eth` API implementation.
|
||||
///
|
||||
/// This type provides the functionality for handling `eth_` related requests.
|
||||
/// These are implemented two-fold: Core functionality is implemented as [`EthApiSpec`]
|
||||
/// trait. Additionally, the required server implementations (e.g.
|
||||
/// [`EthApiServer`](crate::EthApiServer)) are implemented separately in submodules. The rpc handler
|
||||
/// implementation can then delegate to the main impls. This way [`EthApi`] is not limited to
|
||||
/// [`jsonrpsee`] and can be used standalone or in other network handlers (for example ipc).
|
||||
pub struct EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
/// All nested fields bundled together.
|
||||
inner: Arc<EthApiInner<Provider, Pool, Network, EvmConfig>>,
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
/// Sets a forwarder for `eth_sendRawTransaction`
|
||||
///
|
||||
/// Note: this might be removed in the future in favor of a more generic approach.
|
||||
pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc<dyn RawTransactionForwarder>) {
|
||||
self.inner.raw_transaction_forwarder.write().replace(forwarder);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Provider: BlockReaderIdExt + ChainSpecProvider,
|
||||
{
|
||||
/// Creates a new, shareable instance using the default tokio task spawner.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
eth_cache: EthStateCache,
|
||||
gas_oracle: GasPriceOracle<Provider>,
|
||||
gas_cap: impl Into<GasCap>,
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
evm_config: EvmConfig,
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
) -> Self {
|
||||
Self::with_spawner(
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
eth_cache,
|
||||
gas_oracle,
|
||||
gas_cap.into().into(),
|
||||
Box::<TokioTaskExecutor>::default(),
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
raw_transaction_forwarder,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new, shareable instance.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn with_spawner(
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
eth_cache: EthStateCache,
|
||||
gas_oracle: GasPriceOracle<Provider>,
|
||||
gas_cap: u64,
|
||||
task_spawner: Box<dyn TaskSpawner>,
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
evm_config: EvmConfig,
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
) -> Self {
|
||||
// get the block number of the latest block
|
||||
let latest_block = provider
|
||||
.header_by_number_or_tag(BlockNumberOrTag::Latest)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|header| header.number)
|
||||
.unwrap_or_default();
|
||||
|
||||
let inner = EthApiInner {
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
signers: parking_lot::RwLock::new(Default::default()),
|
||||
eth_cache,
|
||||
gas_oracle,
|
||||
gas_cap,
|
||||
starting_block: U256::from(latest_block),
|
||||
task_spawner,
|
||||
pending_block: Default::default(),
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder),
|
||||
};
|
||||
|
||||
Self { inner: Arc::new(inner) }
|
||||
}
|
||||
|
||||
/// Returns the state cache frontend
|
||||
pub fn cache(&self) -> &EthStateCache {
|
||||
&self.inner.eth_cache
|
||||
}
|
||||
|
||||
/// Returns the gas oracle frontend
|
||||
pub fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
|
||||
&self.inner.gas_oracle
|
||||
}
|
||||
|
||||
/// Returns the configured gas limit cap for `eth_call` and tracing related calls
|
||||
pub fn gas_cap(&self) -> u64 {
|
||||
self.inner.gas_cap
|
||||
}
|
||||
|
||||
/// Returns the inner `Provider`
|
||||
pub fn provider(&self) -> &Provider {
|
||||
&self.inner.provider
|
||||
}
|
||||
|
||||
/// Returns the inner `Network`
|
||||
pub fn network(&self) -> &Network {
|
||||
&self.inner.network
|
||||
}
|
||||
|
||||
/// Returns the inner `Pool`
|
||||
pub fn pool(&self) -> &Pool {
|
||||
&self.inner.pool
|
||||
}
|
||||
|
||||
/// Returns fee history cache
|
||||
pub fn fee_history_cache(&self) -> &FeeHistoryCache {
|
||||
&self.inner.fee_history_cache
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EthApi").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> Clone for EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { inner: Arc::clone(&self.inner) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements [`SpawnBlocking`] for a type, that has similar data layout to [`EthApi`].
|
||||
#[macro_export]
|
||||
macro_rules! spawn_blocking_impl {
|
||||
($network_api:ty) => {
|
||||
impl<Provider, Pool, Network, EvmConfig> $crate::servers::SpawnBlocking for $network_api
|
||||
where
|
||||
Self: Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner {
|
||||
self.inner.task_spawner()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tracing_task_pool(&self) -> &reth_tasks::pool::BlockingTaskPool {
|
||||
self.inner.blocking_task_pool()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
spawn_blocking_impl!(EthApi<Provider, Pool, Network, EvmConfig>);
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
/// Generates 20 random developer accounts.
|
||||
/// Used in DEV mode.
|
||||
pub fn with_dev_accounts(&self) {
|
||||
let mut signers = self.inner.signers.write();
|
||||
*signers = DevSigner::random_signers(20);
|
||||
}
|
||||
}
|
||||
|
||||
/// Container type `EthApi`
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct EthApiInner<Provider, Pool, Network, EvmConfig> {
|
||||
/// The transaction pool.
|
||||
pool: Pool,
|
||||
/// The provider that can interact with the chain.
|
||||
provider: Provider,
|
||||
/// An interface to interact with the network
|
||||
network: Network,
|
||||
/// All configured Signers
|
||||
signers: parking_lot::RwLock<Vec<Box<dyn EthSigner>>>,
|
||||
/// The async cache frontend for eth related data
|
||||
eth_cache: EthStateCache,
|
||||
/// The async gas oracle frontend for gas price suggestions
|
||||
gas_oracle: GasPriceOracle<Provider>,
|
||||
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
|
||||
gas_cap: u64,
|
||||
/// The block number at which the node started
|
||||
starting_block: U256,
|
||||
/// The type that can spawn tasks which would otherwise block.
|
||||
task_spawner: Box<dyn TaskSpawner>,
|
||||
/// Cached pending block if any
|
||||
pending_block: Mutex<Option<PendingBlock>>,
|
||||
/// A pool dedicated to CPU heavy blocking tasks.
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
/// Cache for block fees history
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
/// The type that defines how to configure the EVM
|
||||
evm_config: EvmConfig,
|
||||
/// Allows forwarding received raw transactions
|
||||
raw_transaction_forwarder: parking_lot::RwLock<Option<Arc<dyn RawTransactionForwarder>>>,
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig> {
|
||||
/// Returns a handle to data on disk.
|
||||
#[inline]
|
||||
pub const fn provider(&self) -> &Provider {
|
||||
&self.provider
|
||||
}
|
||||
|
||||
/// Returns a handle to data in memory.
|
||||
#[inline]
|
||||
pub const fn cache(&self) -> &EthStateCache {
|
||||
&self.eth_cache
|
||||
}
|
||||
|
||||
/// Returns a handle to the pending block.
|
||||
#[inline]
|
||||
pub const fn pending_block(&self) -> &Mutex<Option<PendingBlock>> {
|
||||
&self.pending_block
|
||||
}
|
||||
|
||||
/// Returns a handle to the task spawner.
|
||||
#[inline]
|
||||
pub const fn task_spawner(&self) -> &dyn TaskSpawner {
|
||||
&*self.task_spawner
|
||||
}
|
||||
|
||||
/// Returns a handle to the blocking thread pool.
|
||||
#[inline]
|
||||
pub const fn blocking_task_pool(&self) -> &BlockingTaskPool {
|
||||
&self.blocking_task_pool
|
||||
}
|
||||
|
||||
/// Returns a handle to the EVM config.
|
||||
#[inline]
|
||||
pub const fn evm_config(&self) -> &EvmConfig {
|
||||
&self.evm_config
|
||||
}
|
||||
|
||||
/// Returns a handle to the transaction pool.
|
||||
#[inline]
|
||||
pub const fn pool(&self) -> &Pool {
|
||||
&self.pool
|
||||
}
|
||||
|
||||
/// Returns a handle to the transaction forwarder.
|
||||
#[inline]
|
||||
pub fn raw_tx_forwarder(&self) -> Option<Arc<dyn RawTransactionForwarder>> {
|
||||
self.raw_transaction_forwarder.read().clone()
|
||||
}
|
||||
|
||||
/// Returns the gas cap.
|
||||
#[inline]
|
||||
pub const fn gas_cap(&self) -> u64 {
|
||||
self.gas_cap
|
||||
}
|
||||
|
||||
/// Returns a handle to the gas oracle.
|
||||
#[inline]
|
||||
pub const fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
|
||||
&self.gas_oracle
|
||||
}
|
||||
|
||||
/// Returns a handle to the fee history cache.
|
||||
#[inline]
|
||||
pub const fn fee_history_cache(&self) -> &FeeHistoryCache {
|
||||
&self.fee_history_cache
|
||||
}
|
||||
|
||||
/// Returns a handle to the signers.
|
||||
#[inline]
|
||||
pub const fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
|
||||
&self.signers
|
||||
}
|
||||
}
|
||||
@ -1,715 +0,0 @@
|
||||
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`] trait. Handles RPC requests for
|
||||
//! the `eth_` namespace.
|
||||
|
||||
use alloy_dyn_abi::TypedData;
|
||||
use jsonrpsee::core::RpcResult as Result;
|
||||
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
|
||||
use reth_rpc_types::{
|
||||
serde_helpers::JsonStorageKey,
|
||||
state::{EvmOverrides, StateOverride},
|
||||
AccessListWithGasUsed, AnyTransactionReceipt, BlockOverrides, Bundle,
|
||||
EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, Index, RichBlock,
|
||||
StateContext, SyncStatus, Transaction, TransactionRequest, Work,
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{
|
||||
result::internal_rpc_err,
|
||||
servers::{
|
||||
EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadReceipt, Trace,
|
||||
},
|
||||
EthApiError, EthApiServer, ToRpcResult,
|
||||
};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T> EthApiServer for T
|
||||
where
|
||||
Self: EthApiSpec
|
||||
+ EthTransactions
|
||||
+ EthBlocks
|
||||
+ EthState
|
||||
+ EthCall
|
||||
+ EthFees
|
||||
+ Trace
|
||||
+ LoadReceipt,
|
||||
{
|
||||
/// Handler for: `eth_protocolVersion`
|
||||
async fn protocol_version(&self) -> Result<U64> {
|
||||
trace!(target: "rpc::eth", "Serving eth_protocolVersion");
|
||||
EthApiSpec::protocol_version(self).await.to_rpc_result()
|
||||
}
|
||||
|
||||
/// Handler for: `eth_syncing`
|
||||
fn syncing(&self) -> Result<SyncStatus> {
|
||||
trace!(target: "rpc::eth", "Serving eth_syncing");
|
||||
EthApiSpec::sync_status(self).to_rpc_result()
|
||||
}
|
||||
|
||||
/// Handler for: `eth_coinbase`
|
||||
async fn author(&self) -> Result<Address> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_accounts`
|
||||
fn accounts(&self) -> Result<Vec<Address>> {
|
||||
trace!(target: "rpc::eth", "Serving eth_accounts");
|
||||
Ok(EthApiSpec::accounts(self))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_blockNumber`
|
||||
fn block_number(&self) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_blockNumber");
|
||||
Ok(U256::from(
|
||||
EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number,
|
||||
))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_chainId`
|
||||
async fn chain_id(&self) -> Result<Option<U64>> {
|
||||
trace!(target: "rpc::eth", "Serving eth_chainId");
|
||||
Ok(Some(EthApiSpec::chain_id(self)))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockByHash`
|
||||
async fn block_by_hash(&self, hash: B256, full: bool) -> Result<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash");
|
||||
Ok(EthBlocks::rpc_block(self, hash.into(), full).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockByNumber`
|
||||
async fn block_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
full: bool,
|
||||
) -> Result<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber");
|
||||
Ok(EthBlocks::rpc_block(self, number.into(), full).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockTransactionCountByHash`
|
||||
async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash");
|
||||
Ok(EthBlocks::block_transaction_count(self, hash).await?.map(U256::from))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockTransactionCountByNumber`
|
||||
async fn block_transaction_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> Result<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber");
|
||||
Ok(EthBlocks::block_transaction_count(self, number).await?.map(U256::from))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleCountByBlockHash`
|
||||
async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash");
|
||||
Ok(EthBlocks::ommers(self, hash)?.map(|ommers| U256::from(ommers.len())))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleCountByBlockNumber`
|
||||
async fn block_uncles_count_by_number(&self, number: BlockNumberOrTag) -> Result<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber");
|
||||
Ok(EthBlocks::ommers(self, number)?.map(|ommers| U256::from(ommers.len())))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockReceipts`
|
||||
async fn block_receipts(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> Result<Option<Vec<AnyTransactionReceipt>>> {
|
||||
trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts");
|
||||
Ok(EthBlocks::block_receipts(self, block_id).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleByBlockHashAndIndex`
|
||||
async fn uncle_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> Result<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex");
|
||||
Ok(EthBlocks::ommer_by_block_and_index(self, hash, index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleByBlockNumberAndIndex`
|
||||
async fn uncle_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> Result<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex");
|
||||
Ok(EthBlocks::ommer_by_block_and_index(self, number, index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getRawTransactionByHash`
|
||||
async fn raw_transaction_by_hash(&self, hash: B256) -> Result<Option<Bytes>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash");
|
||||
Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByHash`
|
||||
async fn transaction_by_hash(&self, hash: B256) -> Result<Option<Transaction>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash");
|
||||
Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getRawTransactionByBlockHashAndIndex`
|
||||
async fn raw_transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> Result<Option<Bytes>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex");
|
||||
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByBlockHashAndIndex`
|
||||
async fn transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> Result<Option<reth_rpc_types::Transaction>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex");
|
||||
Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getRawTransactionByBlockNumberAndIndex`
|
||||
async fn raw_transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> Result<Option<Bytes>> {
|
||||
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex");
|
||||
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, number.into(), index)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByBlockNumberAndIndex`
|
||||
async fn transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> Result<Option<reth_rpc_types::Transaction>> {
|
||||
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex");
|
||||
Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionReceipt`
|
||||
async fn transaction_receipt(&self, hash: B256) -> Result<Option<AnyTransactionReceipt>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt");
|
||||
Ok(EthTransactions::transaction_receipt(self, hash).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBalance`
|
||||
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance");
|
||||
Ok(EthState::balance(self, address, block_number).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getStorageAt`
|
||||
async fn storage_at(
|
||||
&self,
|
||||
address: Address,
|
||||
index: JsonStorageKey,
|
||||
block_number: Option<BlockId>,
|
||||
) -> Result<B256> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt");
|
||||
let res: B256 = EthState::storage_at(self, address, index, block_number).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionCount`
|
||||
async fn transaction_count(
|
||||
&self,
|
||||
address: Address,
|
||||
block_number: Option<BlockId>,
|
||||
) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount");
|
||||
Ok(EthState::transaction_count(self, address, block_number).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getCode`
|
||||
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode");
|
||||
Ok(EthState::get_code(self, address, block_number).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getHeaderByNumber`
|
||||
async fn header_by_number(&self, block_number: BlockNumberOrTag) -> Result<Option<Header>> {
|
||||
trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber");
|
||||
Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getHeaderByHash`
|
||||
async fn header_by_hash(&self, hash: B256) -> Result<Option<Header>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash");
|
||||
Ok(EthBlocks::rpc_block_header(self, hash.into()).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_call`
|
||||
async fn call(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
block_overrides: Option<Box<BlockOverrides>>,
|
||||
) -> Result<Bytes> {
|
||||
trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call");
|
||||
Ok(EthCall::call(
|
||||
self,
|
||||
request,
|
||||
block_number,
|
||||
EvmOverrides::new(state_overrides, block_overrides),
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_callMany`
|
||||
async fn call_many(
|
||||
&self,
|
||||
bundle: Bundle,
|
||||
state_context: Option<StateContext>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> Result<Vec<EthCallResponse>> {
|
||||
trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany");
|
||||
Ok(EthCall::call_many(self, bundle, state_context, state_override).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_createAccessList`
|
||||
async fn create_access_list(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
) -> Result<AccessListWithGasUsed> {
|
||||
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList");
|
||||
let access_list_with_gas_used =
|
||||
EthCall::create_access_list_at(self, request, block_number).await?;
|
||||
|
||||
Ok(access_list_with_gas_used)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_estimateGas`
|
||||
async fn estimate_gas(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas");
|
||||
Ok(EthCall::estimate_gas_at(
|
||||
self,
|
||||
request,
|
||||
block_number.unwrap_or_default(),
|
||||
state_override,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_gasPrice`
|
||||
async fn gas_price(&self) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_gasPrice");
|
||||
return Ok(EthFees::gas_price(self).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_maxPriorityFeePerGas`
|
||||
async fn max_priority_fee_per_gas(&self) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas");
|
||||
return Ok(EthFees::suggested_priority_fee(self).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_blobBaseFee`
|
||||
async fn blob_base_fee(&self) -> Result<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_blobBaseFee");
|
||||
return Ok(EthFees::blob_base_fee(self).await?)
|
||||
}
|
||||
|
||||
// FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further
|
||||
// caching of it in the LRU cache.
|
||||
// When new RPC call is executed, the cache gets locked, we check it for the historical fees
|
||||
// according to the requested block range, and fill any cache misses (in both RPC response
|
||||
// and cache itself) with the actual data queried from the database.
|
||||
// To minimize the number of database seeks required to query the missing data, we calculate the
|
||||
// first non-cached block number and last non-cached block number. After that, we query this
|
||||
// range of consecutive blocks from the database.
|
||||
/// Handler for: `eth_feeHistory`
|
||||
async fn fee_history(
|
||||
&self,
|
||||
block_count: U64,
|
||||
newest_block: BlockNumberOrTag,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> Result<FeeHistory> {
|
||||
trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory");
|
||||
return Ok(
|
||||
EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?
|
||||
)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_mining`
|
||||
async fn is_mining(&self) -> Result<bool> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_hashrate`
|
||||
async fn hashrate(&self) -> Result<U256> {
|
||||
Ok(U256::ZERO)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getWork`
|
||||
async fn get_work(&self) -> Result<Work> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_submitHashrate`
|
||||
async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> Result<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_submitWork`
|
||||
async fn submit_work(&self, _nonce: B64, _pow_hash: B256, _mix_digest: B256) -> Result<bool> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_sendTransaction`
|
||||
async fn send_transaction(&self, request: TransactionRequest) -> Result<B256> {
|
||||
trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction");
|
||||
Ok(EthTransactions::send_transaction(self, request).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_sendRawTransaction`
|
||||
async fn send_raw_transaction(&self, tx: Bytes) -> Result<B256> {
|
||||
trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction");
|
||||
Ok(EthTransactions::send_raw_transaction(self, tx).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_sign`
|
||||
async fn sign(&self, address: Address, message: Bytes) -> Result<Bytes> {
|
||||
trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign");
|
||||
Ok(EthTransactions::sign(self, address, message).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_signTransaction`
|
||||
async fn sign_transaction(&self, _transaction: TransactionRequest) -> Result<Bytes> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_signTypedData`
|
||||
async fn sign_typed_data(&self, address: Address, data: TypedData) -> Result<Bytes> {
|
||||
trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData");
|
||||
Ok(EthTransactions::sign_typed_data(self, &data, address)?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getProof`
|
||||
async fn get_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
keys: Vec<JsonStorageKey>,
|
||||
block_number: Option<BlockId>,
|
||||
) -> Result<EIP1186AccountProofResponse> {
|
||||
trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof");
|
||||
let res = EthState::get_proof(self, address, keys, block_number)?.await;
|
||||
|
||||
Ok(res.map_err(|e| match e {
|
||||
EthApiError::InvalidBlockRange => {
|
||||
internal_rpc_err("eth_getProof is unimplemented for historical blocks")
|
||||
}
|
||||
_ => e.into(),
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use jsonrpsee::types::error::INVALID_PARAMS_CODE;
|
||||
use reth_chainspec::BaseFeeParams;
|
||||
use reth_evm_ethereum::EthEvmConfig;
|
||||
use reth_network_api::noop::NoopNetwork;
|
||||
use reth_primitives::{
|
||||
constants::ETHEREUM_BLOCK_GAS_LIMIT, Block, BlockNumberOrTag, Header, TransactionSigned,
|
||||
B256, U64,
|
||||
};
|
||||
use reth_provider::{
|
||||
test_utils::{MockEthProvider, NoopProvider},
|
||||
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory,
|
||||
};
|
||||
use reth_rpc_types::FeeHistory;
|
||||
use reth_tasks::pool::BlockingTaskPool;
|
||||
use reth_testing_utils::{generators, generators::Rng};
|
||||
use reth_transaction_pool::test_utils::{testing_pool, TestPool};
|
||||
|
||||
use crate::{
|
||||
EthApi, EthApiServer, EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
|
||||
};
|
||||
|
||||
fn build_test_eth_api<
|
||||
P: BlockReaderIdExt
|
||||
+ BlockReader
|
||||
+ ChainSpecProvider
|
||||
+ EvmEnvProvider
|
||||
+ StateProviderFactory
|
||||
+ Unpin
|
||||
+ Clone
|
||||
+ 'static,
|
||||
>(
|
||||
provider: P,
|
||||
) -> EthApi<P, TestPool, NoopNetwork, EthEvmConfig> {
|
||||
let evm_config = EthEvmConfig::default();
|
||||
let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config);
|
||||
let fee_history_cache =
|
||||
FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default());
|
||||
|
||||
EthApi::new(
|
||||
provider.clone(),
|
||||
testing_pool(),
|
||||
NoopNetwork::default(),
|
||||
cache.clone(),
|
||||
GasPriceOracle::new(provider, Default::default(), cache),
|
||||
ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
// Function to prepare the EthApi with mock data
|
||||
fn prepare_eth_api(
|
||||
newest_block: u64,
|
||||
mut oldest_block: Option<B256>,
|
||||
block_count: u64,
|
||||
mock_provider: MockEthProvider,
|
||||
) -> (EthApi<MockEthProvider, TestPool, NoopNetwork, EthEvmConfig>, Vec<u128>, Vec<f64>) {
|
||||
let mut rng = generators::rng();
|
||||
|
||||
// Build mock data
|
||||
let mut gas_used_ratios = Vec::new();
|
||||
let mut base_fees_per_gas = Vec::new();
|
||||
let mut last_header = None;
|
||||
let mut parent_hash = B256::default();
|
||||
|
||||
for i in (0..block_count).rev() {
|
||||
let hash = rng.gen();
|
||||
let gas_limit: u64 = rng.gen();
|
||||
let gas_used: u64 = rng.gen();
|
||||
// Note: Generates a u32 to avoid overflows later
|
||||
let base_fee_per_gas: Option<u64> = rng.gen::<bool>().then(|| rng.gen::<u32>() as u64);
|
||||
|
||||
let header = Header {
|
||||
number: newest_block - i,
|
||||
gas_limit,
|
||||
gas_used,
|
||||
base_fee_per_gas,
|
||||
parent_hash,
|
||||
..Default::default()
|
||||
};
|
||||
last_header = Some(header.clone());
|
||||
parent_hash = hash;
|
||||
|
||||
let mut transactions = vec![];
|
||||
for _ in 0..100 {
|
||||
let random_fee: u128 = rng.gen();
|
||||
|
||||
if let Some(base_fee_per_gas) = header.base_fee_per_gas {
|
||||
let transaction = TransactionSigned {
|
||||
transaction: reth_primitives::Transaction::Eip1559(
|
||||
reth_primitives::TxEip1559 {
|
||||
max_priority_fee_per_gas: random_fee,
|
||||
max_fee_per_gas: random_fee + base_fee_per_gas as u128,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
transactions.push(transaction);
|
||||
} else {
|
||||
let transaction = TransactionSigned {
|
||||
transaction: reth_primitives::Transaction::Legacy(Default::default()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
transactions.push(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
mock_provider.add_block(
|
||||
hash,
|
||||
Block { header: header.clone(), body: transactions, ..Default::default() },
|
||||
);
|
||||
mock_provider.add_header(hash, header);
|
||||
|
||||
oldest_block.get_or_insert(hash);
|
||||
gas_used_ratios.push(gas_used as f64 / gas_limit as f64);
|
||||
base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default());
|
||||
}
|
||||
|
||||
// Add final base fee (for the next block outside of the request)
|
||||
let last_header = last_header.unwrap();
|
||||
base_fees_per_gas.push(BaseFeeParams::ethereum().next_block_base_fee(
|
||||
last_header.gas_used as u128,
|
||||
last_header.gas_limit as u128,
|
||||
last_header.base_fee_per_gas.unwrap_or_default() as u128,
|
||||
));
|
||||
|
||||
let eth_api = build_test_eth_api(mock_provider);
|
||||
|
||||
(eth_api, base_fees_per_gas, gas_used_ratios)
|
||||
}
|
||||
|
||||
/// Invalid block range
|
||||
#[tokio::test]
|
||||
async fn test_fee_history_empty() {
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
&build_test_eth_api(NoopProvider::default()),
|
||||
U64::from(1),
|
||||
BlockNumberOrTag::Latest,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
assert!(response.is_err());
|
||||
let error_object = response.unwrap_err();
|
||||
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Invalid block range (request is before genesis)
|
||||
async fn test_fee_history_invalid_block_range_before_genesis() {
|
||||
let block_count = 10;
|
||||
let newest_block = 1337;
|
||||
let oldest_block = None;
|
||||
|
||||
let (eth_api, _, _) =
|
||||
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
|
||||
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
ð_api,
|
||||
U64::from(newest_block + 1),
|
||||
newest_block.into(),
|
||||
Some(vec![10.0]),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(response.is_err());
|
||||
let error_object = response.unwrap_err();
|
||||
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Invalid block range (request is in the future)
|
||||
async fn test_fee_history_invalid_block_range_in_future() {
|
||||
let block_count = 10;
|
||||
let newest_block = 1337;
|
||||
let oldest_block = None;
|
||||
|
||||
let (eth_api, _, _) =
|
||||
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
|
||||
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
ð_api,
|
||||
U64::from(1),
|
||||
(newest_block + 1000).into(),
|
||||
Some(vec![10.0]),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(response.is_err());
|
||||
let error_object = response.unwrap_err();
|
||||
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Requesting no block should result in a default response
|
||||
async fn test_fee_history_no_block_requested() {
|
||||
let block_count = 10;
|
||||
let newest_block = 1337;
|
||||
let oldest_block = None;
|
||||
|
||||
let (eth_api, _, _) =
|
||||
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
|
||||
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
ð_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"
|
||||
);
|
||||
}
|
||||
}
|
||||
727
crates/rpc/rpc-eth-api/src/core.rs
Normal file
727
crates/rpc/rpc-eth-api/src/core.rs
Normal file
@ -0,0 +1,727 @@
|
||||
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`] trait. Handles RPC requests for
|
||||
//! the `eth_` namespace.
|
||||
|
||||
use alloy_dyn_abi::TypedData;
|
||||
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
|
||||
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
|
||||
use reth_rpc_eth_types::EthApiError;
|
||||
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
|
||||
use reth_rpc_types::{
|
||||
serde_helpers::JsonStorageKey,
|
||||
state::{EvmOverrides, StateOverride},
|
||||
AccessListWithGasUsed, AnyTransactionReceipt, BlockOverrides, Bundle,
|
||||
EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, Index, RichBlock,
|
||||
StateContext, SyncStatus, Transaction, TransactionRequest, Work,
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::helpers::{
|
||||
EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadReceipt, Trace,
|
||||
};
|
||||
|
||||
/// Eth rpc interface: <https://ethereum.github.io/execution-apis/api-documentation/>
|
||||
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
|
||||
#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
|
||||
pub trait EthApi {
|
||||
/// Returns the protocol version encoded as a string.
|
||||
#[method(name = "protocolVersion")]
|
||||
async fn protocol_version(&self) -> RpcResult<U64>;
|
||||
|
||||
/// Returns an object with data about the sync status or false.
|
||||
#[method(name = "syncing")]
|
||||
fn syncing(&self) -> RpcResult<SyncStatus>;
|
||||
|
||||
/// Returns the client coinbase address.
|
||||
#[method(name = "coinbase")]
|
||||
async fn author(&self) -> RpcResult<Address>;
|
||||
|
||||
/// Returns a list of addresses owned by client.
|
||||
#[method(name = "accounts")]
|
||||
fn accounts(&self) -> RpcResult<Vec<Address>>;
|
||||
|
||||
/// Returns the number of most recent block.
|
||||
#[method(name = "blockNumber")]
|
||||
fn block_number(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the chain ID of the current network.
|
||||
#[method(name = "chainId")]
|
||||
async fn chain_id(&self) -> RpcResult<Option<U64>>;
|
||||
|
||||
/// Returns information about a block by hash.
|
||||
#[method(name = "getBlockByHash")]
|
||||
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns information about a block by number.
|
||||
#[method(name = "getBlockByNumber")]
|
||||
async fn block_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
full: bool,
|
||||
) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns the number of transactions in a block from a block matching the given block hash.
|
||||
#[method(name = "getBlockTransactionCountByHash")]
|
||||
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns the number of transactions in a block matching the given block number.
|
||||
#[method(name = "getBlockTransactionCountByNumber")]
|
||||
async fn block_transaction_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns the number of uncles in a block from a block matching the given block hash.
|
||||
#[method(name = "getUncleCountByBlockHash")]
|
||||
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns the number of uncles in a block with given block number.
|
||||
#[method(name = "getUncleCountByBlockNumber")]
|
||||
async fn block_uncles_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> RpcResult<Option<U256>>;
|
||||
|
||||
/// Returns all transaction receipts for a given block.
|
||||
#[method(name = "getBlockReceipts")]
|
||||
async fn block_receipts(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> RpcResult<Option<Vec<AnyTransactionReceipt>>>;
|
||||
|
||||
/// Returns an uncle block of the given block and index.
|
||||
#[method(name = "getUncleByBlockHashAndIndex")]
|
||||
async fn uncle_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns an uncle block of the given block and index.
|
||||
#[method(name = "getUncleByBlockNumberAndIndex")]
|
||||
async fn uncle_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<RichBlock>>;
|
||||
|
||||
/// Returns the EIP-2718 encoded transaction if it exists.
|
||||
///
|
||||
/// If this is a EIP-4844 transaction that is in the pool it will include the sidecar.
|
||||
#[method(name = "getRawTransactionByHash")]
|
||||
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>>;
|
||||
|
||||
/// Returns the information about a transaction requested by transaction hash.
|
||||
#[method(name = "getTransactionByHash")]
|
||||
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Transaction>>;
|
||||
|
||||
/// Returns information about a raw transaction by block hash and transaction index position.
|
||||
#[method(name = "getRawTransactionByBlockHashAndIndex")]
|
||||
async fn raw_transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Bytes>>;
|
||||
|
||||
/// Returns information about a transaction by block hash and transaction index position.
|
||||
#[method(name = "getTransactionByBlockHashAndIndex")]
|
||||
async fn transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Transaction>>;
|
||||
|
||||
/// Returns information about a raw transaction by block number and transaction index
|
||||
/// position.
|
||||
#[method(name = "getRawTransactionByBlockNumberAndIndex")]
|
||||
async fn raw_transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Bytes>>;
|
||||
|
||||
/// Returns information about a transaction by block number and transaction index position.
|
||||
#[method(name = "getTransactionByBlockNumberAndIndex")]
|
||||
async fn transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Transaction>>;
|
||||
|
||||
/// Returns the receipt of a transaction by transaction hash.
|
||||
#[method(name = "getTransactionReceipt")]
|
||||
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<AnyTransactionReceipt>>;
|
||||
|
||||
/// Returns the balance of the account of given address.
|
||||
#[method(name = "getBalance")]
|
||||
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the value from a storage position at a given address
|
||||
#[method(name = "getStorageAt")]
|
||||
async fn storage_at(
|
||||
&self,
|
||||
address: Address,
|
||||
index: JsonStorageKey,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<B256>;
|
||||
|
||||
/// Returns the number of transactions sent from an address at given block number.
|
||||
#[method(name = "getTransactionCount")]
|
||||
async fn transaction_count(
|
||||
&self,
|
||||
address: Address,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<U256>;
|
||||
|
||||
/// Returns code at a given address at given block number.
|
||||
#[method(name = "getCode")]
|
||||
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes>;
|
||||
|
||||
/// Returns the block's header at given number.
|
||||
#[method(name = "getHeaderByNumber")]
|
||||
async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult<Option<Header>>;
|
||||
|
||||
/// Returns the block's header at given hash.
|
||||
#[method(name = "getHeaderByHash")]
|
||||
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<Header>>;
|
||||
|
||||
/// Executes a new message call immediately without creating a transaction on the block chain.
|
||||
#[method(name = "call")]
|
||||
async fn call(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
block_overrides: Option<Box<BlockOverrides>>,
|
||||
) -> RpcResult<Bytes>;
|
||||
|
||||
/// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the
|
||||
/// optionality of state overrides
|
||||
#[method(name = "callMany")]
|
||||
async fn call_many(
|
||||
&self,
|
||||
bundle: Bundle,
|
||||
state_context: Option<StateContext>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> RpcResult<Vec<EthCallResponse>>;
|
||||
|
||||
/// Generates an access list for a transaction.
|
||||
///
|
||||
/// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction.
|
||||
///
|
||||
/// An access list contains all storage slots and addresses touched by the transaction, except
|
||||
/// for the sender account and the chain's precompiles.
|
||||
///
|
||||
/// It returns list of addresses and storage keys used by the transaction, plus the gas
|
||||
/// consumed when the access list is added. That is, it gives you the list of addresses and
|
||||
/// storage keys that will be used by that transaction, plus the gas consumed if the access
|
||||
/// list is included. Like eth_estimateGas, this is an estimation; the list could change
|
||||
/// when the transaction is actually mined. Adding an accessList to your transaction does
|
||||
/// not necessary result in lower gas usage compared to a transaction without an access
|
||||
/// list.
|
||||
#[method(name = "createAccessList")]
|
||||
async fn create_access_list(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<AccessListWithGasUsed>;
|
||||
|
||||
/// Generates and returns an estimate of how much gas is necessary to allow the transaction to
|
||||
/// complete.
|
||||
#[method(name = "estimateGas")]
|
||||
async fn estimate_gas(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the current price per gas in wei.
|
||||
#[method(name = "gasPrice")]
|
||||
async fn gas_price(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions.
|
||||
#[method(name = "maxPriorityFeePerGas")]
|
||||
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Introduced in EIP-4844, returns the current blob base fee in wei.
|
||||
#[method(name = "blobBaseFee")]
|
||||
async fn blob_base_fee(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the Transaction fee history
|
||||
///
|
||||
/// Introduced in EIP-1559 for getting information on the appropriate priority fee to use.
|
||||
///
|
||||
/// Returns transaction base fee per gas and effective priority fee per gas for the
|
||||
/// requested/supported block range. The returned Fee history for the returned block range
|
||||
/// can be a subsection of the requested range if not all blocks are available.
|
||||
#[method(name = "feeHistory")]
|
||||
async fn fee_history(
|
||||
&self,
|
||||
block_count: U64,
|
||||
newest_block: BlockNumberOrTag,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> RpcResult<FeeHistory>;
|
||||
|
||||
/// Returns whether the client is actively mining new blocks.
|
||||
#[method(name = "mining")]
|
||||
async fn is_mining(&self) -> RpcResult<bool>;
|
||||
|
||||
/// Returns the number of hashes per second that the node is mining with.
|
||||
#[method(name = "hashrate")]
|
||||
async fn hashrate(&self) -> RpcResult<U256>;
|
||||
|
||||
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met
|
||||
/// (“target”)
|
||||
#[method(name = "getWork")]
|
||||
async fn get_work(&self) -> RpcResult<Work>;
|
||||
|
||||
/// Used for submitting mining hashrate.
|
||||
///
|
||||
/// Can be used for remote miners to submit their hash rate.
|
||||
/// It accepts the miner hash rate and an identifier which must be unique between nodes.
|
||||
/// Returns `true` if the block was successfully submitted, `false` otherwise.
|
||||
#[method(name = "submitHashrate")]
|
||||
async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult<bool>;
|
||||
|
||||
/// Used for submitting a proof-of-work solution.
|
||||
#[method(name = "submitWork")]
|
||||
async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult<bool>;
|
||||
|
||||
/// Sends transaction; will block waiting for signer to return the
|
||||
/// transaction hash.
|
||||
#[method(name = "sendTransaction")]
|
||||
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256>;
|
||||
|
||||
/// Sends signed transaction, returning its hash.
|
||||
#[method(name = "sendRawTransaction")]
|
||||
async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
|
||||
|
||||
/// Returns an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n"
|
||||
/// + len(message) + message))).
|
||||
#[method(name = "sign")]
|
||||
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes>;
|
||||
|
||||
/// Signs a transaction that can be submitted to the network at a later time using with
|
||||
/// `sendRawTransaction.`
|
||||
#[method(name = "signTransaction")]
|
||||
async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult<Bytes>;
|
||||
|
||||
/// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
|
||||
#[method(name = "signTypedData")]
|
||||
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes>;
|
||||
|
||||
/// Returns the account and storage values of the specified account including the Merkle-proof.
|
||||
/// This call can be used to verify that the data you are pulling from is not tampered with.
|
||||
#[method(name = "getProof")]
|
||||
async fn get_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
keys: Vec<JsonStorageKey>,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<EIP1186AccountProofResponse>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T> EthApiServer for T
|
||||
where
|
||||
Self: EthApiSpec
|
||||
+ EthTransactions
|
||||
+ EthBlocks
|
||||
+ EthState
|
||||
+ EthCall
|
||||
+ EthFees
|
||||
+ Trace
|
||||
+ LoadReceipt,
|
||||
{
|
||||
/// Handler for: `eth_protocolVersion`
|
||||
async fn protocol_version(&self) -> RpcResult<U64> {
|
||||
trace!(target: "rpc::eth", "Serving eth_protocolVersion");
|
||||
EthApiSpec::protocol_version(self).await.to_rpc_result()
|
||||
}
|
||||
|
||||
/// Handler for: `eth_syncing`
|
||||
fn syncing(&self) -> RpcResult<SyncStatus> {
|
||||
trace!(target: "rpc::eth", "Serving eth_syncing");
|
||||
EthApiSpec::sync_status(self).to_rpc_result()
|
||||
}
|
||||
|
||||
/// Handler for: `eth_coinbase`
|
||||
async fn author(&self) -> RpcResult<Address> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_accounts`
|
||||
fn accounts(&self) -> RpcResult<Vec<Address>> {
|
||||
trace!(target: "rpc::eth", "Serving eth_accounts");
|
||||
Ok(EthApiSpec::accounts(self))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_blockNumber`
|
||||
fn block_number(&self) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_blockNumber");
|
||||
Ok(U256::from(
|
||||
EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number,
|
||||
))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_chainId`
|
||||
async fn chain_id(&self) -> RpcResult<Option<U64>> {
|
||||
trace!(target: "rpc::eth", "Serving eth_chainId");
|
||||
Ok(Some(EthApiSpec::chain_id(self)))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockByHash`
|
||||
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash");
|
||||
Ok(EthBlocks::rpc_block(self, hash.into(), full).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockByNumber`
|
||||
async fn block_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
full: bool,
|
||||
) -> RpcResult<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber");
|
||||
Ok(EthBlocks::rpc_block(self, number.into(), full).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockTransactionCountByHash`
|
||||
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash");
|
||||
Ok(EthBlocks::block_transaction_count(self, hash.into()).await?.map(U256::from))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockTransactionCountByNumber`
|
||||
async fn block_transaction_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> RpcResult<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber");
|
||||
Ok(EthBlocks::block_transaction_count(self, number.into()).await?.map(U256::from))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleCountByBlockHash`
|
||||
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash");
|
||||
Ok(EthBlocks::ommers(self, hash.into())?.map(|ommers| U256::from(ommers.len())))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleCountByBlockNumber`
|
||||
async fn block_uncles_count_by_number(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
) -> RpcResult<Option<U256>> {
|
||||
trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber");
|
||||
Ok(EthBlocks::ommers(self, number.into())?.map(|ommers| U256::from(ommers.len())))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBlockReceipts`
|
||||
async fn block_receipts(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> RpcResult<Option<Vec<AnyTransactionReceipt>>> {
|
||||
trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts");
|
||||
Ok(EthBlocks::block_receipts(self, block_id).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleByBlockHashAndIndex`
|
||||
async fn uncle_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex");
|
||||
Ok(EthBlocks::ommer_by_block_and_index(self, hash.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getUncleByBlockNumberAndIndex`
|
||||
async fn uncle_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<RichBlock>> {
|
||||
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex");
|
||||
Ok(EthBlocks::ommer_by_block_and_index(self, number.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getRawTransactionByHash`
|
||||
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash");
|
||||
Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByHash`
|
||||
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Transaction>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash");
|
||||
Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getRawTransactionByBlockHashAndIndex`
|
||||
async fn raw_transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Bytes>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex");
|
||||
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByBlockHashAndIndex`
|
||||
async fn transaction_by_block_hash_and_index(
|
||||
&self,
|
||||
hash: B256,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<reth_rpc_types::Transaction>> {
|
||||
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex");
|
||||
Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getRawTransactionByBlockNumberAndIndex`
|
||||
async fn raw_transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<Bytes>> {
|
||||
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex");
|
||||
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, number.into(), index)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByBlockNumberAndIndex`
|
||||
async fn transaction_by_block_number_and_index(
|
||||
&self,
|
||||
number: BlockNumberOrTag,
|
||||
index: Index,
|
||||
) -> RpcResult<Option<reth_rpc_types::Transaction>> {
|
||||
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex");
|
||||
Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionReceipt`
|
||||
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<AnyTransactionReceipt>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt");
|
||||
Ok(EthTransactions::transaction_receipt(self, hash).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getBalance`
|
||||
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance");
|
||||
Ok(EthState::balance(self, address, block_number).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getStorageAt`
|
||||
async fn storage_at(
|
||||
&self,
|
||||
address: Address,
|
||||
index: JsonStorageKey,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<B256> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt");
|
||||
let res: B256 = EthState::storage_at(self, address, index, block_number).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionCount`
|
||||
async fn transaction_count(
|
||||
&self,
|
||||
address: Address,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount");
|
||||
Ok(EthState::transaction_count(self, address, block_number).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getCode`
|
||||
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes> {
|
||||
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode");
|
||||
Ok(EthState::get_code(self, address, block_number).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getHeaderByNumber`
|
||||
async fn header_by_number(&self, block_number: BlockNumberOrTag) -> RpcResult<Option<Header>> {
|
||||
trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber");
|
||||
Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getHeaderByHash`
|
||||
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<Header>> {
|
||||
trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash");
|
||||
Ok(EthBlocks::rpc_block_header(self, hash.into()).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_call`
|
||||
async fn call(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
block_overrides: Option<Box<BlockOverrides>>,
|
||||
) -> RpcResult<Bytes> {
|
||||
trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call");
|
||||
Ok(EthCall::call(
|
||||
self,
|
||||
request,
|
||||
block_number,
|
||||
EvmOverrides::new(state_overrides, block_overrides),
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_callMany`
|
||||
async fn call_many(
|
||||
&self,
|
||||
bundle: Bundle,
|
||||
state_context: Option<StateContext>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> RpcResult<Vec<EthCallResponse>> {
|
||||
trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany");
|
||||
Ok(EthCall::call_many(self, bundle, state_context, state_override).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_createAccessList`
|
||||
async fn create_access_list(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<AccessListWithGasUsed> {
|
||||
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList");
|
||||
let access_list_with_gas_used =
|
||||
EthCall::create_access_list_at(self, request, block_number).await?;
|
||||
|
||||
Ok(access_list_with_gas_used)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_estimateGas`
|
||||
async fn estimate_gas(
|
||||
&self,
|
||||
request: TransactionRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_override: Option<StateOverride>,
|
||||
) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas");
|
||||
Ok(EthCall::estimate_gas_at(
|
||||
self,
|
||||
request,
|
||||
block_number.unwrap_or_default(),
|
||||
state_override,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_gasPrice`
|
||||
async fn gas_price(&self) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_gasPrice");
|
||||
return Ok(EthFees::gas_price(self).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_maxPriorityFeePerGas`
|
||||
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas");
|
||||
return Ok(EthFees::suggested_priority_fee(self).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_blobBaseFee`
|
||||
async fn blob_base_fee(&self) -> RpcResult<U256> {
|
||||
trace!(target: "rpc::eth", "Serving eth_blobBaseFee");
|
||||
return Ok(EthFees::blob_base_fee(self).await?)
|
||||
}
|
||||
|
||||
// FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further
|
||||
// caching of it in the LRU cache.
|
||||
// When new RPC call is executed, the cache gets locked, we check it for the historical fees
|
||||
// according to the requested block range, and fill any cache misses (in both RPC response
|
||||
// and cache itself) with the actual data queried from the database.
|
||||
// To minimize the number of database seeks required to query the missing data, we calculate the
|
||||
// first non-cached block number and last non-cached block number. After that, we query this
|
||||
// range of consecutive blocks from the database.
|
||||
/// Handler for: `eth_feeHistory`
|
||||
async fn fee_history(
|
||||
&self,
|
||||
block_count: U64,
|
||||
newest_block: BlockNumberOrTag,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> RpcResult<FeeHistory> {
|
||||
trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory");
|
||||
return Ok(
|
||||
EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?
|
||||
)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_mining`
|
||||
async fn is_mining(&self) -> RpcResult<bool> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_hashrate`
|
||||
async fn hashrate(&self) -> RpcResult<U256> {
|
||||
Ok(U256::ZERO)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getWork`
|
||||
async fn get_work(&self) -> RpcResult<Work> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_submitHashrate`
|
||||
async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> RpcResult<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_submitWork`
|
||||
async fn submit_work(
|
||||
&self,
|
||||
_nonce: B64,
|
||||
_pow_hash: B256,
|
||||
_mix_digest: B256,
|
||||
) -> RpcResult<bool> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_sendTransaction`
|
||||
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256> {
|
||||
trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction");
|
||||
Ok(EthTransactions::send_transaction(self, request).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_sendRawTransaction`
|
||||
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256> {
|
||||
trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction");
|
||||
Ok(EthTransactions::send_raw_transaction(self, tx).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_sign`
|
||||
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes> {
|
||||
trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign");
|
||||
Ok(EthTransactions::sign(self, address, message).await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_signTransaction`
|
||||
async fn sign_transaction(&self, _transaction: TransactionRequest) -> RpcResult<Bytes> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_signTypedData`
|
||||
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes> {
|
||||
trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData");
|
||||
Ok(EthTransactions::sign_typed_data(self, &data, address)?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getProof`
|
||||
async fn get_proof(
|
||||
&self,
|
||||
address: Address,
|
||||
keys: Vec<JsonStorageKey>,
|
||||
block_number: Option<BlockId>,
|
||||
) -> RpcResult<EIP1186AccountProofResponse> {
|
||||
trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof");
|
||||
let res = EthState::get_proof(self, address, keys, block_number)?.await;
|
||||
|
||||
Ok(res.map_err(|e| match e {
|
||||
EthApiError::InvalidBlockRange => {
|
||||
internal_rpc_err("eth_getProof is unimplemented for historical blocks")
|
||||
}
|
||||
_ => e.into(),
|
||||
})?)
|
||||
}
|
||||
}
|
||||
@ -5,13 +5,11 @@ use std::sync::Arc;
|
||||
use futures::Future;
|
||||
use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta};
|
||||
use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider};
|
||||
use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder};
|
||||
use reth_rpc_types::{AnyTransactionReceipt, Header, Index, RichBlock};
|
||||
use reth_rpc_types_compat::block::{from_block, uncle_block_from_header};
|
||||
|
||||
use crate::{
|
||||
servers::{LoadPendingBlock, LoadReceipt, SpawnBlocking},
|
||||
EthApiError, EthResult, EthStateCache, ReceiptBuilder,
|
||||
};
|
||||
use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking};
|
||||
|
||||
/// Block related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
|
||||
/// `eth_` namespace.
|
||||
@ -64,10 +62,8 @@ pub trait EthBlocks: LoadBlock {
|
||||
/// Returns `None` if the block does not exist
|
||||
fn block_transaction_count(
|
||||
&self,
|
||||
block_id: impl Into<BlockId>,
|
||||
block_id: BlockId,
|
||||
) -> impl Future<Output = EthResult<Option<usize>>> + Send {
|
||||
let block_id = block_id.into();
|
||||
|
||||
async move {
|
||||
if block_id.is_pending() {
|
||||
// Pending block can be fetched directly without need for caching
|
||||
@ -155,11 +151,7 @@ pub trait EthBlocks: LoadBlock {
|
||||
/// Returns uncle headers of given block.
|
||||
///
|
||||
/// Returns an empty vec if there are none.
|
||||
fn ommers(
|
||||
&self,
|
||||
block_id: impl Into<BlockId>,
|
||||
) -> EthResult<Option<Vec<reth_primitives::Header>>> {
|
||||
let block_id = block_id.into();
|
||||
fn ommers(&self, block_id: BlockId) -> EthResult<Option<Vec<reth_primitives::Header>>> {
|
||||
Ok(LoadBlock::provider(self).ommers_by_id(block_id)?)
|
||||
}
|
||||
|
||||
@ -168,11 +160,9 @@ pub trait EthBlocks: LoadBlock {
|
||||
/// Returns `None` if index out of range.
|
||||
fn ommer_by_block_and_index(
|
||||
&self,
|
||||
block_id: impl Into<BlockId>,
|
||||
block_id: BlockId,
|
||||
index: Index,
|
||||
) -> impl Future<Output = EthResult<Option<RichBlock>>> + Send {
|
||||
let block_id = block_id.into();
|
||||
|
||||
async move {
|
||||
let uncles = if block_id.is_pending() {
|
||||
// Pending block can be fetched directly without need for caching
|
||||
54
crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs
Normal file
54
crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs
Normal file
@ -0,0 +1,54 @@
|
||||
//! Spawns a blocking task. CPU heavy tasks are executed with the `rayon` library. IO heavy tasks
|
||||
//! are executed on the `tokio` runtime.
|
||||
|
||||
use futures::Future;
|
||||
use reth_rpc_eth_types::{EthApiError, EthResult};
|
||||
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
/// Executes code on a blocking thread.
|
||||
pub trait SpawnBlocking: Clone + Send + Sync + 'static {
|
||||
/// Returns a handle for spawning IO heavy blocking tasks.
|
||||
///
|
||||
/// Runtime access in default trait method implementations.
|
||||
fn io_task_spawner(&self) -> impl TaskSpawner;
|
||||
|
||||
/// Returns a handle for spawning CPU heavy blocking tasks.
|
||||
///
|
||||
/// Thread pool access in default trait method implementations.
|
||||
fn tracing_task_pool(&self) -> &BlockingTaskPool;
|
||||
|
||||
/// Executes the future on a new blocking task.
|
||||
///
|
||||
/// Note: This is expected for futures that are dominated by blocking IO operations, for tracing
|
||||
/// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing).
|
||||
fn spawn_blocking_io<F, R>(&self, f: F) -> impl Future<Output = EthResult<R>> + Send
|
||||
where
|
||||
F: FnOnce(Self) -> EthResult<R> + Send + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let this = self.clone();
|
||||
self.io_task_spawner().spawn_blocking(Box::pin(async move {
|
||||
let res = async move { f(this) }.await;
|
||||
let _ = tx.send(res);
|
||||
}));
|
||||
|
||||
async move { rx.await.map_err(|_| EthApiError::InternalEthError)? }
|
||||
}
|
||||
|
||||
/// Executes a blocking task on the tracing pool.
|
||||
///
|
||||
/// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon`
|
||||
/// under the hood, for blocking IO futures use [`spawn_blocking`](Self::spawn_blocking_io). See
|
||||
/// <https://ryhl.io/blog/async-what-is-blocking/>.
|
||||
fn spawn_tracing<F, R>(&self, f: F) -> impl Future<Output = EthResult<R>> + Send
|
||||
where
|
||||
F: FnOnce(Self) -> EthResult<R> + Send + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let this = self.clone();
|
||||
let fut = self.tracing_task_pool().spawn(move || f(this));
|
||||
async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? }
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
@ -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.
|
||||
@ -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:
|
||||
@ -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.
|
||||
///
|
||||
@ -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.
|
||||
@ -5,10 +5,9 @@ use std::result;
|
||||
use alloy_dyn_abi::TypedData;
|
||||
use dyn_clone::DynClone;
|
||||
use reth_primitives::{Address, Signature, TransactionSigned};
|
||||
use reth_rpc_eth_types::SignError;
|
||||
use reth_rpc_types::TypedTransactionRequest;
|
||||
|
||||
use crate::SignError;
|
||||
|
||||
/// Result returned by [`EthSigner`] methods.
|
||||
pub type Result<T> = result::Result<T, SignError>;
|
||||
|
||||
@ -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 {
|
||||
@ -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 {
|
||||
@ -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.
|
||||
@ -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;
|
||||
|
||||
68
crates/rpc/rpc-eth-types/Cargo.toml
Normal file
68
crates/rpc/rpc-eth-types/Cargo.toml
Normal file
@ -0,0 +1,68 @@
|
||||
[package]
|
||||
name = "reth-rpc-eth-types"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
description = "Types supporting implementation of 'eth' namespace RPC server API"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
reth-chainspec.workspace = true
|
||||
reth-errors.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-execution-types.workspace = true
|
||||
reth-metrics.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-revm.workspace = true
|
||||
reth-rpc-server-types.workspace = true
|
||||
reth-rpc-types.workspace = true
|
||||
reth-rpc-types-compat.workspace = true
|
||||
reth-tasks.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
reth-trie.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-sol-types.workspace = true
|
||||
revm.workspace = true
|
||||
revm-inspectors = { workspace = true, features = ["js-tracer"] }
|
||||
revm-primitives = { workspace = true, features = ["dev"] }
|
||||
|
||||
# rpc
|
||||
jsonrpsee-core.workspace = true
|
||||
jsonrpsee-types.workspace = true
|
||||
|
||||
# async
|
||||
futures.workspace = true
|
||||
tokio.workspace = true
|
||||
tokio-stream.workspace = true
|
||||
|
||||
# metrics
|
||||
metrics.workspace = true
|
||||
|
||||
# misc
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror.workspace = true
|
||||
derive_more.workspace = true
|
||||
schnellru.workspace = true
|
||||
rand.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"reth-primitives/optimism",
|
||||
"reth-provider/optimism",
|
||||
"reth-revm/optimism",
|
||||
"reth-chainspec/optimism",
|
||||
"reth-execution-types/optimism",
|
||||
"reth-revm/optimism",
|
||||
"revm/optimism"
|
||||
]
|
||||
@ -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 {
|
||||
@ -1,6 +1,6 @@
|
||||
//! Helper types to workaround 'higher-ranked lifetime error'
|
||||
//! <https://github.com/rust-lang/rust/issues/100013> in default implementation of
|
||||
//! [`Call`](crate::servers::Call).
|
||||
//! `reth_rpc_eth_api::helpers::Call`.
|
||||
|
||||
use reth_primitives::{B256, U256};
|
||||
use reth_provider::StateProvider;
|
||||
@ -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<
|
||||
@ -1,14 +1,16 @@
|
||||
//! Metered cache, which also provides storage for senders in order to queue queries that result in
|
||||
//! a cache miss.
|
||||
|
||||
use super::metrics::CacheMetrics;
|
||||
use schnellru::{ByLength, Limiter, LruMap};
|
||||
use std::{
|
||||
collections::{hash_map::Entry, HashMap},
|
||||
fmt::{self, Debug, Formatter},
|
||||
hash::Hash,
|
||||
};
|
||||
|
||||
use schnellru::{ByLength, Limiter, LruMap};
|
||||
|
||||
use super::metrics::CacheMetrics;
|
||||
|
||||
/// A multi-consumer LRU cache.
|
||||
pub struct MultiConsumerLruCache<K, V, L, S>
|
||||
where
|
||||
@ -1,10 +1,13 @@
|
||||
//! Implementation specific Errors for the `eth_` namespace.
|
||||
|
||||
use crate::result::{internal_rpc_err, invalid_params_rpc_err, rpc_err, rpc_error_with_code};
|
||||
use std::time::Duration;
|
||||
|
||||
use alloy_sol_types::decode_revert_reason;
|
||||
use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObject};
|
||||
use reth_errors::RethError;
|
||||
use reth_primitives::{revm_primitives::InvalidHeader, Address, Bytes};
|
||||
use reth_rpc_server_types::result::{
|
||||
internal_rpc_err, invalid_params_rpc_err, rpc_err, rpc_error_with_code,
|
||||
};
|
||||
use reth_rpc_types::{
|
||||
error::EthRpcErrorCode, request::TransactionInputError, BlockError, ToRpcError,
|
||||
};
|
||||
@ -14,7 +17,6 @@ use reth_transaction_pool::error::{
|
||||
};
|
||||
use revm::primitives::{EVMError, ExecutionResult, HaltReason, OutOfGasError};
|
||||
use revm_inspectors::tracing::{js::JsInspectorError, MuxError};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Result alias
|
||||
pub type EthResult<T> = Result<T, EthApiError>;
|
||||
@ -134,7 +136,7 @@ impl EthApiError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EthApiError> for ErrorObject<'static> {
|
||||
impl From<EthApiError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
fn from(error: EthApiError) -> Self {
|
||||
match error {
|
||||
EthApiError::FailedToDecodeSignedTransaction |
|
||||
@ -165,9 +167,10 @@ impl From<EthApiError> for ErrorObject<'static> {
|
||||
EthApiError::Unsupported(msg) => internal_rpc_err(msg),
|
||||
EthApiError::InternalJsTracerError(msg) => internal_rpc_err(msg),
|
||||
EthApiError::InvalidParams(msg) => invalid_params_rpc_err(msg),
|
||||
err @ EthApiError::ExecutionTimedOut(_) => {
|
||||
rpc_error_with_code(CALL_EXECUTION_FAILED_CODE, err.to_string())
|
||||
}
|
||||
err @ EthApiError::ExecutionTimedOut(_) => rpc_error_with_code(
|
||||
jsonrpsee_types::error::CALL_EXECUTION_FAILED_CODE,
|
||||
err.to_string(),
|
||||
),
|
||||
err @ EthApiError::InternalBlockingTaskError | err @ EthApiError::InternalEthError => {
|
||||
internal_rpc_err(err.to_string())
|
||||
}
|
||||
@ -386,7 +389,7 @@ impl RpcInvalidTransactionError {
|
||||
/// Converts the halt error
|
||||
///
|
||||
/// Takes the configured gas limit of the transaction which is attached to the error
|
||||
pub(crate) const fn halt(reason: HaltReason, gas_limit: u64) -> Self {
|
||||
pub const fn halt(reason: HaltReason, gas_limit: u64) -> Self {
|
||||
match reason {
|
||||
HaltReason::OutOfGas(err) => Self::out_of_gas(err, gas_limit),
|
||||
HaltReason::NonceOverflow => Self::NonceMaxValue,
|
||||
@ -395,7 +398,7 @@ impl RpcInvalidTransactionError {
|
||||
}
|
||||
|
||||
/// Converts the out of gas error
|
||||
pub(crate) const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self {
|
||||
pub const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self {
|
||||
match reason {
|
||||
OutOfGasError::Basic => Self::BasicOutOfGas(gas_limit),
|
||||
OutOfGasError::Memory | OutOfGasError::MemoryLimit => Self::MemoryOutOfGas(gas_limit),
|
||||
@ -405,7 +408,7 @@ impl RpcInvalidTransactionError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RpcInvalidTransactionError> for ErrorObject<'static> {
|
||||
impl From<RpcInvalidTransactionError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
fn from(err: RpcInvalidTransactionError) -> Self {
|
||||
match err {
|
||||
RpcInvalidTransactionError::Revert(revert) => {
|
||||
@ -580,7 +583,7 @@ pub enum RpcPoolError {
|
||||
Other(Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
impl From<RpcPoolError> for ErrorObject<'static> {
|
||||
impl From<RpcPoolError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
fn from(error: RpcPoolError) -> Self {
|
||||
match error {
|
||||
RpcPoolError::Invalid(err) => err.into(),
|
||||
@ -655,7 +658,7 @@ pub enum SignError {
|
||||
|
||||
/// Converts the evm [`ExecutionResult`] into a result where `Ok` variant is the output bytes if it
|
||||
/// is [`ExecutionResult::Success`].
|
||||
pub(crate) fn ensure_success(result: ExecutionResult) -> EthResult<Bytes> {
|
||||
pub fn ensure_success(result: ExecutionResult) -> EthResult<Bytes> {
|
||||
match result {
|
||||
ExecutionResult::Success { output, .. } => Ok(output.into_data()),
|
||||
ExecutionResult::Revert { output, .. } => {
|
||||
@ -18,12 +18,13 @@ use reth_primitives::{
|
||||
Receipt, SealedBlock, TransactionSigned, B256,
|
||||
};
|
||||
use reth_provider::{BlockReaderIdExt, CanonStateNotification, ChainSpecProvider};
|
||||
use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY;
|
||||
use reth_rpc_types::TxGasAndReward;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{EthApiError, EthStateCache};
|
||||
use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY;
|
||||
|
||||
use super::{EthApiError, EthStateCache};
|
||||
|
||||
/// Contains cached fee history entries for blocks.
|
||||
///
|
||||
@ -265,7 +266,7 @@ pub async fn fee_history_cache_new_blocks_task<St, Provider>(
|
||||
/// the corresponding rewards for the transactions at each percentile.
|
||||
///
|
||||
/// The results are returned as a vector of U256 values.
|
||||
pub(crate) fn calculate_reward_percentiles_for_block(
|
||||
pub fn calculate_reward_percentiles_for_block(
|
||||
percentiles: &[f64],
|
||||
gas_used: u64,
|
||||
base_fee_per_gas: u64,
|
||||
@ -3,30 +3,25 @@
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut, From, Into};
|
||||
use reth_primitives::{constants::GWEI_TO_WEI, BlockNumberOrTag, B256, U256};
|
||||
use reth_provider::BlockReaderIdExt;
|
||||
use reth_rpc_server_types::constants::gas_oracle::*;
|
||||
use reth_rpc_server_types::constants;
|
||||
use schnellru::{ByLength, LruMap};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError};
|
||||
use reth_rpc_server_types::constants::gas_oracle::{
|
||||
DEFAULT_GAS_PRICE_BLOCKS, DEFAULT_GAS_PRICE_PERCENTILE, DEFAULT_IGNORE_GAS_PRICE,
|
||||
DEFAULT_MAX_GAS_PRICE, MAX_HEADER_HISTORY, SAMPLE_NUMBER,
|
||||
};
|
||||
|
||||
/// The default gas limit for `eth_call` and adjacent calls.
|
||||
///
|
||||
/// This is different from the default to regular 30M block gas limit
|
||||
/// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow for
|
||||
/// more complex calls.
|
||||
pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(50_000_000);
|
||||
use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError};
|
||||
|
||||
/// Gas per transaction not creating a contract.
|
||||
pub const MIN_TRANSACTION_GAS: u64 = 21_000u64;
|
||||
/// Allowed error ratio for gas estimation
|
||||
/// Taken from Geth's implementation in order to pass the hive tests
|
||||
/// <https://github.com/ethereum/go-ethereum/blob/a5a4fa7032bb248f5a7c40f4e8df2b131c4186a4/internal/ethapi/api.go#L56>
|
||||
pub const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015;
|
||||
/// The default gas limit for `eth_call` and adjacent calls. See
|
||||
/// [`RPC_DEFAULT_GAS_CAP`](constants::gas_oracle::RPC_DEFAULT_GAS_CAP).
|
||||
pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(constants::gas_oracle::RPC_DEFAULT_GAS_CAP);
|
||||
|
||||
/// Settings for the [`GasPriceOracle`]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
@ -300,8 +295,8 @@ impl Default for GasPriceOracleResult {
|
||||
}
|
||||
|
||||
/// The wrapper type for gas limit
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct GasCap(u64);
|
||||
#[derive(Debug, Clone, Copy, From, Into)]
|
||||
pub struct GasCap(pub u64);
|
||||
|
||||
impl Default for GasCap {
|
||||
fn default() -> Self {
|
||||
@ -309,18 +304,6 @@ impl Default for GasCap {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for GasCap {
|
||||
fn from(gas_cap: u64) -> Self {
|
||||
Self(gas_cap)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GasCap> for u64 {
|
||||
fn from(gas_cap: GasCap) -> Self {
|
||||
gas_cap.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -1,19 +1,19 @@
|
||||
//! Helper type for [`EthPubSubApiServer`](crate::EthPubSubApiServer) implementation.
|
||||
//! Helper type for `reth_rpc_eth_api::EthPubSubApiServer` implementation.
|
||||
//!
|
||||
//! Generates IDs for tracking subscriptions.
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use jsonrpsee::types::SubscriptionId;
|
||||
use jsonrpsee_types::SubscriptionId;
|
||||
|
||||
/// An [`IdProvider`](jsonrpsee::core::traits::IdProvider) for ethereum subscription ids.
|
||||
/// An [`IdProvider`](jsonrpsee_core::traits::IdProvider) for ethereum subscription ids.
|
||||
///
|
||||
/// Returns new hex-string [QUANTITY](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding) ids
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct EthSubscriptionIdProvider;
|
||||
|
||||
impl jsonrpsee::core::traits::IdProvider for EthSubscriptionIdProvider {
|
||||
impl jsonrpsee_core::traits::IdProvider for EthSubscriptionIdProvider {
|
||||
fn next_id(&self) -> SubscriptionId<'static> {
|
||||
to_quantity(rand::random::<u128>())
|
||||
}
|
||||
34
crates/rpc/rpc-eth-types/src/lib.rs
Normal file
34
crates/rpc/rpc-eth-types/src/lib.rs
Normal file
@ -0,0 +1,34 @@
|
||||
//! Reth RPC server types, used in server implementation of `eth` namespace API.
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
|
||||
pub mod cache;
|
||||
pub mod error;
|
||||
pub mod fee_history;
|
||||
pub mod gas_oracle;
|
||||
pub mod id_provider;
|
||||
pub mod logs_utils;
|
||||
pub mod pending_block;
|
||||
pub mod receipt;
|
||||
pub mod revm_utils;
|
||||
pub mod transaction;
|
||||
pub mod utils;
|
||||
|
||||
pub use cache::{
|
||||
config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache,
|
||||
EthStateCache,
|
||||
};
|
||||
pub use error::{EthApiError, EthResult, RevertError, RpcInvalidTransactionError, SignError};
|
||||
pub use fee_history::{FeeHistoryCache, FeeHistoryCacheConfig, FeeHistoryEntry};
|
||||
pub use gas_oracle::{GasCap, GasPriceOracle, GasPriceOracleConfig, GasPriceOracleResult};
|
||||
pub use id_provider::EthSubscriptionIdProvider;
|
||||
pub use logs_utils::EthFilterError;
|
||||
pub use pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin};
|
||||
pub use receipt::ReceiptBuilder;
|
||||
pub use transaction::TransactionSource;
|
||||
@ -1,16 +1,66 @@
|
||||
//! Helper functions for [`EthFilterApiServer`](crate::EthFilterApiServer) implementation.
|
||||
//! Helper functions for `reth_rpc_eth_api::EthFilterApiServer` implementation.
|
||||
//!
|
||||
//! Log parsing for building filter.
|
||||
|
||||
use reth_chainspec::ChainInfo;
|
||||
use reth_primitives::{BlockNumHash, Receipt, TxHash};
|
||||
use reth_provider::{BlockReader, ProviderError};
|
||||
use reth_rpc_types::{FilteredParams, Log};
|
||||
use reth_rpc_server_types::result::rpc_error_with_code;
|
||||
use reth_rpc_types::{FilterId, FilteredParams, Log};
|
||||
|
||||
use crate::servers::filter::EthFilterError;
|
||||
use crate::EthApiError;
|
||||
|
||||
/// Errors that can occur in the handler implementation
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum EthFilterError {
|
||||
/// Filter not found.
|
||||
#[error("filter not found")]
|
||||
FilterNotFound(FilterId),
|
||||
/// Invalid block range.
|
||||
#[error("invalid block range params")]
|
||||
InvalidBlockRangeParams,
|
||||
/// Query scope is too broad.
|
||||
#[error("query exceeds max block range {0}")]
|
||||
QueryExceedsMaxBlocks(u64),
|
||||
/// Query result is too large.
|
||||
#[error("query exceeds max results {0}")]
|
||||
QueryExceedsMaxResults(usize),
|
||||
/// Error serving request in `eth_` namespace.
|
||||
#[error(transparent)]
|
||||
EthAPIError(#[from] EthApiError),
|
||||
/// Error thrown when a spawned task failed to deliver a response.
|
||||
#[error("internal filter error")]
|
||||
InternalError,
|
||||
}
|
||||
|
||||
// convert the error
|
||||
impl From<EthFilterError> for jsonrpsee_types::error::ErrorObject<'static> {
|
||||
fn from(err: EthFilterError) -> Self {
|
||||
match err {
|
||||
EthFilterError::FilterNotFound(_) => {
|
||||
rpc_error_with_code(jsonrpsee_types::error::INVALID_PARAMS_CODE, "filter not found")
|
||||
}
|
||||
err @ EthFilterError::InternalError => {
|
||||
rpc_error_with_code(jsonrpsee_types::error::INTERNAL_ERROR_CODE, err.to_string())
|
||||
}
|
||||
EthFilterError::EthAPIError(err) => err.into(),
|
||||
err @ EthFilterError::InvalidBlockRangeParams |
|
||||
err @ EthFilterError::QueryExceedsMaxBlocks(_) |
|
||||
err @ EthFilterError::QueryExceedsMaxResults(_) => {
|
||||
rpc_error_with_code(jsonrpsee_types::error::INVALID_PARAMS_CODE, err.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProviderError> for EthFilterError {
|
||||
fn from(err: ProviderError) -> Self {
|
||||
Self::EthAPIError(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all matching of a block's receipts when the transaction hashes are known.
|
||||
pub(crate) fn matching_block_logs_with_tx_hashes<'a, I>(
|
||||
pub fn matching_block_logs_with_tx_hashes<'a, I>(
|
||||
filter: &FilteredParams,
|
||||
block_num_hash: BlockNumHash,
|
||||
tx_hashes_and_receipts: I,
|
||||
@ -47,7 +97,7 @@ where
|
||||
|
||||
/// Appends all matching logs of a block's receipts.
|
||||
/// If the log matches, look up the corresponding transaction hash.
|
||||
pub(crate) fn append_matching_block_logs(
|
||||
pub fn append_matching_block_logs(
|
||||
all_logs: &mut Vec<Log>,
|
||||
provider: impl BlockReader,
|
||||
filter: &FilteredParams,
|
||||
@ -114,7 +164,7 @@ pub(crate) fn append_matching_block_logs(
|
||||
}
|
||||
|
||||
/// Returns true if the log matches the filter and should be included
|
||||
pub(crate) fn log_matches_filter(
|
||||
pub fn log_matches_filter(
|
||||
block: BlockNumHash,
|
||||
log: &reth_primitives::Log,
|
||||
params: &FilteredParams,
|
||||
@ -131,7 +181,7 @@ pub(crate) fn log_matches_filter(
|
||||
}
|
||||
|
||||
/// Computes the block range based on the filter range and current block numbers
|
||||
pub(crate) fn get_filter_block_range(
|
||||
pub fn get_filter_block_range(
|
||||
from_block: Option<u64>,
|
||||
to_block: Option<u64>,
|
||||
start_block: u64,
|
||||
@ -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)]
|
||||
@ -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)]
|
||||
@ -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]
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
///
|
||||
@ -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"] }
|
||||
|
||||
|
||||
@ -64,6 +64,20 @@ pub mod gas_oracle {
|
||||
|
||||
/// The default minimum gas price, under which the sample will be ignored
|
||||
pub const DEFAULT_IGNORE_GAS_PRICE: U256 = U256::from_limbs([2u64, 0, 0, 0]);
|
||||
|
||||
/// The default gas limit for `eth_call` and adjacent calls.
|
||||
///
|
||||
/// This is different from the default to regular 30M block gas limit
|
||||
/// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow
|
||||
/// for more complex calls.
|
||||
pub const RPC_DEFAULT_GAS_CAP: u64 = 50_000_000;
|
||||
|
||||
/// Gas per transaction not creating a contract.
|
||||
pub const MIN_TRANSACTION_GAS: u64 = 21_000u64;
|
||||
/// Allowed error ratio for gas estimation
|
||||
/// Taken from Geth's implementation in order to pass the hive tests
|
||||
/// <https://github.com/ethereum/go-ethereum/blob/a5a4fa7032bb248f5a7c40f4e8df2b131c4186a4/internal/ethapi/api.go#L56>
|
||||
pub const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015;
|
||||
}
|
||||
|
||||
/// Cache specific constants
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
/// Common RPC constants.
|
||||
pub mod constants;
|
||||
pub mod result;
|
||||
|
||||
mod module;
|
||||
pub use module::{RethRpcModule, RpcModuleSelection};
|
||||
|
||||
pub use result::ToRpcResult;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use jsonrpsee::core::RpcResult;
|
||||
use jsonrpsee_core::RpcResult;
|
||||
use reth_rpc_types::engine::PayloadError;
|
||||
|
||||
/// Helper trait to easily convert various `Result` types into [`RpcResult`]
|
||||
@ -22,14 +22,14 @@ pub trait ToRpcResult<Ok, Err>: Sized {
|
||||
M: Into<String>;
|
||||
|
||||
/// Converts this type into an [`RpcResult`] with the
|
||||
/// [`jsonrpsee::types::error::INTERNAL_ERROR_CODE` and the given message.
|
||||
/// [`jsonrpsee_types::error::INTERNAL_ERROR_CODE`] and the given message.
|
||||
fn map_internal_err<F, M>(self, op: F) -> RpcResult<Ok>
|
||||
where
|
||||
F: FnOnce(Err) -> M,
|
||||
M: Into<String>;
|
||||
|
||||
/// Converts this type into an [`RpcResult`] with the
|
||||
/// [`jsonrpsee::types::error::INTERNAL_ERROR_CODE`] and given message and data.
|
||||
/// [`jsonrpsee_types::error::INTERNAL_ERROR_CODE`] and given message and data.
|
||||
fn map_internal_err_with_data<'a, F, M>(self, op: F) -> RpcResult<Ok>
|
||||
where
|
||||
F: FnOnce(Err) -> (M, &'a [u8]),
|
||||
@ -47,7 +47,7 @@ macro_rules! impl_to_rpc_result {
|
||||
($err:ty) => {
|
||||
impl<Ok> ToRpcResult<Ok, $err> for Result<Ok, $err> {
|
||||
#[inline]
|
||||
fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult<Ok>
|
||||
fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
|
||||
where
|
||||
F: FnOnce($err) -> (i32, M, Option<&'a [u8]>),
|
||||
M: Into<String>,
|
||||
@ -62,7 +62,7 @@ macro_rules! impl_to_rpc_result {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult<Ok>
|
||||
fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
|
||||
where
|
||||
F: FnOnce($err) -> M,
|
||||
M: Into<String>,
|
||||
@ -71,7 +71,7 @@ macro_rules! impl_to_rpc_result {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult<Ok>
|
||||
fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
|
||||
where
|
||||
F: FnOnce($err) -> (M, &'a [u8]),
|
||||
M: Into<String>,
|
||||
@ -86,7 +86,7 @@ macro_rules! impl_to_rpc_result {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_message(self, msg: &str) -> jsonrpsee::core::RpcResult<Ok> {
|
||||
fn with_message(self, msg: &str) -> jsonrpsee_core::RpcResult<Ok> {
|
||||
match self {
|
||||
Ok(t) => Ok(t),
|
||||
Err(err) => {
|
||||
@ -107,28 +107,28 @@ impl_to_rpc_result!(reth_network_api::NetworkError);
|
||||
/// Constructs an invalid params JSON-RPC error.
|
||||
pub fn invalid_params_rpc_err(
|
||||
msg: impl Into<String>,
|
||||
) -> jsonrpsee::types::error::ErrorObject<'static> {
|
||||
rpc_err(jsonrpsee::types::error::INVALID_PARAMS_CODE, msg, None)
|
||||
) -> jsonrpsee_types::error::ErrorObject<'static> {
|
||||
rpc_err(jsonrpsee_types::error::INVALID_PARAMS_CODE, msg, None)
|
||||
}
|
||||
|
||||
/// Constructs an internal JSON-RPC error.
|
||||
pub fn internal_rpc_err(msg: impl Into<String>) -> jsonrpsee::types::error::ErrorObject<'static> {
|
||||
rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, None)
|
||||
pub fn internal_rpc_err(msg: impl Into<String>) -> jsonrpsee_types::error::ErrorObject<'static> {
|
||||
rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, None)
|
||||
}
|
||||
|
||||
/// Constructs an internal JSON-RPC error with data
|
||||
pub fn internal_rpc_err_with_data(
|
||||
msg: impl Into<String>,
|
||||
data: &[u8],
|
||||
) -> jsonrpsee::types::error::ErrorObject<'static> {
|
||||
rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, Some(data))
|
||||
) -> jsonrpsee_types::error::ErrorObject<'static> {
|
||||
rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, Some(data))
|
||||
}
|
||||
|
||||
/// Constructs an internal JSON-RPC error with code and message
|
||||
pub fn rpc_error_with_code(
|
||||
code: i32,
|
||||
msg: impl Into<String>,
|
||||
) -> jsonrpsee::types::error::ErrorObject<'static> {
|
||||
) -> jsonrpsee_types::error::ErrorObject<'static> {
|
||||
rpc_err(code, msg, None)
|
||||
}
|
||||
|
||||
@ -137,12 +137,12 @@ pub fn rpc_err(
|
||||
code: i32,
|
||||
msg: impl Into<String>,
|
||||
data: Option<&[u8]>,
|
||||
) -> jsonrpsee::types::error::ErrorObject<'static> {
|
||||
jsonrpsee::types::error::ErrorObject::owned(
|
||||
) -> jsonrpsee_types::error::ErrorObject<'static> {
|
||||
jsonrpsee_types::error::ErrorObject::owned(
|
||||
code,
|
||||
msg.into(),
|
||||
data.map(|data| {
|
||||
jsonrpsee::core::to_json_raw_value(&reth_primitives::hex::encode_prefixed(data))
|
||||
jsonrpsee_core::to_json_raw_value(&reth_primitives::hex::encode_prefixed(data))
|
||||
.expect("serializing String can't fail")
|
||||
}),
|
||||
)
|
||||
@ -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"]
|
||||
@ -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",
|
||||
]
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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::{
|
||||
|
||||
@ -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.
|
||||
601
crates/rpc/rpc/src/eth/core.rs
Normal file
601
crates/rpc/rpc/src/eth/core.rs
Normal file
@ -0,0 +1,601 @@
|
||||
//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait
|
||||
//! Handles RPC requests for the `eth_` namespace.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use reth_primitives::{BlockNumberOrTag, U256};
|
||||
use reth_provider::{BlockReaderIdExt, ChainSpecProvider};
|
||||
use reth_rpc_eth_api::{
|
||||
helpers::{EthSigner, SpawnBlocking},
|
||||
RawTransactionForwarder,
|
||||
};
|
||||
use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock};
|
||||
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::eth::DevSigner;
|
||||
|
||||
/// `Eth` API implementation.
|
||||
///
|
||||
/// This type provides the functionality for handling `eth_` related requests.
|
||||
/// These are implemented two-fold: Core functionality is implemented as
|
||||
/// [`EthApiSpec`](reth_rpc_eth_api::helpers::EthApiSpec) trait. Additionally, the required server
|
||||
/// implementations (e.g. [`EthApiServer`](reth_rpc_eth_api::EthApiServer)) are implemented
|
||||
/// separately in submodules. The rpc handler implementation can then delegate to the main impls.
|
||||
/// This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone or in other
|
||||
/// network handlers (for example ipc).
|
||||
pub struct EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
/// All nested fields bundled together.
|
||||
pub(super) inner: Arc<EthApiInner<Provider, Pool, Network, EvmConfig>>,
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
/// Sets a forwarder for `eth_sendRawTransaction`
|
||||
///
|
||||
/// Note: this might be removed in the future in favor of a more generic approach.
|
||||
pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc<dyn RawTransactionForwarder>) {
|
||||
self.inner.raw_transaction_forwarder.write().replace(forwarder);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Provider: BlockReaderIdExt + ChainSpecProvider,
|
||||
{
|
||||
/// Creates a new, shareable instance using the default tokio task spawner.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
eth_cache: EthStateCache,
|
||||
gas_oracle: GasPriceOracle<Provider>,
|
||||
gas_cap: impl Into<GasCap>,
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
evm_config: EvmConfig,
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
) -> Self {
|
||||
Self::with_spawner(
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
eth_cache,
|
||||
gas_oracle,
|
||||
gas_cap.into().into(),
|
||||
Box::<TokioTaskExecutor>::default(),
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
raw_transaction_forwarder,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new, shareable instance.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn with_spawner(
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
eth_cache: EthStateCache,
|
||||
gas_oracle: GasPriceOracle<Provider>,
|
||||
gas_cap: u64,
|
||||
task_spawner: Box<dyn TaskSpawner>,
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
evm_config: EvmConfig,
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
) -> Self {
|
||||
// get the block number of the latest block
|
||||
let latest_block = provider
|
||||
.header_by_number_or_tag(BlockNumberOrTag::Latest)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|header| header.number)
|
||||
.unwrap_or_default();
|
||||
|
||||
let inner = EthApiInner {
|
||||
provider,
|
||||
pool,
|
||||
network,
|
||||
signers: parking_lot::RwLock::new(Default::default()),
|
||||
eth_cache,
|
||||
gas_oracle,
|
||||
gas_cap,
|
||||
starting_block: U256::from(latest_block),
|
||||
task_spawner,
|
||||
pending_block: Default::default(),
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder),
|
||||
};
|
||||
|
||||
Self { inner: Arc::new(inner) }
|
||||
}
|
||||
|
||||
/// Returns the state cache frontend
|
||||
pub fn cache(&self) -> &EthStateCache {
|
||||
&self.inner.eth_cache
|
||||
}
|
||||
|
||||
/// Returns the gas oracle frontend
|
||||
pub fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
|
||||
&self.inner.gas_oracle
|
||||
}
|
||||
|
||||
/// Returns the configured gas limit cap for `eth_call` and tracing related calls
|
||||
pub fn gas_cap(&self) -> u64 {
|
||||
self.inner.gas_cap
|
||||
}
|
||||
|
||||
/// Returns the inner `Provider`
|
||||
pub fn provider(&self) -> &Provider {
|
||||
&self.inner.provider
|
||||
}
|
||||
|
||||
/// Returns the inner `Network`
|
||||
pub fn network(&self) -> &Network {
|
||||
&self.inner.network
|
||||
}
|
||||
|
||||
/// Returns the inner `Pool`
|
||||
pub fn pool(&self) -> &Pool {
|
||||
&self.inner.pool
|
||||
}
|
||||
|
||||
/// Returns fee history cache
|
||||
pub fn fee_history_cache(&self) -> &FeeHistoryCache {
|
||||
&self.inner.fee_history_cache
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> std::fmt::Debug
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EthApi").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> Clone for EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { inner: Arc::clone(&self.inner) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> SpawnBlocking
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
Self: Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner {
|
||||
self.inner.task_spawner()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tracing_task_pool(&self) -> &reth_tasks::pool::BlockingTaskPool {
|
||||
self.inner.blocking_task_pool()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
|
||||
/// Generates 20 random developer accounts.
|
||||
/// Used in DEV mode.
|
||||
pub fn with_dev_accounts(&self) {
|
||||
let mut signers = self.inner.signers.write();
|
||||
*signers = DevSigner::random_signers(20);
|
||||
}
|
||||
}
|
||||
|
||||
/// Container type `EthApi`
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct EthApiInner<Provider, Pool, Network, EvmConfig> {
|
||||
/// The transaction pool.
|
||||
pool: Pool,
|
||||
/// The provider that can interact with the chain.
|
||||
provider: Provider,
|
||||
/// An interface to interact with the network
|
||||
network: Network,
|
||||
/// All configured Signers
|
||||
signers: parking_lot::RwLock<Vec<Box<dyn EthSigner>>>,
|
||||
/// The async cache frontend for eth related data
|
||||
eth_cache: EthStateCache,
|
||||
/// The async gas oracle frontend for gas price suggestions
|
||||
gas_oracle: GasPriceOracle<Provider>,
|
||||
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
|
||||
gas_cap: u64,
|
||||
/// The block number at which the node started
|
||||
starting_block: U256,
|
||||
/// The type that can spawn tasks which would otherwise block.
|
||||
task_spawner: Box<dyn TaskSpawner>,
|
||||
/// Cached pending block if any
|
||||
pending_block: Mutex<Option<PendingBlock>>,
|
||||
/// A pool dedicated to CPU heavy blocking tasks.
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
/// Cache for block fees history
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
/// The type that defines how to configure the EVM
|
||||
evm_config: EvmConfig,
|
||||
/// Allows forwarding received raw transactions
|
||||
raw_transaction_forwarder: parking_lot::RwLock<Option<Arc<dyn RawTransactionForwarder>>>,
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApiInner<Provider, Pool, Network, EvmConfig> {
|
||||
/// Returns a handle to data on disk.
|
||||
#[inline]
|
||||
pub const fn provider(&self) -> &Provider {
|
||||
&self.provider
|
||||
}
|
||||
|
||||
/// Returns a handle to data in memory.
|
||||
#[inline]
|
||||
pub const fn cache(&self) -> &EthStateCache {
|
||||
&self.eth_cache
|
||||
}
|
||||
|
||||
/// Returns a handle to the pending block.
|
||||
#[inline]
|
||||
pub const fn pending_block(&self) -> &Mutex<Option<PendingBlock>> {
|
||||
&self.pending_block
|
||||
}
|
||||
|
||||
/// Returns a handle to the task spawner.
|
||||
#[inline]
|
||||
pub const fn task_spawner(&self) -> &dyn TaskSpawner {
|
||||
&*self.task_spawner
|
||||
}
|
||||
|
||||
/// Returns a handle to the blocking thread pool.
|
||||
#[inline]
|
||||
pub const fn blocking_task_pool(&self) -> &BlockingTaskPool {
|
||||
&self.blocking_task_pool
|
||||
}
|
||||
|
||||
/// Returns a handle to the EVM config.
|
||||
#[inline]
|
||||
pub const fn evm_config(&self) -> &EvmConfig {
|
||||
&self.evm_config
|
||||
}
|
||||
|
||||
/// Returns a handle to the transaction pool.
|
||||
#[inline]
|
||||
pub const fn pool(&self) -> &Pool {
|
||||
&self.pool
|
||||
}
|
||||
|
||||
/// Returns a handle to the transaction forwarder.
|
||||
#[inline]
|
||||
pub fn raw_tx_forwarder(&self) -> Option<Arc<dyn RawTransactionForwarder>> {
|
||||
self.raw_transaction_forwarder.read().clone()
|
||||
}
|
||||
|
||||
/// Returns the gas cap.
|
||||
#[inline]
|
||||
pub const fn gas_cap(&self) -> u64 {
|
||||
self.gas_cap
|
||||
}
|
||||
|
||||
/// Returns a handle to the gas oracle.
|
||||
#[inline]
|
||||
pub const fn gas_oracle(&self) -> &GasPriceOracle<Provider> {
|
||||
&self.gas_oracle
|
||||
}
|
||||
|
||||
/// Returns a handle to the fee history cache.
|
||||
#[inline]
|
||||
pub const fn fee_history_cache(&self) -> &FeeHistoryCache {
|
||||
&self.fee_history_cache
|
||||
}
|
||||
|
||||
/// Returns a handle to the signers.
|
||||
#[inline]
|
||||
pub const fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
|
||||
&self.signers
|
||||
}
|
||||
|
||||
/// Returns the starting block.
|
||||
#[inline]
|
||||
pub const fn starting_block(&self) -> U256 {
|
||||
self.starting_block
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use jsonrpsee_types::error::INVALID_PARAMS_CODE;
|
||||
use reth_chainspec::BaseFeeParams;
|
||||
use reth_evm_ethereum::EthEvmConfig;
|
||||
use reth_network_api::noop::NoopNetwork;
|
||||
use reth_primitives::{
|
||||
constants::ETHEREUM_BLOCK_GAS_LIMIT, Block, BlockNumberOrTag, Header, TransactionSigned,
|
||||
B256, U64,
|
||||
};
|
||||
use reth_provider::{
|
||||
test_utils::{MockEthProvider, NoopProvider},
|
||||
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory,
|
||||
};
|
||||
use reth_rpc_eth_api::EthApiServer;
|
||||
use reth_rpc_eth_types::{
|
||||
EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
|
||||
};
|
||||
use reth_rpc_types::FeeHistory;
|
||||
use reth_tasks::pool::BlockingTaskPool;
|
||||
use reth_testing_utils::{generators, generators::Rng};
|
||||
use reth_transaction_pool::test_utils::{testing_pool, TestPool};
|
||||
|
||||
use crate::EthApi;
|
||||
|
||||
fn build_test_eth_api<
|
||||
P: BlockReaderIdExt
|
||||
+ BlockReader
|
||||
+ ChainSpecProvider
|
||||
+ EvmEnvProvider
|
||||
+ StateProviderFactory
|
||||
+ Unpin
|
||||
+ Clone
|
||||
+ 'static,
|
||||
>(
|
||||
provider: P,
|
||||
) -> EthApi<P, TestPool, NoopNetwork, EthEvmConfig> {
|
||||
let evm_config = EthEvmConfig::default();
|
||||
let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config);
|
||||
let fee_history_cache =
|
||||
FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default());
|
||||
|
||||
EthApi::new(
|
||||
provider.clone(),
|
||||
testing_pool(),
|
||||
NoopNetwork::default(),
|
||||
cache.clone(),
|
||||
GasPriceOracle::new(provider, Default::default(), cache),
|
||||
ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
// Function to prepare the EthApi with mock data
|
||||
fn prepare_eth_api(
|
||||
newest_block: u64,
|
||||
mut oldest_block: Option<B256>,
|
||||
block_count: u64,
|
||||
mock_provider: MockEthProvider,
|
||||
) -> (EthApi<MockEthProvider, TestPool, NoopNetwork, EthEvmConfig>, Vec<u128>, Vec<f64>) {
|
||||
let mut rng = generators::rng();
|
||||
|
||||
// Build mock data
|
||||
let mut gas_used_ratios = Vec::new();
|
||||
let mut base_fees_per_gas = Vec::new();
|
||||
let mut last_header = None;
|
||||
let mut parent_hash = B256::default();
|
||||
|
||||
for i in (0..block_count).rev() {
|
||||
let hash = rng.gen();
|
||||
let gas_limit: u64 = rng.gen();
|
||||
let gas_used: u64 = rng.gen();
|
||||
// Note: Generates a u32 to avoid overflows later
|
||||
let base_fee_per_gas: Option<u64> = rng.gen::<bool>().then(|| rng.gen::<u32>() as u64);
|
||||
|
||||
let header = Header {
|
||||
number: newest_block - i,
|
||||
gas_limit,
|
||||
gas_used,
|
||||
base_fee_per_gas,
|
||||
parent_hash,
|
||||
..Default::default()
|
||||
};
|
||||
last_header = Some(header.clone());
|
||||
parent_hash = hash;
|
||||
|
||||
let mut transactions = vec![];
|
||||
for _ in 0..100 {
|
||||
let random_fee: u128 = rng.gen();
|
||||
|
||||
if let Some(base_fee_per_gas) = header.base_fee_per_gas {
|
||||
let transaction = TransactionSigned {
|
||||
transaction: reth_primitives::Transaction::Eip1559(
|
||||
reth_primitives::TxEip1559 {
|
||||
max_priority_fee_per_gas: random_fee,
|
||||
max_fee_per_gas: random_fee + base_fee_per_gas as u128,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
transactions.push(transaction);
|
||||
} else {
|
||||
let transaction = TransactionSigned {
|
||||
transaction: reth_primitives::Transaction::Legacy(Default::default()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
transactions.push(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
mock_provider.add_block(
|
||||
hash,
|
||||
Block { header: header.clone(), body: transactions, ..Default::default() },
|
||||
);
|
||||
mock_provider.add_header(hash, header);
|
||||
|
||||
oldest_block.get_or_insert(hash);
|
||||
gas_used_ratios.push(gas_used as f64 / gas_limit as f64);
|
||||
base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default());
|
||||
}
|
||||
|
||||
// Add final base fee (for the next block outside of the request)
|
||||
let last_header = last_header.unwrap();
|
||||
base_fees_per_gas.push(BaseFeeParams::ethereum().next_block_base_fee(
|
||||
last_header.gas_used as u128,
|
||||
last_header.gas_limit as u128,
|
||||
last_header.base_fee_per_gas.unwrap_or_default() as u128,
|
||||
));
|
||||
|
||||
let eth_api = build_test_eth_api(mock_provider);
|
||||
|
||||
(eth_api, base_fees_per_gas, gas_used_ratios)
|
||||
}
|
||||
|
||||
/// Invalid block range
|
||||
#[tokio::test]
|
||||
async fn test_fee_history_empty() {
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
&build_test_eth_api(NoopProvider::default()),
|
||||
U64::from(1),
|
||||
BlockNumberOrTag::Latest,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
assert!(response.is_err());
|
||||
let error_object = response.unwrap_err();
|
||||
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Invalid block range (request is before genesis)
|
||||
async fn test_fee_history_invalid_block_range_before_genesis() {
|
||||
let block_count = 10;
|
||||
let newest_block = 1337;
|
||||
let oldest_block = None;
|
||||
|
||||
let (eth_api, _, _) =
|
||||
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
|
||||
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
ð_api,
|
||||
U64::from(newest_block + 1),
|
||||
newest_block.into(),
|
||||
Some(vec![10.0]),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(response.is_err());
|
||||
let error_object = response.unwrap_err();
|
||||
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Invalid block range (request is in the future)
|
||||
async fn test_fee_history_invalid_block_range_in_future() {
|
||||
let block_count = 10;
|
||||
let newest_block = 1337;
|
||||
let oldest_block = None;
|
||||
|
||||
let (eth_api, _, _) =
|
||||
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
|
||||
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
ð_api,
|
||||
U64::from(1),
|
||||
(newest_block + 1000).into(),
|
||||
Some(vec![10.0]),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(response.is_err());
|
||||
let error_object = response.unwrap_err();
|
||||
assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
/// Requesting no block should result in a default response
|
||||
async fn test_fee_history_no_block_requested() {
|
||||
let block_count = 10;
|
||||
let newest_block = 1337;
|
||||
let oldest_block = None;
|
||||
|
||||
let (eth_api, _, _) =
|
||||
prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
|
||||
|
||||
let response = <EthApi<_, _, _, _> as EthApiServer>::fee_history(
|
||||
ð_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"
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,12 @@ use jsonrpsee::{core::RpcResult, server::IdProvider};
|
||||
use reth_chainspec::ChainInfo;
|
||||
use reth_primitives::{IntoRecoveredTransaction, TxHash};
|
||||
use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError};
|
||||
use reth_rpc_eth_api::EthFilterApiServer;
|
||||
use reth_rpc_eth_types::{
|
||||
logs_utils::{self, append_matching_block_logs},
|
||||
EthApiError, EthFilterError, EthStateCache, EthSubscriptionIdProvider,
|
||||
};
|
||||
use reth_rpc_server_types::ToRpcResult;
|
||||
use reth_rpc_types::{
|
||||
BlockNumHash, Filter, FilterBlockOption, FilterChanges, FilterId, FilteredParams, Log,
|
||||
PendingTransactionFilterKind,
|
||||
@ -26,12 +32,6 @@ use tokio::{
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{
|
||||
logs_utils::{self, append_matching_block_logs},
|
||||
result::rpc_error_with_code,
|
||||
EthApiError, EthFilterApiServer, EthStateCache, EthSubscriptionIdProvider, ToRpcResult,
|
||||
};
|
||||
|
||||
/// The maximum number of headers we read at once when handling a range filter.
|
||||
const MAX_HEADERS_RANGE: u64 = 1_000; // with ~530bytes per header this is ~500kb
|
||||
|
||||
@ -706,56 +706,6 @@ impl Iterator for BlockRangeInclusiveIter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur in the handler implementation
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum EthFilterError {
|
||||
/// Filter not found.
|
||||
#[error("filter not found")]
|
||||
FilterNotFound(FilterId),
|
||||
/// Invalid block range.
|
||||
#[error("invalid block range params")]
|
||||
InvalidBlockRangeParams,
|
||||
/// Query scope is too broad.
|
||||
#[error("query exceeds max block range {0}")]
|
||||
QueryExceedsMaxBlocks(u64),
|
||||
/// Query result is too large.
|
||||
#[error("query exceeds max results {0}")]
|
||||
QueryExceedsMaxResults(usize),
|
||||
/// Error serving request in `eth_` namespace.
|
||||
#[error(transparent)]
|
||||
EthAPIError(#[from] EthApiError),
|
||||
/// Error thrown when a spawned task failed to deliver a response.
|
||||
#[error("internal filter error")]
|
||||
InternalError,
|
||||
}
|
||||
|
||||
// convert the error
|
||||
impl From<EthFilterError> for jsonrpsee::types::error::ErrorObject<'static> {
|
||||
fn from(err: EthFilterError) -> Self {
|
||||
match err {
|
||||
EthFilterError::FilterNotFound(_) => rpc_error_with_code(
|
||||
jsonrpsee::types::error::INVALID_PARAMS_CODE,
|
||||
"filter not found",
|
||||
),
|
||||
err @ EthFilterError::InternalError => {
|
||||
rpc_error_with_code(jsonrpsee::types::error::INTERNAL_ERROR_CODE, err.to_string())
|
||||
}
|
||||
EthFilterError::EthAPIError(err) => err.into(),
|
||||
err @ EthFilterError::InvalidBlockRangeParams |
|
||||
err @ EthFilterError::QueryExceedsMaxBlocks(_) |
|
||||
err @ EthFilterError::QueryExceedsMaxResults(_) => {
|
||||
rpc_error_with_code(jsonrpsee::types::error::INVALID_PARAMS_CODE, err.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProviderError> for EthFilterError {
|
||||
fn from(err: ProviderError) -> Self {
|
||||
Self::EthAPIError(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -1,11 +1,10 @@
|
||||
//! Contains RPC handler implementations specific to blocks.
|
||||
|
||||
use reth_provider::{BlockReaderIdExt, HeaderProvider};
|
||||
use reth_rpc_eth_api::helpers::{EthBlocks, LoadBlock, LoadPendingBlock, SpawnBlocking};
|
||||
use reth_rpc_eth_types::EthStateCache;
|
||||
|
||||
use crate::{
|
||||
servers::{EthBlocks, LoadBlock, LoadPendingBlock, SpawnBlocking},
|
||||
EthApi, EthStateCache,
|
||||
};
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthBlocks for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
@ -1,11 +1,9 @@
|
||||
//! Contains RPC handler implementations specific to endpoints that call/execute within evm.
|
||||
|
||||
use reth_evm::ConfigureEvm;
|
||||
use reth_rpc_eth_api::helpers::{Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking};
|
||||
|
||||
use crate::{
|
||||
servers::{Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking},
|
||||
EthApi,
|
||||
};
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthCall for EthApi<Provider, Pool, Network, EvmConfig> where
|
||||
Self: Call + LoadPendingBlock
|
||||
346
crates/rpc/rpc/src/eth/helpers/fee.rs
Normal file
346
crates/rpc/rpc/src/eth/helpers/fee.rs
Normal file
@ -0,0 +1,346 @@
|
||||
//! Loads fee history from database. Helper trait for `eth_` fee and transaction RPC methods.
|
||||
|
||||
use futures::Future;
|
||||
use reth_primitives::U256;
|
||||
use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider};
|
||||
use reth_rpc_types::{BlockNumberOrTag, FeeHistory};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{
|
||||
fee_history::calculate_reward_percentiles_for_block, api::LoadBlock, EthApiError,
|
||||
EthResult, EthStateCache, FeeHistoryCache, FeeHistoryEntry, GasPriceOracle,
|
||||
RpcInvalidTransactionError,
|
||||
};
|
||||
|
||||
/// Fee related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
|
||||
/// `eth_` namespace.
|
||||
pub trait EthFees: LoadFee {
|
||||
/// Returns a suggestion for a gas price for legacy transactions.
|
||||
///
|
||||
/// See also: <https://github.com/ethereum/pm/issues/328#issuecomment-853234014>
|
||||
fn gas_price(&self) -> impl Future<Output = EthResult<U256>> + Send
|
||||
where
|
||||
Self: LoadBlock,
|
||||
{
|
||||
LoadFee::gas_price(self)
|
||||
}
|
||||
|
||||
/// Returns a suggestion for a base fee for blob transactions.
|
||||
fn blob_base_fee(&self) -> impl Future<Output = EthResult<U256>> + Send
|
||||
where
|
||||
Self: LoadBlock,
|
||||
{
|
||||
LoadFee::blob_base_fee(self)
|
||||
}
|
||||
|
||||
/// Returns a suggestion for the priority fee (the tip)
|
||||
fn suggested_priority_fee(&self) -> impl Future<Output = EthResult<U256>> + Send
|
||||
where
|
||||
Self: 'static,
|
||||
{
|
||||
LoadFee::suggested_priority_fee(self)
|
||||
}
|
||||
|
||||
/// Reports the fee history, for the given amount of blocks, up until the given newest block.
|
||||
///
|
||||
/// If `reward_percentiles` are provided the [`FeeHistory`] will include the _approximated_
|
||||
/// rewards for the requested range.
|
||||
fn fee_history(
|
||||
&self,
|
||||
mut block_count: u64,
|
||||
newest_block: BlockNumberOrTag,
|
||||
reward_percentiles: Option<Vec<f64>>,
|
||||
) -> impl Future<Output = EthResult<FeeHistory>> + Send {
|
||||
async move {
|
||||
if block_count == 0 {
|
||||
return Ok(FeeHistory::default())
|
||||
}
|
||||
|
||||
// See https://github.com/ethereum/go-ethereum/blob/2754b197c935ee63101cbbca2752338246384fec/eth/gasprice/feehistory.go#L218C8-L225
|
||||
let max_fee_history = if reward_percentiles.is_none() {
|
||||
self.gas_oracle().config().max_header_history
|
||||
} else {
|
||||
self.gas_oracle().config().max_block_history
|
||||
};
|
||||
|
||||
if block_count > max_fee_history {
|
||||
debug!(
|
||||
requested = block_count,
|
||||
truncated = max_fee_history,
|
||||
"Sanitizing fee history block count"
|
||||
);
|
||||
block_count = max_fee_history
|
||||
}
|
||||
|
||||
let Some(end_block) =
|
||||
LoadFee::provider(self).block_number_for_id(newest_block.into())?
|
||||
else {
|
||||
return Err(EthApiError::UnknownBlockNumber)
|
||||
};
|
||||
|
||||
// need to add 1 to the end block to get the correct (inclusive) range
|
||||
let end_block_plus = end_block + 1;
|
||||
// Ensure that we would not be querying outside of genesis
|
||||
if end_block_plus < block_count {
|
||||
block_count = end_block_plus;
|
||||
}
|
||||
|
||||
// If reward percentiles were specified, we
|
||||
// need to validate that they are monotonically
|
||||
// increasing and 0 <= p <= 100
|
||||
// Note: The types used ensure that the percentiles are never < 0
|
||||
if let Some(percentiles) = &reward_percentiles {
|
||||
if percentiles.windows(2).any(|w| w[0] > w[1] || w[0] > 100.) {
|
||||
return Err(EthApiError::InvalidRewardPercentiles)
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the headers and ensure we got all of them
|
||||
//
|
||||
// Treat a request for 1 block as a request for `newest_block..=newest_block`,
|
||||
// otherwise `newest_block - 2
|
||||
// NOTE: We ensured that block count is capped
|
||||
let start_block = end_block_plus - block_count;
|
||||
|
||||
// Collect base fees, gas usage ratios and (optionally) reward percentile data
|
||||
let mut base_fee_per_gas: Vec<u128> = Vec::new();
|
||||
let mut gas_used_ratio: Vec<f64> = Vec::new();
|
||||
|
||||
let mut base_fee_per_blob_gas: Vec<u128> = Vec::new();
|
||||
let mut blob_gas_used_ratio: Vec<f64> = Vec::new();
|
||||
|
||||
let mut rewards: Vec<Vec<u128>> = Vec::new();
|
||||
|
||||
// Check if the requested range is within the cache bounds
|
||||
let fee_entries = self.fee_history_cache().get_history(start_block, end_block).await;
|
||||
|
||||
if let Some(fee_entries) = fee_entries {
|
||||
if fee_entries.len() != block_count as usize {
|
||||
return Err(EthApiError::InvalidBlockRange)
|
||||
}
|
||||
|
||||
for entry in &fee_entries {
|
||||
base_fee_per_gas.push(entry.base_fee_per_gas as u128);
|
||||
gas_used_ratio.push(entry.gas_used_ratio);
|
||||
base_fee_per_blob_gas.push(entry.base_fee_per_blob_gas.unwrap_or_default());
|
||||
blob_gas_used_ratio.push(entry.blob_gas_used_ratio);
|
||||
|
||||
if let Some(percentiles) = &reward_percentiles {
|
||||
let mut block_rewards = Vec::with_capacity(percentiles.len());
|
||||
for &percentile in percentiles {
|
||||
block_rewards.push(self.approximate_percentile(entry, percentile));
|
||||
}
|
||||
rewards.push(block_rewards);
|
||||
}
|
||||
}
|
||||
let last_entry = fee_entries.last().expect("is not empty");
|
||||
|
||||
// Also need to include the `base_fee_per_gas` and `base_fee_per_blob_gas` for the
|
||||
// next block
|
||||
base_fee_per_gas
|
||||
.push(last_entry.next_block_base_fee(&LoadFee::provider(self).chain_spec())
|
||||
as u128);
|
||||
|
||||
base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default());
|
||||
} else {
|
||||
// read the requested header range
|
||||
let headers = LoadFee::provider(self).sealed_headers_range(start_block..=end_block)?;
|
||||
if headers.len() != block_count as usize {
|
||||
return Err(EthApiError::InvalidBlockRange)
|
||||
}
|
||||
|
||||
for header in &headers {
|
||||
base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128);
|
||||
gas_used_ratio.push(header.gas_used as f64 / header.gas_limit as f64);
|
||||
base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default());
|
||||
blob_gas_used_ratio.push(
|
||||
header.blob_gas_used.unwrap_or_default() as f64 /
|
||||
reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64,
|
||||
);
|
||||
|
||||
// Percentiles were specified, so we need to collect reward percentile ino
|
||||
if let Some(percentiles) = &reward_percentiles {
|
||||
let (transactions, receipts) = LoadFee::cache(self)
|
||||
.get_transactions_and_receipts(header.hash())
|
||||
.await?
|
||||
.ok_or(EthApiError::InvalidBlockRange)?;
|
||||
rewards.push(
|
||||
calculate_reward_percentiles_for_block(
|
||||
percentiles,
|
||||
header.gas_used,
|
||||
header.base_fee_per_gas.unwrap_or_default(),
|
||||
&transactions,
|
||||
&receipts,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// The spec states that `base_fee_per_gas` "[..] includes the next block after the
|
||||
// newest of the returned range, because this value can be derived from the
|
||||
// newest block"
|
||||
//
|
||||
// The unwrap is safe since we checked earlier that we got at least 1 header.
|
||||
let last_header = headers.last().expect("is present");
|
||||
base_fee_per_gas.push(
|
||||
LoadFee::provider(self).chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee(
|
||||
last_header.gas_used as u128,
|
||||
last_header.gas_limit as u128,
|
||||
last_header.base_fee_per_gas.unwrap_or_default() as u128,
|
||||
));
|
||||
|
||||
// Same goes for the `base_fee_per_blob_gas`:
|
||||
// > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block.
|
||||
base_fee_per_blob_gas
|
||||
.push(last_header.next_block_blob_fee().unwrap_or_default());
|
||||
};
|
||||
|
||||
Ok(FeeHistory {
|
||||
base_fee_per_gas,
|
||||
gas_used_ratio,
|
||||
base_fee_per_blob_gas,
|
||||
blob_gas_used_ratio,
|
||||
oldest_block: start_block,
|
||||
reward: reward_percentiles.map(|_| rewards),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Approximates reward at a given percentile for a specific block
|
||||
/// Based on the configured resolution
|
||||
fn approximate_percentile(&self, entry: &FeeHistoryEntry, requested_percentile: f64) -> u128 {
|
||||
let resolution = self.fee_history_cache().resolution();
|
||||
let rounded_percentile =
|
||||
(requested_percentile * resolution as f64).round() / resolution as f64;
|
||||
let clamped_percentile = rounded_percentile.clamp(0.0, 100.0);
|
||||
|
||||
// Calculate the index in the precomputed rewards array
|
||||
let index = (clamped_percentile / (1.0 / resolution as f64)).round() as usize;
|
||||
// Fetch the reward from the FeeHistoryEntry
|
||||
entry.rewards.get(index).cloned().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads fee from database.
|
||||
///
|
||||
/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` fees RPC methods.
|
||||
pub trait LoadFee: LoadBlock {
|
||||
// Returns a handle for reading data from disk.
|
||||
///
|
||||
/// Data access in default (L1) trait method implementations.
|
||||
fn provider(&self) -> impl BlockIdReader + HeaderProvider + ChainSpecProvider;
|
||||
|
||||
/// Returns a handle for reading data from memory.
|
||||
///
|
||||
/// Data access in default (L1) trait method implementations.
|
||||
fn cache(&self) -> &EthStateCache;
|
||||
|
||||
/// Returns a handle for reading gas price.
|
||||
///
|
||||
/// Data access in default (L1) trait method implementations.
|
||||
fn gas_oracle(&self) -> &GasPriceOracle<impl BlockReaderIdExt>;
|
||||
|
||||
/// Returns a handle for reading fee history data from memory.
|
||||
///
|
||||
/// Data access in default (L1) trait method implementations.
|
||||
fn fee_history_cache(&self) -> &FeeHistoryCache;
|
||||
|
||||
/// Returns the gas price if it is set, otherwise fetches a suggested gas price for legacy
|
||||
/// transactions.
|
||||
fn legacy_gas_price(
|
||||
&self,
|
||||
gas_price: Option<U256>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
async move {
|
||||
match gas_price {
|
||||
Some(gas_price) => Ok(gas_price),
|
||||
None => {
|
||||
// fetch a suggested gas price
|
||||
self.gas_price().await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the EIP-1559 fees if they are set, otherwise fetches a suggested gas price for
|
||||
/// EIP-1559 transactions.
|
||||
///
|
||||
/// Returns (`max_fee`, `priority_fee`)
|
||||
fn eip1559_fees(
|
||||
&self,
|
||||
max_fee_per_gas: Option<U256>,
|
||||
max_priority_fee_per_gas: Option<U256>,
|
||||
) -> impl Future<Output = EthResult<(U256, U256)>> + Send {
|
||||
async move {
|
||||
let max_fee_per_gas = match max_fee_per_gas {
|
||||
Some(max_fee_per_gas) => max_fee_per_gas,
|
||||
None => {
|
||||
// fetch pending base fee
|
||||
let base_fee = self
|
||||
.block(BlockNumberOrTag::Pending)
|
||||
.await?
|
||||
.ok_or(EthApiError::UnknownBlockNumber)?
|
||||
.base_fee_per_gas
|
||||
.ok_or_else(|| {
|
||||
EthApiError::InvalidTransaction(
|
||||
RpcInvalidTransactionError::TxTypeNotSupported,
|
||||
)
|
||||
})?;
|
||||
U256::from(base_fee)
|
||||
}
|
||||
};
|
||||
|
||||
let max_priority_fee_per_gas = match max_priority_fee_per_gas {
|
||||
Some(max_priority_fee_per_gas) => max_priority_fee_per_gas,
|
||||
None => self.suggested_priority_fee().await?,
|
||||
};
|
||||
Ok((max_fee_per_gas, max_priority_fee_per_gas))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the EIP-4844 blob fee if it is set, otherwise fetches a blob fee.
|
||||
fn eip4844_blob_fee(
|
||||
&self,
|
||||
blob_fee: Option<U256>,
|
||||
) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
async move {
|
||||
match blob_fee {
|
||||
Some(blob_fee) => Ok(blob_fee),
|
||||
None => self.blob_base_fee().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a suggestion for a gas price for legacy transactions.
|
||||
///
|
||||
/// See also: <https://github.com/ethereum/pm/issues/328#issuecomment-853234014>
|
||||
fn gas_price(&self) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
let header = self.block(BlockNumberOrTag::Latest);
|
||||
let suggested_tip = self.suggested_priority_fee();
|
||||
async move {
|
||||
let (header, suggested_tip) = futures::try_join!(header, suggested_tip)?;
|
||||
let base_fee = header.and_then(|h| h.base_fee_per_gas).unwrap_or_default();
|
||||
Ok(suggested_tip + U256::from(base_fee))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a suggestion for a base fee for blob transactions.
|
||||
fn blob_base_fee(&self) -> impl Future<Output = EthResult<U256>> + Send {
|
||||
async move {
|
||||
self.block(BlockNumberOrTag::Latest)
|
||||
.await?
|
||||
.and_then(|h: reth_primitives::SealedBlock| h.next_block_blob_fee())
|
||||
.ok_or(EthApiError::ExcessBlobGasNotSet)
|
||||
.map(U256::from)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a suggestion for the priority fee (the tip)
|
||||
fn suggested_priority_fee(&self) -> impl Future<Output = EthResult<U256>> + Send
|
||||
where
|
||||
Self: 'static,
|
||||
{
|
||||
self.gas_oracle().suggest_tip_cap()
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,10 @@
|
||||
|
||||
use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider};
|
||||
|
||||
use crate::{
|
||||
servers::{EthFees, LoadBlock, LoadFee},
|
||||
EthApi, EthStateCache, FeeHistoryCache, GasPriceOracle,
|
||||
};
|
||||
use reth_rpc_eth_api::helpers::{EthFees, LoadBlock, LoadFee};
|
||||
use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasPriceOracle};
|
||||
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthFees for EthApi<Provider, Pool, Network, EvmConfig> where
|
||||
Self: LoadFee
|
||||
@ -2,7 +2,6 @@
|
||||
//! files.
|
||||
|
||||
pub mod signer;
|
||||
pub mod traits;
|
||||
|
||||
mod block;
|
||||
mod call;
|
||||
@ -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)]
|
||||
@ -2,12 +2,11 @@
|
||||
|
||||
use reth_evm::ConfigureEvm;
|
||||
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
|
||||
use reth_rpc_eth_api::helpers::{LoadPendingBlock, SpawnBlocking};
|
||||
use reth_rpc_eth_types::PendingBlock;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
use crate::{
|
||||
servers::{LoadPendingBlock, SpawnBlocking},
|
||||
EthApi, PendingBlock,
|
||||
};
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> LoadPendingBlock
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
@ -1,6 +1,9 @@
|
||||
//! Builds an RPC receipt response w.r.t. data layout of network.
|
||||
|
||||
use crate::{servers::LoadReceipt, EthApi, EthStateCache};
|
||||
use reth_rpc_eth_api::helpers::LoadReceipt;
|
||||
use reth_rpc_eth_types::EthStateCache;
|
||||
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> LoadReceipt for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
@ -8,6 +11,6 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn cache(&self) -> &EthStateCache {
|
||||
&self.inner.eth_cache
|
||||
self.inner.cache()
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
@ -4,10 +4,11 @@ use reth_evm::ConfigureEvm;
|
||||
use reth_network_api::NetworkInfo;
|
||||
use reth_primitives::{Address, U256, U64};
|
||||
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
|
||||
use reth_rpc_eth_api::helpers::EthApiSpec;
|
||||
use reth_rpc_types::{SyncInfo, SyncStatus};
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
use crate::{servers::EthApiSpec, EthApi};
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApiSpec for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
@ -36,7 +37,7 @@ where
|
||||
}
|
||||
|
||||
fn accounts(&self) -> Vec<Address> {
|
||||
self.inner.signers.read().iter().flat_map(|s| s.accounts()).collect()
|
||||
self.inner.signers().read().iter().flat_map(|s| s.accounts()).collect()
|
||||
}
|
||||
|
||||
fn is_syncing(&self) -> bool {
|
||||
@ -50,7 +51,7 @@ where
|
||||
self.provider().chain_info().map(|info| info.best_number).unwrap_or_default(),
|
||||
);
|
||||
SyncStatus::Info(SyncInfo {
|
||||
starting_block: self.inner.starting_block,
|
||||
starting_block: self.inner.starting_block(),
|
||||
current_block,
|
||||
highest_block: current_block,
|
||||
warp_chunks_amount: None,
|
||||
@ -3,10 +3,10 @@
|
||||
use reth_provider::StateProviderFactory;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
use crate::{
|
||||
servers::{EthState, LoadState, SpawnBlocking},
|
||||
EthApi, EthStateCache,
|
||||
};
|
||||
use reth_rpc_eth_api::helpers::{EthState, LoadState, SpawnBlocking};
|
||||
use reth_rpc_eth_types::EthStateCache;
|
||||
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthState for EthApi<Provider, Pool, Network, EvmConfig> where
|
||||
Self: LoadState + SpawnBlocking
|
||||
@ -43,13 +43,13 @@ mod tests {
|
||||
constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, StorageKey, StorageValue, U256,
|
||||
};
|
||||
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider};
|
||||
use reth_rpc_eth_api::helpers::EthState;
|
||||
use reth_rpc_eth_types::{
|
||||
EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
|
||||
};
|
||||
use reth_tasks::pool::BlockingTaskPool;
|
||||
use reth_transaction_pool::test_utils::testing_pool;
|
||||
|
||||
use crate::{
|
||||
servers::EthState, EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
@ -1,11 +1,9 @@
|
||||
//! Contains RPC handler implementations specific to tracing.
|
||||
|
||||
use reth_evm::ConfigureEvm;
|
||||
use reth_rpc_eth_api::helpers::{LoadState, Trace};
|
||||
|
||||
use crate::{
|
||||
servers::{LoadState, Trace},
|
||||
EthApi,
|
||||
};
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> Trace for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
where
|
||||
@ -1,14 +1,14 @@
|
||||
//! Contains RPC handler implementations specific to transactions
|
||||
|
||||
use reth_provider::{BlockReaderIdExt, TransactionsProvider};
|
||||
use reth_rpc_eth_api::{
|
||||
helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking},
|
||||
RawTransactionForwarder,
|
||||
};
|
||||
use reth_rpc_eth_types::EthStateCache;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
use crate::{
|
||||
servers::{
|
||||
EthSigner, EthTransactions, LoadTransaction, RawTransactionForwarder, SpawnBlocking,
|
||||
},
|
||||
EthApi, EthStateCache,
|
||||
};
|
||||
use crate::EthApi;
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthTransactions
|
||||
for EthApi<Provider, Pool, Network, EvmConfig>
|
||||
@ -64,14 +64,13 @@ mod tests {
|
||||
use reth_network_api::noop::NoopNetwork;
|
||||
use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex, Bytes};
|
||||
use reth_provider::test_utils::NoopProvider;
|
||||
use reth_rpc_eth_api::helpers::EthTransactions;
|
||||
use reth_rpc_eth_types::{
|
||||
EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle,
|
||||
};
|
||||
use reth_tasks::pool::BlockingTaskPool;
|
||||
use reth_transaction_pool::{test_utils::testing_pool, TransactionPool};
|
||||
|
||||
use crate::{
|
||||
servers::EthTransactions, EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig,
|
||||
GasPriceOracle,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
17
crates/rpc/rpc/src/eth/mod.rs
Normal file
17
crates/rpc/rpc/src/eth/mod.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//! Sever implementation of `eth` namespace API.
|
||||
|
||||
pub mod bundle;
|
||||
pub mod core;
|
||||
pub mod filter;
|
||||
pub mod helpers;
|
||||
pub mod pubsub;
|
||||
|
||||
/// Implementation of `eth` namespace API.
|
||||
pub use bundle::EthBundle;
|
||||
pub use core::EthApi;
|
||||
pub use filter::{EthFilter, EthFilterConfig};
|
||||
pub use pubsub::EthPubSub;
|
||||
|
||||
pub use helpers::signer::DevSigner;
|
||||
|
||||
pub use reth_rpc_eth_api::RawTransactionForwarder;
|
||||
@ -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.
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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::{
|
||||
|
||||
@ -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.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user