diff --git a/Cargo.lock b/Cargo.lock index 6d4f935e03..f5a5175909 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9232,6 +9232,7 @@ dependencies = [ "alloy-sol-types", "eyre", "futures", + "jsonrpsee-core", "rand 0.9.2", "reth-chainspec", "reth-db", @@ -9267,6 +9268,7 @@ dependencies = [ "serde", "serde_json", "similar-asserts", + "tempfile", "tokio", ] @@ -10157,6 +10159,7 @@ dependencies = [ "reth-db-api", "reth-engine-primitives", "reth-errors", + "reth-ethereum-engine-primitives", "reth-ethereum-primitives", "reth-evm", "reth-evm-ethereum", @@ -10219,7 +10222,9 @@ dependencies = [ "reth-network-peers", "reth-rpc-eth-api", "reth-trie-common", + "serde", "serde_json", + "tokio", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cfe5aa014a..ac4b9e5d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -376,11 +376,11 @@ reth-era-utils = { path = "crates/era-utils" } reth-errors = { path = "crates/errors" } reth-eth-wire = { path = "crates/net/eth-wire" } reth-eth-wire-types = { path = "crates/net/eth-wire-types" } +reth-ethereum-payload-builder = { path = "crates/ethereum/payload" } reth-ethereum-cli = { path = "crates/ethereum/cli", default-features = false } reth-ethereum-consensus = { path = "crates/ethereum/consensus", default-features = false } reth-ethereum-engine-primitives = { path = "crates/ethereum/engine-primitives", default-features = false } reth-ethereum-forks = { path = "crates/ethereum/hardforks", default-features = false } -reth-ethereum-payload-builder = { path = "crates/ethereum/payload" } reth-ethereum-primitives = { path = "crates/ethereum/primitives", default-features = false } reth-ethereum = { path = "crates/ethereum/reth" } reth-etl = { path = "crates/etl" } diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index 4ea3b8ccb1..0209dcb70a 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -61,6 +61,8 @@ reth-node-core.workspace = true reth-e2e-test-utils.workspace = true reth-tasks.workspace = true reth-testing-utils.workspace = true +tempfile.workspace = true +jsonrpsee-core.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index 5b60f85b52..dd288f704a 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -38,9 +38,9 @@ use reth_payload_primitives::PayloadTypes; use reth_provider::{providers::ProviderFactoryBuilder, EthStorage}; use reth_rpc::{ eth::core::{EthApiFor, EthRpcConverterFor}, - ValidationApi, + TestingApi, ValidationApi, }; -use reth_rpc_api::servers::BlockSubmissionValidationApiServer; +use reth_rpc_api::servers::{BlockSubmissionValidationApiServer, TestingApiServer}; use reth_rpc_builder::{config::RethRpcServerConfig, middleware::RethRpcMiddleware}; use reth_rpc_eth_api::{ helpers::{ @@ -313,6 +313,17 @@ where .modules .merge_if_module_configured(RethRpcModule::Eth, eth_config.into_rpc())?; + // testing_buildBlockV1: only wire when the hidden testing module is explicitly + // requested on any transport. Default stays disabled to honor security guidance. + let testing_api = TestingApi::new( + container.registry.eth_api().clone(), + container.registry.evm_config().clone(), + ) + .into_rpc(); + container + .modules + .merge_if_module_configured(RethRpcModule::Testing, testing_api)?; + Ok(()) }) .await diff --git a/crates/ethereum/node/tests/it/main.rs b/crates/ethereum/node/tests/it/main.rs index 0f85adda31..7aeec57ada 100644 --- a/crates/ethereum/node/tests/it/main.rs +++ b/crates/ethereum/node/tests/it/main.rs @@ -2,5 +2,6 @@ mod builder; mod exex; +mod testing; const fn main() {} diff --git a/crates/ethereum/node/tests/it/testing.rs b/crates/ethereum/node/tests/it/testing.rs new file mode 100644 index 0000000000..16f26a8c6a --- /dev/null +++ b/crates/ethereum/node/tests/it/testing.rs @@ -0,0 +1,84 @@ +//! E2E tests for the testing RPC namespace. + +use alloy_primitives::{Address, B256}; +use alloy_rpc_types_engine::ExecutionPayloadEnvelopeV4; +use jsonrpsee_core::client::ClientT; +use reth_db::test_utils::create_test_rw_db; +use reth_ethereum_engine_primitives::EthPayloadAttributes; +use reth_node_builder::{NodeBuilder, NodeConfig}; +use reth_node_core::{ + args::DatadirArgs, + dirs::{DataDirPath, MaybePlatformPath}, +}; +use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; +use reth_rpc_api::TestingBuildBlockRequestV1; +use reth_rpc_server_types::{RethRpcModule, RpcModuleSelection}; +use reth_tasks::TaskManager; +use std::str::FromStr; +use tempfile::tempdir; +use tokio::sync::oneshot; + +#[tokio::test(flavor = "multi_thread")] +async fn testing_rpc_build_block_works() -> eyre::Result<()> { + let tasks = TaskManager::current(); + let mut rpc_args = reth_node_core::args::RpcServerArgs::default().with_http(); + rpc_args.http_api = Some(RpcModuleSelection::from_iter([RethRpcModule::Testing])); + let tempdir = tempdir().expect("temp datadir"); + let datadir_args = DatadirArgs { + datadir: MaybePlatformPath::::from_str(tempdir.path().to_str().unwrap()) + .expect("valid datadir"), + static_files_path: Some(tempdir.path().join("static")), + }; + let config = NodeConfig::test().with_datadir_args(datadir_args).with_rpc(rpc_args); + let db = create_test_rw_db(); + + let (tx, rx): ( + oneshot::Sender>, + oneshot::Receiver>, + ) = oneshot::channel(); + + let builder = NodeBuilder::new(config) + .with_database(db) + .with_launch_context(tasks.executor()) + .with_types::() + .with_components(EthereumNode::components()) + .with_add_ons(EthereumAddOns::default()) + .on_rpc_started(move |ctx, handles| { + let Some(client) = handles.rpc.http_client() else { return Ok(()) }; + + let chain = ctx.config().chain.clone(); + let parent_block_hash = chain.genesis_hash(); + let payload_attributes = EthPayloadAttributes { + timestamp: chain.genesis().timestamp + 1, + prev_randao: B256::ZERO, + suggested_fee_recipient: Address::ZERO, + withdrawals: None, + parent_beacon_block_root: None, + }; + + let request = TestingBuildBlockRequestV1 { + parent_block_hash, + payload_attributes, + transactions: vec![], + extra_data: None, + }; + + tokio::spawn(async move { + let res: eyre::Result = + client.request("testing_buildBlockV1", [request]).await.map_err(Into::into); + let _ = tx.send(res); + }); + + Ok(()) + }); + + // Launch the node with the default engine launcher. + let launcher = builder.engine_api_launcher(); + let _node = builder.launch_with(launcher).await?; + + // Wait for the testing RPC call to return. + let res = rx.await.expect("testing_buildBlockV1 response"); + assert!(res.is_ok(), "testing_buildBlockV1 failed: {:?}", res.err()); + + Ok(()) +} diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index d092267c4b..524b7d88a9 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -168,6 +168,7 @@ where gas_limit: builder_config.gas_limit(parent_header.gas_limit), parent_beacon_block_root: attributes.parent_beacon_block_root(), withdrawals: Some(attributes.withdrawals().clone()), + extra_data: None, }, ) .map_err(PayloadBuilderError::other)?; diff --git a/crates/evm/evm/src/lib.rs b/crates/evm/evm/src/lib.rs index e2101fd915..676eb2ff6f 100644 --- a/crates/evm/evm/src/lib.rs +++ b/crates/evm/evm/src/lib.rs @@ -28,7 +28,7 @@ use alloy_evm::{ block::{BlockExecutorFactory, BlockExecutorFor}, precompiles::PrecompilesMap, }; -use alloy_primitives::{Address, B256}; +use alloy_primitives::{Address, Bytes, B256}; use core::{error::Error, fmt::Debug}; use execute::{BasicBlockExecutor, BlockAssembler, BlockBuilder}; use reth_execution_errors::BlockExecutionError; @@ -501,6 +501,8 @@ pub struct NextBlockEnvAttributes { pub parent_beacon_block_root: Option, /// Withdrawals pub withdrawals: Option, + /// Optional extra data. + pub extra_data: Option, } /// Abstraction over transaction environment. diff --git a/crates/rpc/rpc-api/Cargo.toml b/crates/rpc/rpc-api/Cargo.toml index ebd748d183..e2c2d00155 100644 --- a/crates/rpc/rpc-api/Cargo.toml +++ b/crates/rpc/rpc-api/Cargo.toml @@ -35,6 +35,7 @@ alloy-serde.workspace = true alloy-rpc-types-beacon.workspace = true alloy-rpc-types-engine.workspace = true alloy-genesis.workspace = true +serde = { workspace = true, features = ["derive"] } # misc jsonrpsee = { workspace = true, features = ["server", "macros"] } @@ -46,3 +47,8 @@ client = [ "jsonrpsee/async-client", "reth-rpc-eth-api/client", ] + +[dev-dependencies] +serde_json = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +jsonrpsee = { workspace = true, features = ["client", "async-client", "http-client"] } diff --git a/crates/rpc/rpc-api/src/lib.rs b/crates/rpc/rpc-api/src/lib.rs index 89e21c80b0..9c3a4baa03 100644 --- a/crates/rpc/rpc-api/src/lib.rs +++ b/crates/rpc/rpc-api/src/lib.rs @@ -25,11 +25,14 @@ mod net; mod otterscan; mod reth; mod rpc; +mod testing; mod trace; mod txpool; mod validation; mod web3; +pub use testing::{TestingBuildBlockRequestV1, TESTING_BUILD_BLOCK_V1}; + /// re-export of all server traits pub use servers::*; @@ -45,6 +48,7 @@ pub mod servers { otterscan::OtterscanServer, reth::RethApiServer, rpc::RpcApiServer, + testing::TestingApiServer, trace::TraceApiServer, txpool::TxPoolApiServer, validation::BlockSubmissionValidationApiServer, @@ -75,6 +79,7 @@ pub mod clients { otterscan::OtterscanClient, reth::RethApiClient, rpc::RpcApiServer, + testing::TestingApiClient, trace::TraceApiClient, txpool::TxPoolApiClient, validation::BlockSubmissionValidationApiClient, diff --git a/crates/rpc/rpc-api/src/testing.rs b/crates/rpc/rpc-api/src/testing.rs new file mode 100644 index 0000000000..f49380058e --- /dev/null +++ b/crates/rpc/rpc-api/src/testing.rs @@ -0,0 +1,45 @@ +//! Testing namespace for building a block in a single call. +//! +//! This follows the `testing_buildBlockV1` specification. **Highly sensitive:** +//! testing-only, powerful enough to include arbitrary transactions; must stay +//! disabled by default and never be exposed on public-facing RPC without an +//! explicit operator flag. + +use alloy_primitives::{Bytes, B256}; +use alloy_rpc_types_engine::{ + ExecutionPayloadEnvelopeV5, PayloadAttributes as EthPayloadAttributes, +}; +use jsonrpsee::proc_macros::rpc; +use serde::{Deserialize, Serialize}; + +/// Capability string for `testing_buildBlockV1`. +pub const TESTING_BUILD_BLOCK_V1: &str = "testing_buildBlockV1"; + +/// Request payload for `testing_buildBlockV1`. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TestingBuildBlockRequestV1 { + /// Parent block hash of the block to build. + pub parent_block_hash: B256, + /// Payload attributes (Cancun version). + pub payload_attributes: EthPayloadAttributes, + /// Raw signed transactions to force-include in order. + pub transactions: Vec, + /// Optional extra data for the block header. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub extra_data: Option, +} + +/// Testing RPC interface for building a block in a single call. +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "testing"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "testing"))] +pub trait TestingApi { + /// Builds a block using the provided parent, payload attributes, and transactions. + /// + /// See + #[method(name = "buildBlockV1")] + async fn build_block_v1( + &self, + request: TestingBuildBlockRequestV1, + ) -> jsonrpsee::core::RpcResult; +} diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 89935ca747..644f5dd496 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -52,6 +52,7 @@ use reth_rpc_eth_api::{ }; use reth_rpc_eth_types::{receipt::EthReceiptConverter, EthConfig, EthSubscriptionIdProvider}; use reth_rpc_layer::{AuthLayer, Claims, CompressionLayer, JwtAuthValidator, JwtSecret}; +pub use reth_rpc_server_types::RethRpcModule; use reth_storage_api::{ AccountReader, BlockReader, ChangeSetReader, FullRpcProvider, NodePrimitivesProvider, StateProviderFactory, @@ -76,7 +77,7 @@ use jsonrpsee::server::ServerConfigBuilder; pub use reth_ipc::server::{ Builder as IpcServerBuilder, RpcServiceBuilder as IpcRpcServiceBuilder, }; -pub use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection}; +pub use reth_rpc_server_types::{constants, RpcModuleSelection}; pub use tower::layer::util::{Identity, Stack}; /// Auth server utilities. @@ -561,8 +562,8 @@ where } } -impl - RpcRegistryInner +impl + RpcRegistryInner where EthApi: EthApiTypes, { @@ -591,6 +592,11 @@ where &self.provider } + /// Returns a reference to the evm config + pub const fn evm_config(&self) -> &Evm { + &self.evm_config + } + /// Returns all installed methods pub fn methods(&self) -> Vec { self.modules.values().cloned().collect() @@ -992,18 +998,18 @@ where .into_rpc() .into() } - // only relevant for Ethereum and configured in `EthereumAddOns` - // implementation - // TODO: can we get rid of this here? - // Custom modules are not handled here - they should be registered via - // extend_rpc_modules - RethRpcModule::Flashbots | RethRpcModule::Other(_) => Default::default(), RethRpcModule::Miner => MinerApi::default().into_rpc().into(), RethRpcModule::Mev => { EthSimBundle::new(eth_api.clone(), self.blocking_pool_guard.clone()) .into_rpc() .into() } + // these are implementation specific and need to be handled during + // initialization and should be registered via extend_rpc_modules in the + // nodebuilder rpc addon stack + RethRpcModule::Flashbots | + RethRpcModule::Testing | + RethRpcModule::Other(_) => Default::default(), }) .clone() }) diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index e368f309f3..00b675823e 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -420,6 +420,7 @@ impl BuildPendingEnv for NextBlockEnvAttributes { gas_limit: parent.gas_limit(), parent_beacon_block_root: parent.parent_beacon_block_root(), withdrawals: parent.withdrawals_root().map(|_| Default::default()), + extra_data: None, } } } diff --git a/crates/rpc/rpc-server-types/src/module.rs b/crates/rpc/rpc-server-types/src/module.rs index 14e44cb7c0..d41e10bb73 100644 --- a/crates/rpc/rpc-server-types/src/module.rs +++ b/crates/rpc/rpc-server-types/src/module.rs @@ -323,6 +323,8 @@ pub enum RethRpcModule { Miner, /// `mev_` module Mev, + /// `testing_` module + Testing, /// Custom RPC module not part of the standard set #[strum(default)] #[serde(untagged)] @@ -347,6 +349,7 @@ impl RethRpcModule { Self::Flashbots, Self::Miner, Self::Mev, + Self::Testing, ]; /// Returns the number of standard variants (excludes Other) @@ -406,6 +409,7 @@ impl AsRef for RethRpcModule { Self::Flashbots => "flashbots", Self::Miner => "miner", Self::Mev => "mev", + Self::Testing => "testing", } } } @@ -428,6 +432,7 @@ impl FromStr for RethRpcModule { "flashbots" => Self::Flashbots, "miner" => Self::Miner, "mev" => Self::Mev, + "testing" => Self::Testing, // Any unknown module becomes Other other => Self::Other(other.to_string()), }) diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index a47fa5ebcd..80c89e6027 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -38,6 +38,8 @@ reth-rpc-server-types.workspace = true reth-network-types.workspace = true reth-consensus.workspace = true reth-consensus-common.workspace = true +reth-ethereum-primitives.workspace = true +reth-ethereum-engine-primitives.workspace = true reth-node-api.workspace = true reth-trie-common.workspace = true diff --git a/crates/rpc/rpc/src/lib.rs b/crates/rpc/rpc/src/lib.rs index b5a20c19cf..816b39f485 100644 --- a/crates/rpc/rpc/src/lib.rs +++ b/crates/rpc/rpc/src/lib.rs @@ -42,6 +42,7 @@ mod net; mod otterscan; mod reth; mod rpc; +mod testing; mod trace; mod txpool; mod validation; @@ -58,6 +59,7 @@ pub use otterscan::OtterscanApi; pub use reth::RethApi; pub use reth_rpc_convert::RpcTypes; pub use rpc::RPCApi; +pub use testing::TestingApi; pub use trace::TraceApi; pub use txpool::TxPoolApi; pub use validation::{ValidationApi, ValidationApiConfig}; diff --git a/crates/rpc/rpc/src/testing.rs b/crates/rpc/rpc/src/testing.rs new file mode 100644 index 0000000000..6306c172b3 --- /dev/null +++ b/crates/rpc/rpc/src/testing.rs @@ -0,0 +1,127 @@ +//! Implementation of the `testing` namespace. +//! +//! This exposes `testing_buildBlockV1`, intended for non-production/debug use. + +use alloy_consensus::{Header, Transaction}; +use alloy_evm::Evm; +use alloy_primitives::U256; +use alloy_rpc_types_engine::ExecutionPayloadEnvelopeV5; +use async_trait::async_trait; +use jsonrpsee::core::RpcResult; +use reth_errors::RethError; +use reth_ethereum_engine_primitives::EthBuiltPayload; +use reth_ethereum_primitives::EthPrimitives; +use reth_evm::{execute::BlockBuilder, ConfigureEvm, NextBlockEnvAttributes}; +use reth_primitives_traits::{AlloyBlockHeader as BlockTrait, Recovered, TxTy}; +use reth_revm::{database::StateProviderDatabase, db::State}; +use reth_rpc_api::{TestingApiServer, TestingBuildBlockRequestV1}; +use reth_rpc_eth_api::{helpers::Call, FromEthApiError}; +use reth_rpc_eth_types::{utils::recover_raw_transaction, EthApiError}; +use reth_storage_api::{BlockReader, HeaderProvider}; +use revm::context::Block; +use std::sync::Arc; + +/// Testing API handler. +#[derive(Debug, Clone)] +pub struct TestingApi { + eth_api: Eth, + evm_config: Evm, +} + +impl TestingApi { + /// Create a new testing API handler. + pub const fn new(eth_api: Eth, evm_config: Evm) -> Self { + Self { eth_api, evm_config } + } +} + +impl TestingApi +where + Eth: Call>, + Evm: ConfigureEvm + + 'static, +{ + async fn build_block_v1( + &self, + request: TestingBuildBlockRequestV1, + ) -> Result { + let evm_config = self.evm_config.clone(); + self.eth_api + .spawn_with_state_at_block(request.parent_block_hash, move |eth_api, state| { + let state = state.database.0; + let mut db = State::builder() + .with_bundle_update() + .with_database(StateProviderDatabase::new(&state)) + .build(); + let parent = eth_api + .provider() + .sealed_header_by_hash(request.parent_block_hash)? + .ok_or_else(|| { + EthApiError::HeaderNotFound(request.parent_block_hash.into()) + })?; + + let env_attrs = NextBlockEnvAttributes { + timestamp: request.payload_attributes.timestamp, + suggested_fee_recipient: request.payload_attributes.suggested_fee_recipient, + prev_randao: request.payload_attributes.prev_randao, + gas_limit: parent.gas_limit(), + parent_beacon_block_root: request.payload_attributes.parent_beacon_block_root, + withdrawals: request.payload_attributes.withdrawals.map(Into::into), + extra_data: request.extra_data, + }; + + let mut builder = evm_config + .builder_for_next_block(&mut db, &parent, env_attrs) + .map_err(RethError::other) + .map_err(Eth::Error::from_eth_err)?; + builder.apply_pre_execution_changes().map_err(Eth::Error::from_eth_err)?; + + let mut total_fees = U256::ZERO; + let base_fee = builder.evm_mut().block().basefee(); + + for tx in request.transactions { + let tx: Recovered> = recover_raw_transaction(&tx)?; + let tip = tx.effective_tip_per_gas(base_fee).unwrap_or_default(); + let gas_used = + builder.execute_transaction(tx).map_err(Eth::Error::from_eth_err)?; + + total_fees += U256::from(tip) * U256::from(gas_used); + } + let outcome = builder.finish(&state).map_err(Eth::Error::from_eth_err)?; + + let requests = outcome + .block + .requests_hash() + .is_some() + .then_some(outcome.execution_result.requests); + + EthBuiltPayload::new( + alloy_rpc_types_engine::PayloadId::default(), + Arc::new(outcome.block.into_sealed_block()), + total_fees, + requests, + ) + .try_into_v5() + .map_err(RethError::other) + .map_err(Eth::Error::from_eth_err) + }) + .await + } +} + +#[async_trait] +impl TestingApiServer for TestingApi +where + Eth: Call>, + Evm: ConfigureEvm + + 'static, +{ + /// Handles `testing_buildBlockV1` by gating concurrency via a semaphore and offloading heavy + /// work to the blocking pool to avoid stalling the async runtime. + async fn build_block_v1( + &self, + request: TestingBuildBlockRequestV1, + ) -> RpcResult { + self.build_block_v1(request).await.map_err(Into::into) + } +} diff --git a/docs/vocs/docs/pages/cli/op-reth/node.mdx b/docs/vocs/docs/pages/cli/op-reth/node.mdx index 2a6450d344..2883cae22c 100644 --- a/docs/vocs/docs/pages/cli/op-reth/node.mdx +++ b/docs/vocs/docs/pages/cli/op-reth/node.mdx @@ -302,7 +302,7 @@ RPC: --http.api Rpc Modules to be configured for the HTTP server - [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev] + [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev, testing] --http.corsdomain Http Corsdomain to allow request from @@ -326,7 +326,7 @@ RPC: --ws.api Rpc Modules to be configured for the WS server - [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev] + [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev, testing] --ipcdisable Disable the IPC-RPC server diff --git a/docs/vocs/docs/pages/cli/reth/node.mdx b/docs/vocs/docs/pages/cli/reth/node.mdx index 6542d0c5bf..076fd06eee 100644 --- a/docs/vocs/docs/pages/cli/reth/node.mdx +++ b/docs/vocs/docs/pages/cli/reth/node.mdx @@ -302,7 +302,7 @@ RPC: --http.api Rpc Modules to be configured for the HTTP server - [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev] + [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev, testing] --http.corsdomain Http Corsdomain to allow request from @@ -326,7 +326,7 @@ RPC: --ws.api Rpc Modules to be configured for the WS server - [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev] + [possible values: admin, debug, eth, net, trace, txpool, web3, rpc, reth, ots, flashbots, miner, mev, testing] --ipcdisable Disable the IPC-RPC server