mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-08 23:08:19 -05:00
Merge branch 'main' into niven/fb-get-block-tx-count
This commit is contained in:
2
.github/workflows/bench.yml
vendored
2
.github/workflows/bench.yml
vendored
@@ -11,6 +11,7 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
BASELINE: base
|
||||
SEED: reth
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
name: bench
|
||||
jobs:
|
||||
@@ -22,6 +23,7 @@ jobs:
|
||||
submodules: true
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
7
.github/workflows/book.yml
vendored
7
.github/workflows/book.yml
vendored
@@ -10,9 +10,12 @@ on:
|
||||
types: [opened, reopened, synchronize, closed]
|
||||
merge_group:
|
||||
|
||||
env:
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest-8
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -33,6 +36,8 @@ jobs:
|
||||
- name: Install Rust nightly
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
|
||||
- name: Build docs
|
||||
run: cd docs/vocs && bash scripts/build-cargo-docs.sh
|
||||
|
||||
|
||||
4
.github/workflows/compact.yml
vendored
4
.github/workflows/compact.yml
vendored
@@ -13,11 +13,12 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
name: compact-codec
|
||||
jobs:
|
||||
compact-codec:
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
bin:
|
||||
@@ -26,6 +27,7 @@ jobs:
|
||||
steps:
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
4
.github/workflows/e2e.yml
vendored
4
.github/workflows/e2e.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
SEED: rustethereumethereumrust
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -19,13 +20,14 @@ concurrency:
|
||||
jobs:
|
||||
test:
|
||||
name: e2e-testsuite
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
|
||||
2
.github/workflows/hive.yml
vendored
2
.github/workflows/hive.yml
vendored
@@ -245,7 +245,7 @@ jobs:
|
||||
notify-on-error:
|
||||
needs: test
|
||||
if: failure()
|
||||
runs-on: depot-ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Webhook Action
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
|
||||
2
.github/workflows/integration.yml
vendored
2
.github/workflows/integration.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
test:
|
||||
name: test / ${{ matrix.network }}
|
||||
if: github.event_name != 'schedule'
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
strategy:
|
||||
|
||||
2
.github/workflows/kurtosis-op.yml
vendored
2
.github/workflows/kurtosis-op.yml
vendored
@@ -85,7 +85,7 @@ jobs:
|
||||
notify-on-error:
|
||||
needs: test
|
||||
if: failure()
|
||||
runs-on: depot-ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Webhook Action
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
|
||||
2
.github/workflows/kurtosis.yml
vendored
2
.github/workflows/kurtosis.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
notify-on-error:
|
||||
needs: test
|
||||
if: failure()
|
||||
runs-on: depot-ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Webhook Action
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
|
||||
12
.github/workflows/lint.yml
vendored
12
.github/workflows/lint.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
clippy:
|
||||
name: clippy
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
|
||||
crate-checks:
|
||||
name: crate-checks (${{ matrix.partition }}/${{ matrix.total_partitions }})
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
strategy:
|
||||
matrix:
|
||||
partition: [1, 2, 3]
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
|
||||
docs:
|
||||
name: docs
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -172,7 +172,7 @@ jobs:
|
||||
|
||||
udeps:
|
||||
name: udeps
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -187,7 +187,7 @@ jobs:
|
||||
|
||||
book:
|
||||
name: book
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -246,7 +246,7 @@ jobs:
|
||||
# Checks that selected crates can compile with power set of features
|
||||
features:
|
||||
name: features (${{ matrix.partition }}/${{ matrix.total_partitions }})
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
partition: [1, 2]
|
||||
|
||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -22,6 +22,7 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
DOCKER_IMAGE_NAME_URL: https://ghcr.io/${{ github.repository_owner }}/reth
|
||||
DOCKER_OP_IMAGE_NAME_URL: https://ghcr.io/${{ github.repository_owner }}/op-reth
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
dry-run:
|
||||
@@ -51,6 +52,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- name: Verify crate version matches tag
|
||||
# Check that the Cargo version starts with the tag,
|
||||
# so that Cargo version 1.4.8 can be matched against both v1.4.8 and v1.4.8-rc.1
|
||||
@@ -104,6 +106,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: ${{ matrix.configs.target }}
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- name: Install cross main
|
||||
id: cross_main
|
||||
run: |
|
||||
|
||||
2
.github/workflows/sync-era.yml
vendored
2
.github/workflows/sync-era.yml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -41,6 +42,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
2
.github/workflows/sync.yml
vendored
2
.github/workflows/sync.yml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
@@ -41,6 +42,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: rui314/setup-mold@v1
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
4
.github/workflows/unit.yml
vendored
4
.github/workflows/unit.yml
vendored
@@ -20,7 +20,7 @@ concurrency:
|
||||
jobs:
|
||||
test:
|
||||
name: test / ${{ matrix.type }} (${{ matrix.partition }}/${{ matrix.total_partitions }})
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest-4
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
strategy:
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
|
||||
doc:
|
||||
name: doc tests
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
timeout-minutes: 30
|
||||
|
||||
4
.github/workflows/windows.yml
vendored
4
.github/workflows/windows.yml
vendored
@@ -14,7 +14,7 @@ env:
|
||||
|
||||
jobs:
|
||||
check-reth:
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
run: cargo check --target x86_64-pc-windows-gnu
|
||||
|
||||
check-op-reth:
|
||||
runs-on: depot-ubuntu-latest-16
|
||||
runs-on: depot-ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
|
||||
26
Cargo.lock
generated
26
Cargo.lock
generated
@@ -238,6 +238,18 @@ dependencies = [
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloy-eip7928"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "926b2c0d34e641cf8b17bf54ce50fda16715b9f68ad878fa6128bae410c6f890"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rlp",
|
||||
"borsh",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloy-eips"
|
||||
version = "1.1.3"
|
||||
@@ -266,9 +278,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-evm"
|
||||
version = "0.25.0"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70cd39002a40b8d528f4a3f8ecc7e59dc2204d9bfae249296d7d379f291f9cba"
|
||||
checksum = "3e7b4fb2418490bca9978e74208215ed5fcb21a10aba7eea487abaa60fd588db"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -383,9 +395,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alloy-op-evm"
|
||||
version = "0.25.0"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bec5d35135e72ab8096f9b7713840725dc0cd0f9e20ed283156808874da76f4"
|
||||
checksum = "56afbe3c3b66435c7c3846fe639a60e4cdbc31b9263596eb2f382408b1b160c4"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eips",
|
||||
@@ -8208,6 +8220,7 @@ name = "reth-engine-tree"
|
||||
version = "1.9.3"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-eip7928",
|
||||
"alloy-eips",
|
||||
"alloy-evm",
|
||||
"alloy-primitives",
|
||||
@@ -9232,6 +9245,7 @@ dependencies = [
|
||||
"alloy-sol-types",
|
||||
"eyre",
|
||||
"futures",
|
||||
"jsonrpsee-core",
|
||||
"rand 0.9.2",
|
||||
"reth-chainspec",
|
||||
"reth-db",
|
||||
@@ -9267,6 +9281,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar-asserts",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -10157,6 +10172,7 @@ dependencies = [
|
||||
"reth-db-api",
|
||||
"reth-engine-primitives",
|
||||
"reth-errors",
|
||||
"reth-ethereum-engine-primitives",
|
||||
"reth-ethereum-primitives",
|
||||
"reth-evm",
|
||||
"reth-evm-ethereum",
|
||||
@@ -10219,7 +10235,9 @@ dependencies = [
|
||||
"reth-network-peers",
|
||||
"reth-rpc-eth-api",
|
||||
"reth-trie-common",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -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" }
|
||||
@@ -487,7 +487,8 @@ revm-inspectors = "0.33.1"
|
||||
alloy-chains = { version = "0.2.5", default-features = false }
|
||||
alloy-dyn-abi = "1.4.1"
|
||||
alloy-eip2124 = { version = "0.2.0", default-features = false }
|
||||
alloy-evm = { version = "0.25.0", default-features = false }
|
||||
alloy-eip7928 = { version = "0.1.0" }
|
||||
alloy-evm = { version = "0.25.1", default-features = false }
|
||||
alloy-primitives = { version = "1.4.1", default-features = false, features = ["map-foldhash"] }
|
||||
alloy-rlp = { version = "0.3.10", default-features = false, features = ["core-net"] }
|
||||
alloy-sol-macro = "1.4.1"
|
||||
|
||||
@@ -93,6 +93,7 @@ impl Command {
|
||||
transaction_senders_in_static_files: _,
|
||||
storages_history_in_rocksdb: _,
|
||||
transaction_hash_numbers_in_rocksdb: _,
|
||||
account_history_in_rocksdb: _,
|
||||
} = settings.unwrap_or_else(StorageSettings::legacy);
|
||||
|
||||
// Update the setting based on the key
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::BlockProvider;
|
||||
use alloy_provider::{ConnectionConfig, Network, Provider, ProviderBuilder};
|
||||
use alloy_provider::{ConnectionConfig, Network, Provider, ProviderBuilder, WebSocketConfig};
|
||||
use alloy_transport::TransportResult;
|
||||
use futures::{Stream, StreamExt};
|
||||
use reth_node_api::Block;
|
||||
@@ -29,7 +29,12 @@ impl<N: Network, PrimitiveBlock> RpcBlockProvider<N, PrimitiveBlock> {
|
||||
ProviderBuilder::default()
|
||||
.connect_with_config(
|
||||
rpc_url,
|
||||
ConnectionConfig::default().with_max_retries(u32::MAX),
|
||||
ConnectionConfig::default().with_max_retries(u32::MAX).with_ws_config(
|
||||
WebSocketConfig::default()
|
||||
// allow larger messages/frames for big blocks
|
||||
.max_frame_size(Some(128 * 1024 * 1024))
|
||||
.max_message_size(Some(128 * 1024 * 1024)),
|
||||
),
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! Engine tree configuration.
|
||||
|
||||
use alloy_eips::merge::EPOCH_SLOTS;
|
||||
|
||||
/// Triggers persistence when the number of canonical blocks in memory exceeds this threshold.
|
||||
pub const DEFAULT_PERSISTENCE_THRESHOLD: u64 = 2;
|
||||
|
||||
@@ -40,7 +42,7 @@ pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
|
||||
/// Default maximum concurrency for prewarm task.
|
||||
pub const DEFAULT_PREWARM_MAX_CONCURRENCY: usize = 16;
|
||||
|
||||
const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = 256;
|
||||
const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = EPOCH_SLOTS as u32 * 2;
|
||||
const DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH: u32 = 256;
|
||||
const DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE: usize = 4;
|
||||
const DEFAULT_CROSS_BLOCK_CACHE_SIZE: u64 = 4 * 1024 * 1024 * 1024;
|
||||
|
||||
@@ -39,6 +39,7 @@ reth-trie.workspace = true
|
||||
alloy-evm.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
alloy-eips.workspace = true
|
||||
alloy-eip7928.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
alloy-rlp.workspace = true
|
||||
alloy-rpc-types-engine.workspace = true
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::tree::{
|
||||
StateProviderDatabase, TreeConfig,
|
||||
};
|
||||
use alloy_consensus::transaction::Either;
|
||||
use alloy_eip7928::BlockAccessList;
|
||||
use alloy_eips::{eip1898::BlockWithParent, NumHash};
|
||||
use alloy_evm::Evm;
|
||||
use alloy_primitives::B256;
|
||||
@@ -1243,4 +1244,10 @@ impl<T: PayloadTypes> BlockOrPayload<T> {
|
||||
Self::Block(_) => "block",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the block access list if available.
|
||||
pub const fn block_access_list(&self) -> Option<Result<BlockAccessList, alloy_rlp::Error>> {
|
||||
// TODO decode and return `BlockAccessList`
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ use alloy_consensus::{
|
||||
};
|
||||
use alloy_eips::merge::BEACON_NONCE;
|
||||
use alloy_evm::{block::BlockExecutorFactory, eth::EthBlockExecutionCtx};
|
||||
use alloy_primitives::Bytes;
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||
use reth_evm::execute::{BlockAssembler, BlockAssemblerInput, BlockExecutionError};
|
||||
use reth_execution_types::BlockExecutionResult;
|
||||
@@ -17,14 +16,12 @@ use revm::context::Block as _;
|
||||
pub struct EthBlockAssembler<ChainSpec = reth_chainspec::ChainSpec> {
|
||||
/// The chainspec.
|
||||
pub chain_spec: Arc<ChainSpec>,
|
||||
/// Extra data to use for the blocks.
|
||||
pub extra_data: Bytes,
|
||||
}
|
||||
|
||||
impl<ChainSpec> EthBlockAssembler<ChainSpec> {
|
||||
/// Creates a new [`EthBlockAssembler`].
|
||||
pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec, extra_data: Default::default() }
|
||||
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
Self { chain_spec }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +107,7 @@ where
|
||||
gas_limit: evm_env.block_env.gas_limit(),
|
||||
difficulty: evm_env.block_env.difficulty(),
|
||||
gas_used: *gas_used,
|
||||
extra_data: self.extra_data.clone(),
|
||||
extra_data: ctx.extra_data,
|
||||
parent_beacon_block_root: ctx.parent_beacon_block_root,
|
||||
blob_gas_used: block_blob_gas_used,
|
||||
excess_blob_gas,
|
||||
|
||||
@@ -116,12 +116,6 @@ impl<ChainSpec, EvmFactory> EthEvmConfig<ChainSpec, EvmFactory> {
|
||||
pub const fn chain_spec(&self) -> &Arc<ChainSpec> {
|
||||
self.executor_factory.spec()
|
||||
}
|
||||
|
||||
/// Sets the extra data for the block assembler.
|
||||
pub fn with_extra_data(mut self, extra_data: Bytes) -> Self {
|
||||
self.block_assembler.extra_data = extra_data;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<ChainSpec, EvmF> ConfigureEvm for EthEvmConfig<ChainSpec, EvmF>
|
||||
@@ -193,6 +187,7 @@ where
|
||||
parent_beacon_block_root: block.header().parent_beacon_block_root,
|
||||
ommers: &block.body().ommers,
|
||||
withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed),
|
||||
extra_data: block.header().extra_data.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -206,6 +201,7 @@ where
|
||||
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
||||
ommers: &[],
|
||||
withdrawals: attributes.withdrawals.map(Cow::Owned),
|
||||
extra_data: attributes.extra_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -282,6 +278,7 @@ where
|
||||
parent_beacon_block_root: payload.sidecar.parent_beacon_block_root(),
|
||||
ommers: &[],
|
||||
withdrawals: payload.payload.withdrawals().map(|w| Cow::Owned(w.clone().into())),
|
||||
extra_data: payload.payload.as_v1().extra_data.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,15 +32,15 @@ use reth_node_builder::{
|
||||
EngineValidatorBuilder, EthApiBuilder, EthApiCtx, Identity, PayloadValidatorBuilder,
|
||||
RethRpcAddOns, RpcAddOns, RpcHandle,
|
||||
},
|
||||
BuilderContext, DebugNode, Node, NodeAdapter, PayloadBuilderConfig,
|
||||
BuilderContext, DebugNode, Node, NodeAdapter,
|
||||
};
|
||||
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
|
||||
@@ -426,9 +437,7 @@ where
|
||||
type EVM = EthEvmConfig<Types::ChainSpec>;
|
||||
|
||||
async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
|
||||
let evm_config = EthEvmConfig::new(ctx.chain_spec())
|
||||
.with_extra_data(ctx.payload_builder_config().extra_data_bytes());
|
||||
Ok(evm_config)
|
||||
Ok(EthEvmConfig::new(ctx.chain_spec()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ where
|
||||
evm_config,
|
||||
EthereumBuilderConfig::new()
|
||||
.with_gas_limit(gas_limit)
|
||||
.with_max_blobs_per_block(conf.max_blobs_per_block()),
|
||||
.with_max_blobs_per_block(conf.max_blobs_per_block())
|
||||
.with_extra_data(conf.extra_data_bytes()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
mod builder;
|
||||
mod exex;
|
||||
mod testing;
|
||||
|
||||
const fn main() {}
|
||||
|
||||
84
crates/ethereum/node/tests/it/testing.rs
Normal file
84
crates/ethereum/node/tests/it/testing.rs
Normal file
@@ -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::<DataDirPath>::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<eyre::Result<ExecutionPayloadEnvelopeV4>>,
|
||||
oneshot::Receiver<eyre::Result<ExecutionPayloadEnvelopeV4>>,
|
||||
) = oneshot::channel();
|
||||
|
||||
let builder = NodeBuilder::new(config)
|
||||
.with_database(db)
|
||||
.with_launch_context(tasks.executor())
|
||||
.with_types::<EthereumNode>()
|
||||
.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<ExecutionPayloadEnvelopeV4> =
|
||||
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(())
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use alloy_eips::eip1559::ETHEREUM_BLOCK_GAS_LIMIT_30M;
|
||||
use alloy_primitives::Bytes;
|
||||
use reth_primitives_traits::constants::GAS_LIMIT_BOUND_DIVISOR;
|
||||
|
||||
/// Settings for the Ethereum builder.
|
||||
@@ -13,6 +14,8 @@ pub struct EthereumBuilderConfig {
|
||||
///
|
||||
/// If `None`, defaults to the protocol maximum.
|
||||
pub max_blobs_per_block: Option<u64>,
|
||||
/// Extra data for built blocks.
|
||||
pub extra_data: Bytes,
|
||||
}
|
||||
|
||||
impl Default for EthereumBuilderConfig {
|
||||
@@ -28,6 +31,7 @@ impl EthereumBuilderConfig {
|
||||
desired_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT_30M,
|
||||
await_payload_on_missing: true,
|
||||
max_blobs_per_block: None,
|
||||
extra_data: Bytes::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +53,12 @@ impl EthereumBuilderConfig {
|
||||
self.max_blobs_per_block = max_blobs_per_block;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the extra data for built blocks.
|
||||
pub fn with_extra_data(mut self, extra_data: Bytes) -> Self {
|
||||
self.extra_data = extra_data;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl EthereumBuilderConfig {
|
||||
|
||||
@@ -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: builder_config.extra_data,
|
||||
},
|
||||
)
|
||||
.map_err(PayloadBuilderError::other)?;
|
||||
|
||||
@@ -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<B256>,
|
||||
/// Withdrawals
|
||||
pub withdrawals: Option<Withdrawals>,
|
||||
/// Optional extra data.
|
||||
pub extra_data: Bytes,
|
||||
}
|
||||
|
||||
/// Abstraction over transaction environment.
|
||||
|
||||
@@ -859,8 +859,8 @@ impl<Node: FullNodeTypes> BuilderContext<Node> {
|
||||
.request_handler(self.provider().clone())
|
||||
.split_with_handle();
|
||||
|
||||
self.executor.spawn_critical("p2p txpool", Box::pin(txpool));
|
||||
self.executor.spawn_critical("p2p eth request handler", Box::pin(eth));
|
||||
self.executor.spawn_critical_blocking("p2p txpool", Box::pin(txpool));
|
||||
self.executor.spawn_critical_blocking("p2p eth request handler", Box::pin(eth));
|
||||
|
||||
let default_peers_path = self.config().datadir().known_peers();
|
||||
let known_peers_file = self.config().network.persistent_peers_file(default_peers_path);
|
||||
|
||||
@@ -1179,6 +1179,7 @@ impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumH
|
||||
.proof_permits(self.config.proof_permits)
|
||||
.gas_oracle_config(self.config.gas_oracle)
|
||||
.max_batch_size(self.config.max_batch_size)
|
||||
.max_blocking_io_requests(self.config.max_blocking_io_requests)
|
||||
.pending_block_kind(self.config.pending_block_kind)
|
||||
.raw_tx_forwarder(self.config.raw_tx_forwarder)
|
||||
.evm_memory_limit(self.config.rpc_evm_memory_limit)
|
||||
|
||||
@@ -6,7 +6,7 @@ pub use network::{DiscoveryArgs, NetworkArgs};
|
||||
|
||||
/// RpcServerArg struct for configuring the RPC
|
||||
mod rpc_server;
|
||||
pub use rpc_server::RpcServerArgs;
|
||||
pub use rpc_server::{DefaultRpcServerArgs, RpcServerArgs};
|
||||
|
||||
/// `RpcStateCacheArgs` struct for configuring RPC state cache
|
||||
mod rpc_state_cache;
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::args::{
|
||||
use alloy_primitives::Address;
|
||||
use alloy_rpc_types_engine::JwtSecret;
|
||||
use clap::{
|
||||
builder::{PossibleValue, RangedU64ValueParser, TypedValueParser},
|
||||
builder::{PossibleValue, RangedU64ValueParser, Resettable, TypedValueParser},
|
||||
Arg, Args, Command,
|
||||
};
|
||||
use rand::Rng;
|
||||
@@ -19,12 +19,16 @@ use std::{
|
||||
ffi::OsStr,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
sync::OnceLock,
|
||||
time::Duration,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use super::types::MaxOr;
|
||||
|
||||
/// Global static RPC server defaults
|
||||
static RPC_SERVER_DEFAULTS: OnceLock<DefaultRpcServerArgs> = OnceLock::new();
|
||||
|
||||
/// Default max number of subscriptions per connection.
|
||||
pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024;
|
||||
|
||||
@@ -37,76 +41,442 @@ pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15;
|
||||
pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160;
|
||||
|
||||
/// Default number of incoming connections.
|
||||
///
|
||||
/// This restricts how many active connections (http, ws) the server accepts.
|
||||
/// Once exceeded, the server can reject new connections.
|
||||
pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500;
|
||||
|
||||
/// Default values for RPC server that can be customized
|
||||
///
|
||||
/// Global defaults can be set via [`DefaultRpcServerArgs::try_init`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DefaultRpcServerArgs {
|
||||
http: bool,
|
||||
http_addr: IpAddr,
|
||||
http_port: u16,
|
||||
http_disable_compression: bool,
|
||||
http_api: Option<RpcModuleSelection>,
|
||||
http_corsdomain: Option<String>,
|
||||
ws: bool,
|
||||
ws_addr: IpAddr,
|
||||
ws_port: u16,
|
||||
ws_allowed_origins: Option<String>,
|
||||
ws_api: Option<RpcModuleSelection>,
|
||||
ipcdisable: bool,
|
||||
ipcpath: String,
|
||||
ipc_socket_permissions: Option<String>,
|
||||
auth_addr: IpAddr,
|
||||
auth_port: u16,
|
||||
auth_jwtsecret: Option<PathBuf>,
|
||||
auth_ipc: bool,
|
||||
auth_ipc_path: String,
|
||||
disable_auth_server: bool,
|
||||
rpc_jwtsecret: Option<JwtSecret>,
|
||||
rpc_max_request_size: MaxU32,
|
||||
rpc_max_response_size: MaxU32,
|
||||
rpc_max_subscriptions_per_connection: MaxU32,
|
||||
rpc_max_connections: MaxU32,
|
||||
rpc_max_tracing_requests: usize,
|
||||
rpc_max_blocking_io_requests: usize,
|
||||
rpc_max_trace_filter_blocks: u64,
|
||||
rpc_max_blocks_per_filter: ZeroAsNoneU64,
|
||||
rpc_max_logs_per_response: ZeroAsNoneU64,
|
||||
rpc_gas_cap: u64,
|
||||
rpc_evm_memory_limit: u64,
|
||||
rpc_tx_fee_cap: u128,
|
||||
rpc_max_simulate_blocks: u64,
|
||||
rpc_eth_proof_window: u64,
|
||||
rpc_proof_permits: usize,
|
||||
rpc_pending_block: PendingBlockKind,
|
||||
rpc_forwarder: Option<Url>,
|
||||
builder_disallow: Option<HashSet<Address>>,
|
||||
rpc_state_cache: RpcStateCacheArgs,
|
||||
gas_price_oracle: GasPriceOracleArgs,
|
||||
rpc_send_raw_transaction_sync_timeout: Duration,
|
||||
}
|
||||
|
||||
impl DefaultRpcServerArgs {
|
||||
/// Initialize the global RPC server defaults with this configuration
|
||||
pub fn try_init(self) -> Result<(), Self> {
|
||||
RPC_SERVER_DEFAULTS.set(self)
|
||||
}
|
||||
|
||||
/// Get a reference to the global RPC server defaults
|
||||
pub fn get_global() -> &'static Self {
|
||||
RPC_SERVER_DEFAULTS.get_or_init(Self::default)
|
||||
}
|
||||
|
||||
/// Set the default HTTP enabled state
|
||||
pub const fn with_http(mut self, v: bool) -> Self {
|
||||
self.http = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP address
|
||||
pub const fn with_http_addr(mut self, v: IpAddr) -> Self {
|
||||
self.http_addr = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP port
|
||||
pub const fn with_http_port(mut self, v: u16) -> Self {
|
||||
self.http_port = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable HTTP compression by default
|
||||
pub const fn with_http_disable_compression(mut self, v: bool) -> Self {
|
||||
self.http_disable_compression = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP API modules
|
||||
pub fn with_http_api(mut self, v: Option<RpcModuleSelection>) -> Self {
|
||||
self.http_api = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default HTTP CORS domain
|
||||
pub fn with_http_corsdomain(mut self, v: Option<String>) -> Self {
|
||||
self.http_corsdomain = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS enabled state
|
||||
pub const fn with_ws(mut self, v: bool) -> Self {
|
||||
self.ws = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS address
|
||||
pub const fn with_ws_addr(mut self, v: IpAddr) -> Self {
|
||||
self.ws_addr = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS port
|
||||
pub const fn with_ws_port(mut self, v: u16) -> Self {
|
||||
self.ws_port = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS allowed origins
|
||||
pub fn with_ws_allowed_origins(mut self, v: Option<String>) -> Self {
|
||||
self.ws_allowed_origins = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default WS API modules
|
||||
pub fn with_ws_api(mut self, v: Option<RpcModuleSelection>) -> Self {
|
||||
self.ws_api = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable IPC by default
|
||||
pub const fn with_ipcdisable(mut self, v: bool) -> Self {
|
||||
self.ipcdisable = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default IPC path
|
||||
pub fn with_ipcpath(mut self, v: String) -> Self {
|
||||
self.ipcpath = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default IPC socket permissions
|
||||
pub fn with_ipc_socket_permissions(mut self, v: Option<String>) -> Self {
|
||||
self.ipc_socket_permissions = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth server address
|
||||
pub const fn with_auth_addr(mut self, v: IpAddr) -> Self {
|
||||
self.auth_addr = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth server port
|
||||
pub const fn with_auth_port(mut self, v: u16) -> Self {
|
||||
self.auth_port = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth JWT secret path
|
||||
pub fn with_auth_jwtsecret(mut self, v: Option<PathBuf>) -> Self {
|
||||
self.auth_jwtsecret = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth IPC enabled state
|
||||
pub const fn with_auth_ipc(mut self, v: bool) -> Self {
|
||||
self.auth_ipc = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default auth IPC path
|
||||
pub fn with_auth_ipc_path(mut self, v: String) -> Self {
|
||||
self.auth_ipc_path = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to disable the auth server by default
|
||||
pub const fn with_disable_auth_server(mut self, v: bool) -> Self {
|
||||
self.disable_auth_server = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default RPC JWT secret
|
||||
pub const fn with_rpc_jwtsecret(mut self, v: Option<JwtSecret>) -> Self {
|
||||
self.rpc_jwtsecret = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max request size
|
||||
pub const fn with_rpc_max_request_size(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_request_size = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max response size
|
||||
pub const fn with_rpc_max_response_size(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_response_size = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max subscriptions per connection
|
||||
pub const fn with_rpc_max_subscriptions_per_connection(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_subscriptions_per_connection = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max connections
|
||||
pub const fn with_rpc_max_connections(mut self, v: MaxU32) -> Self {
|
||||
self.rpc_max_connections = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max tracing requests
|
||||
pub const fn with_rpc_max_tracing_requests(mut self, v: usize) -> Self {
|
||||
self.rpc_max_tracing_requests = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max blocking IO requests
|
||||
pub const fn with_rpc_max_blocking_io_requests(mut self, v: usize) -> Self {
|
||||
self.rpc_max_blocking_io_requests = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max trace filter blocks
|
||||
pub const fn with_rpc_max_trace_filter_blocks(mut self, v: u64) -> Self {
|
||||
self.rpc_max_trace_filter_blocks = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max blocks per filter
|
||||
pub const fn with_rpc_max_blocks_per_filter(mut self, v: ZeroAsNoneU64) -> Self {
|
||||
self.rpc_max_blocks_per_filter = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max logs per response
|
||||
pub const fn with_rpc_max_logs_per_response(mut self, v: ZeroAsNoneU64) -> Self {
|
||||
self.rpc_max_logs_per_response = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default gas cap
|
||||
pub const fn with_rpc_gas_cap(mut self, v: u64) -> Self {
|
||||
self.rpc_gas_cap = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default EVM memory limit
|
||||
pub const fn with_rpc_evm_memory_limit(mut self, v: u64) -> Self {
|
||||
self.rpc_evm_memory_limit = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default tx fee cap
|
||||
pub const fn with_rpc_tx_fee_cap(mut self, v: u128) -> Self {
|
||||
self.rpc_tx_fee_cap = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default max simulate blocks
|
||||
pub const fn with_rpc_max_simulate_blocks(mut self, v: u64) -> Self {
|
||||
self.rpc_max_simulate_blocks = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default eth proof window
|
||||
pub const fn with_rpc_eth_proof_window(mut self, v: u64) -> Self {
|
||||
self.rpc_eth_proof_window = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default proof permits
|
||||
pub const fn with_rpc_proof_permits(mut self, v: usize) -> Self {
|
||||
self.rpc_proof_permits = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default pending block kind
|
||||
pub const fn with_rpc_pending_block(mut self, v: PendingBlockKind) -> Self {
|
||||
self.rpc_pending_block = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default RPC forwarder
|
||||
pub fn with_rpc_forwarder(mut self, v: Option<Url>) -> Self {
|
||||
self.rpc_forwarder = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default builder disallow addresses
|
||||
pub fn with_builder_disallow(mut self, v: Option<HashSet<Address>>) -> Self {
|
||||
self.builder_disallow = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default RPC state cache args
|
||||
pub const fn with_rpc_state_cache(mut self, v: RpcStateCacheArgs) -> Self {
|
||||
self.rpc_state_cache = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default gas price oracle args
|
||||
pub const fn with_gas_price_oracle(mut self, v: GasPriceOracleArgs) -> Self {
|
||||
self.gas_price_oracle = v;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the default send raw transaction sync timeout
|
||||
pub const fn with_rpc_send_raw_transaction_sync_timeout(mut self, v: Duration) -> Self {
|
||||
self.rpc_send_raw_transaction_sync_timeout = v;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DefaultRpcServerArgs {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
http: false,
|
||||
http_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
http_port: constants::DEFAULT_HTTP_RPC_PORT,
|
||||
http_disable_compression: false,
|
||||
http_api: None,
|
||||
http_corsdomain: None,
|
||||
ws: false,
|
||||
ws_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
ws_port: constants::DEFAULT_WS_RPC_PORT,
|
||||
ws_allowed_origins: None,
|
||||
ws_api: None,
|
||||
ipcdisable: false,
|
||||
ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
|
||||
ipc_socket_permissions: None,
|
||||
auth_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
auth_port: constants::DEFAULT_AUTH_PORT,
|
||||
auth_jwtsecret: None,
|
||||
auth_ipc: false,
|
||||
auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
|
||||
disable_auth_server: false,
|
||||
rpc_jwtsecret: None,
|
||||
rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
|
||||
rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
|
||||
rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
|
||||
rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
|
||||
rpc_max_tracing_requests: constants::default_max_tracing_requests(),
|
||||
rpc_max_blocking_io_requests: constants::DEFAULT_MAX_BLOCKING_IO_REQUEST,
|
||||
rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
|
||||
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: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
|
||||
rpc_evm_memory_limit: (1 << 32) - 1,
|
||||
rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
|
||||
rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
|
||||
rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
|
||||
rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
|
||||
rpc_pending_block: PendingBlockKind::Full,
|
||||
rpc_forwarder: None,
|
||||
builder_disallow: None,
|
||||
rpc_state_cache: RpcStateCacheArgs::default(),
|
||||
gas_price_oracle: GasPriceOracleArgs::default(),
|
||||
rpc_send_raw_transaction_sync_timeout:
|
||||
constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters for configuring the rpc more granularity via CLI
|
||||
#[derive(Debug, Clone, Args, PartialEq, Eq)]
|
||||
#[command(next_help_heading = "RPC")]
|
||||
pub struct RpcServerArgs {
|
||||
/// Enable the HTTP-RPC server
|
||||
#[arg(long, default_value_if("dev", "true", "true"))]
|
||||
#[arg(long, default_value_if("dev", "true", "true"), default_value_t = DefaultRpcServerArgs::get_global().http)]
|
||||
pub http: bool,
|
||||
|
||||
/// Http server address to listen on
|
||||
#[arg(long = "http.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
|
||||
#[arg(long = "http.addr", default_value_t = DefaultRpcServerArgs::get_global().http_addr)]
|
||||
pub http_addr: IpAddr,
|
||||
|
||||
/// Http server port to listen on
|
||||
#[arg(long = "http.port", default_value_t = constants::DEFAULT_HTTP_RPC_PORT)]
|
||||
#[arg(long = "http.port", default_value_t = DefaultRpcServerArgs::get_global().http_port)]
|
||||
pub http_port: u16,
|
||||
|
||||
/// Disable compression for HTTP responses
|
||||
#[arg(long = "http.disable-compression", default_value_t = false)]
|
||||
#[arg(long = "http.disable-compression", default_value_t = DefaultRpcServerArgs::get_global().http_disable_compression)]
|
||||
pub http_disable_compression: bool,
|
||||
|
||||
/// Rpc Modules to be configured for the HTTP server
|
||||
#[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default())]
|
||||
#[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default(), default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_api.as_ref().map(|v| v.to_string().into())))]
|
||||
pub http_api: Option<RpcModuleSelection>,
|
||||
|
||||
/// Http Corsdomain to allow request from
|
||||
#[arg(long = "http.corsdomain")]
|
||||
#[arg(long = "http.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().http_corsdomain.as_ref().map(|v| v.to_string().into())))]
|
||||
pub http_corsdomain: Option<String>,
|
||||
|
||||
/// Enable the WS-RPC server
|
||||
#[arg(long)]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ws)]
|
||||
pub ws: bool,
|
||||
|
||||
/// Ws server address to listen on
|
||||
#[arg(long = "ws.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
|
||||
#[arg(long = "ws.addr", default_value_t = DefaultRpcServerArgs::get_global().ws_addr)]
|
||||
pub ws_addr: IpAddr,
|
||||
|
||||
/// Ws server port to listen on
|
||||
#[arg(long = "ws.port", default_value_t = constants::DEFAULT_WS_RPC_PORT)]
|
||||
#[arg(long = "ws.port", default_value_t = DefaultRpcServerArgs::get_global().ws_port)]
|
||||
pub ws_port: u16,
|
||||
|
||||
/// Origins from which to accept `WebSocket` requests
|
||||
#[arg(id = "ws.origins", long = "ws.origins", alias = "ws.corsdomain")]
|
||||
#[arg(id = "ws.origins", long = "ws.origins", alias = "ws.corsdomain", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ws_allowed_origins.as_ref().map(|v| v.to_string().into())))]
|
||||
pub ws_allowed_origins: Option<String>,
|
||||
|
||||
/// Rpc Modules to be configured for the WS server
|
||||
#[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default())]
|
||||
#[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default(), default_value = Resettable::from(DefaultRpcServerArgs::get_global().ws_api.as_ref().map(|v| v.to_string().into())))]
|
||||
pub ws_api: Option<RpcModuleSelection>,
|
||||
|
||||
/// Disable the IPC-RPC server
|
||||
#[arg(long)]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcdisable)]
|
||||
pub ipcdisable: bool,
|
||||
|
||||
/// Filename for IPC socket/pipe within the datadir
|
||||
#[arg(long, default_value_t = constants::DEFAULT_IPC_ENDPOINT.to_string())]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().ipcpath.clone())]
|
||||
pub ipcpath: String,
|
||||
|
||||
/// Set the permissions for the IPC socket file, in octal format.
|
||||
///
|
||||
/// If not specified, the permissions will be set by the system's umask.
|
||||
#[arg(long = "ipc.permissions")]
|
||||
#[arg(long = "ipc.permissions", default_value = Resettable::from(DefaultRpcServerArgs::get_global().ipc_socket_permissions.as_ref().map(|v| v.to_string().into())))]
|
||||
pub ipc_socket_permissions: Option<String>,
|
||||
|
||||
/// Auth server address to listen on
|
||||
#[arg(long = "authrpc.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
|
||||
#[arg(long = "authrpc.addr", default_value_t = DefaultRpcServerArgs::get_global().auth_addr)]
|
||||
pub auth_addr: IpAddr,
|
||||
|
||||
/// Auth server port to listen on
|
||||
#[arg(long = "authrpc.port", default_value_t = constants::DEFAULT_AUTH_PORT)]
|
||||
#[arg(long = "authrpc.port", default_value_t = DefaultRpcServerArgs::get_global().auth_port)]
|
||||
pub auth_port: u16,
|
||||
|
||||
/// Path to a JWT secret to use for the authenticated engine-API RPC server.
|
||||
@@ -115,22 +485,22 @@ pub struct RpcServerArgs {
|
||||
///
|
||||
/// If no path is provided, a secret will be generated and stored in the datadir under
|
||||
/// `<DIR>/<CHAIN_ID>/jwt.hex`. For mainnet this would be `~/.reth/mainnet/jwt.hex` by default.
|
||||
#[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false)]
|
||||
#[arg(long = "authrpc.jwtsecret", value_name = "PATH", global = true, required = false, default_value = Resettable::from(DefaultRpcServerArgs::get_global().auth_jwtsecret.as_ref().map(|v| v.to_string_lossy().into())))]
|
||||
pub auth_jwtsecret: Option<PathBuf>,
|
||||
|
||||
/// Enable auth engine API over IPC
|
||||
#[arg(long)]
|
||||
#[arg(long, default_value_t = DefaultRpcServerArgs::get_global().auth_ipc)]
|
||||
pub auth_ipc: bool,
|
||||
|
||||
/// Filename for auth IPC socket/pipe within the datadir
|
||||
#[arg(long = "auth-ipc.path", default_value_t = constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string())]
|
||||
#[arg(long = "auth-ipc.path", default_value_t = DefaultRpcServerArgs::get_global().auth_ipc_path.clone())]
|
||||
pub auth_ipc_path: String,
|
||||
|
||||
/// Disable the auth/engine API server.
|
||||
///
|
||||
/// This will prevent the authenticated engine-API server from starting. Use this if you're
|
||||
/// running a node that doesn't need to serve engine API requests.
|
||||
#[arg(long = "disable-auth-server", alias = "disable-engine-api")]
|
||||
#[arg(long = "disable-auth-server", alias = "disable-engine-api", default_value_t = DefaultRpcServerArgs::get_global().disable_auth_server)]
|
||||
pub disable_auth_server: bool,
|
||||
|
||||
/// Hex encoded JWT secret to authenticate the regular RPC server(s), see `--http.api` and
|
||||
@@ -138,23 +508,23 @@ pub struct RpcServerArgs {
|
||||
///
|
||||
/// This is __not__ used for the authenticated engine-API RPC server, see
|
||||
/// `--authrpc.jwtsecret`.
|
||||
#[arg(long = "rpc.jwtsecret", value_name = "HEX", global = true, required = false)]
|
||||
#[arg(long = "rpc.jwtsecret", value_name = "HEX", global = true, required = false, default_value = Resettable::from(DefaultRpcServerArgs::get_global().rpc_jwtsecret.as_ref().map(|v| format!("{:?}", v).into())))]
|
||||
pub rpc_jwtsecret: Option<JwtSecret>,
|
||||
|
||||
/// Set the maximum RPC request payload size for both HTTP and WS in megabytes.
|
||||
#[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into())]
|
||||
#[arg(long = "rpc.max-request-size", alias = "rpc-max-request-size", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_request_size)]
|
||||
pub rpc_max_request_size: MaxU32,
|
||||
|
||||
/// Set the maximum RPC response payload size for both HTTP and WS in megabytes.
|
||||
#[arg(long = "rpc.max-response-size", alias = "rpc-max-response-size", visible_alias = "rpc.returndata.limit", default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into())]
|
||||
#[arg(long = "rpc.max-response-size", alias = "rpc-max-response-size", visible_alias = "rpc.returndata.limit", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_response_size)]
|
||||
pub rpc_max_response_size: MaxU32,
|
||||
|
||||
/// Set the maximum concurrent subscriptions per connection.
|
||||
#[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN.into())]
|
||||
#[arg(long = "rpc.max-subscriptions-per-connection", alias = "rpc-max-subscriptions-per-connection", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_subscriptions_per_connection)]
|
||||
pub rpc_max_subscriptions_per_connection: MaxU32,
|
||||
|
||||
/// Maximum number of RPC server connections.
|
||||
#[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS.into())]
|
||||
#[arg(long = "rpc.max-connections", alias = "rpc-max-connections", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_connections)]
|
||||
pub rpc_max_connections: MaxU32,
|
||||
|
||||
/// Maximum number of concurrent tracing requests.
|
||||
@@ -163,19 +533,27 @@ pub struct RpcServerArgs {
|
||||
/// Tracing requests are generally CPU bound.
|
||||
/// Choosing a value that is higher than the available CPU cores can have a negative impact on
|
||||
/// the performance of the node and affect the node's ability to maintain sync.
|
||||
#[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = constants::default_max_tracing_requests())]
|
||||
#[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_tracing_requests)]
|
||||
pub rpc_max_tracing_requests: usize,
|
||||
|
||||
/// Maximum number of concurrent blocking IO requests.
|
||||
///
|
||||
/// Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that
|
||||
/// require EVM execution. These are spawned as blocking tasks to avoid blocking the async
|
||||
/// runtime.
|
||||
#[arg(long = "rpc.max-blocking-io-requests", alias = "rpc-max-blocking-io-requests", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_blocking_io_requests)]
|
||||
pub rpc_max_blocking_io_requests: usize,
|
||||
|
||||
/// Maximum number of blocks for `trace_filter` requests.
|
||||
#[arg(long = "rpc.max-trace-filter-blocks", alias = "rpc-max-trace-filter-blocks", value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS)]
|
||||
#[arg(long = "rpc.max-trace-filter-blocks", alias = "rpc-max-trace-filter-blocks", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_trace_filter_blocks)]
|
||||
pub rpc_max_trace_filter_blocks: u64,
|
||||
|
||||
/// Maximum number of blocks that could be scanned per filter request. (0 = entire chain)
|
||||
#[arg(long = "rpc.max-blocks-per-filter", alias = "rpc-max-blocks-per-filter", value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_BLOCKS_PER_FILTER))]
|
||||
#[arg(long = "rpc.max-blocks-per-filter", alias = "rpc-max-blocks-per-filter", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_blocks_per_filter)]
|
||||
pub rpc_max_blocks_per_filter: ZeroAsNoneU64,
|
||||
|
||||
/// Maximum number of logs that can be returned in a single response. (0 = no limit)
|
||||
#[arg(long = "rpc.max-logs-per-response", alias = "rpc-max-logs-per-response", value_name = "COUNT", default_value_t = ZeroAsNoneU64::new(constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64))]
|
||||
#[arg(long = "rpc.max-logs-per-response", alias = "rpc-max-logs-per-response", value_name = "COUNT", default_value_t = DefaultRpcServerArgs::get_global().rpc_max_logs_per_response)]
|
||||
pub rpc_max_logs_per_response: ZeroAsNoneU64,
|
||||
|
||||
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
|
||||
@@ -184,7 +562,7 @@ pub struct RpcServerArgs {
|
||||
alias = "rpc-gascap",
|
||||
value_name = "GAS_CAP",
|
||||
value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
|
||||
default_value_t = constants::gas_oracle::RPC_DEFAULT_GAS_CAP
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_gas_cap
|
||||
)]
|
||||
pub rpc_gas_cap: u64,
|
||||
|
||||
@@ -194,7 +572,7 @@ pub struct RpcServerArgs {
|
||||
alias = "rpc-evm-memory-limit",
|
||||
value_name = "MEMORY_LIMIT",
|
||||
value_parser = MaxOr::new(RangedU64ValueParser::<u64>::new().range(1..)),
|
||||
default_value_t = (1 << 32) - 1
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_evm_memory_limit
|
||||
)]
|
||||
pub rpc_evm_memory_limit: u64,
|
||||
|
||||
@@ -212,7 +590,7 @@ pub struct RpcServerArgs {
|
||||
#[arg(
|
||||
long = "rpc.max-simulate-blocks",
|
||||
value_name = "BLOCKS_COUNT",
|
||||
default_value_t = constants::DEFAULT_MAX_SIMULATE_BLOCKS
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_max_simulate_blocks
|
||||
)]
|
||||
pub rpc_max_simulate_blocks: u64,
|
||||
|
||||
@@ -221,7 +599,7 @@ pub struct RpcServerArgs {
|
||||
/// configured number of blocks from current tip (up to `tip - window`).
|
||||
#[arg(
|
||||
long = "rpc.eth-proof-window",
|
||||
default_value_t = constants::DEFAULT_ETH_PROOF_WINDOW,
|
||||
default_value_t = DefaultRpcServerArgs::get_global().rpc_eth_proof_window,
|
||||
value_parser = RangedU64ValueParser::<u64>::new().range(..=constants::MAX_ETH_PROOF_WINDOW)
|
||||
)]
|
||||
pub rpc_eth_proof_window: u64,
|
||||
@@ -243,7 +621,7 @@ pub struct RpcServerArgs {
|
||||
|
||||
/// Path to file containing disallowed addresses, json-encoded list of strings. Block
|
||||
/// validation API will reject blocks containing transactions from these addresses.
|
||||
#[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::<HashSet<Address>>)]
|
||||
#[arg(long = "builder.disallow", value_name = "PATH", value_parser = reth_cli_util::parsers::read_json_from_file::<HashSet<Address>>, default_value = Resettable::from(DefaultRpcServerArgs::get_global().builder_disallow.as_ref().map(|v| format!("{:?}", v).into())))]
|
||||
pub builder_disallow: Option<HashSet<Address>>,
|
||||
|
||||
/// State cache configuration.
|
||||
@@ -387,49 +765,93 @@ impl RpcServerArgs {
|
||||
|
||||
impl Default for RpcServerArgs {
|
||||
fn default() -> Self {
|
||||
let DefaultRpcServerArgs {
|
||||
http,
|
||||
http_addr,
|
||||
http_port,
|
||||
http_disable_compression,
|
||||
http_api,
|
||||
http_corsdomain,
|
||||
ws,
|
||||
ws_addr,
|
||||
ws_port,
|
||||
ws_allowed_origins,
|
||||
ws_api,
|
||||
ipcdisable,
|
||||
ipcpath,
|
||||
ipc_socket_permissions,
|
||||
auth_addr,
|
||||
auth_port,
|
||||
auth_jwtsecret,
|
||||
auth_ipc,
|
||||
auth_ipc_path,
|
||||
disable_auth_server,
|
||||
rpc_jwtsecret,
|
||||
rpc_max_request_size,
|
||||
rpc_max_response_size,
|
||||
rpc_max_subscriptions_per_connection,
|
||||
rpc_max_connections,
|
||||
rpc_max_tracing_requests,
|
||||
rpc_max_blocking_io_requests,
|
||||
rpc_max_trace_filter_blocks,
|
||||
rpc_max_blocks_per_filter,
|
||||
rpc_max_logs_per_response,
|
||||
rpc_gas_cap,
|
||||
rpc_evm_memory_limit,
|
||||
rpc_tx_fee_cap,
|
||||
rpc_max_simulate_blocks,
|
||||
rpc_eth_proof_window,
|
||||
rpc_proof_permits,
|
||||
rpc_pending_block,
|
||||
rpc_forwarder,
|
||||
builder_disallow,
|
||||
rpc_state_cache,
|
||||
gas_price_oracle,
|
||||
rpc_send_raw_transaction_sync_timeout,
|
||||
} = DefaultRpcServerArgs::get_global().clone();
|
||||
Self {
|
||||
http: false,
|
||||
http_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
http_port: constants::DEFAULT_HTTP_RPC_PORT,
|
||||
http_disable_compression: false,
|
||||
http_api: None,
|
||||
http_corsdomain: None,
|
||||
ws: false,
|
||||
ws_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
ws_port: constants::DEFAULT_WS_RPC_PORT,
|
||||
ws_allowed_origins: None,
|
||||
ws_api: None,
|
||||
ipcdisable: false,
|
||||
ipcpath: constants::DEFAULT_IPC_ENDPOINT.to_string(),
|
||||
ipc_socket_permissions: None,
|
||||
auth_addr: Ipv4Addr::LOCALHOST.into(),
|
||||
auth_port: constants::DEFAULT_AUTH_PORT,
|
||||
auth_jwtsecret: None,
|
||||
auth_ipc: false,
|
||||
auth_ipc_path: constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string(),
|
||||
disable_auth_server: false,
|
||||
rpc_jwtsecret: None,
|
||||
rpc_max_request_size: RPC_DEFAULT_MAX_REQUEST_SIZE_MB.into(),
|
||||
rpc_max_response_size: RPC_DEFAULT_MAX_RESPONSE_SIZE_MB.into(),
|
||||
rpc_max_subscriptions_per_connection: RPC_DEFAULT_MAX_SUBS_PER_CONN.into(),
|
||||
rpc_max_connections: RPC_DEFAULT_MAX_CONNECTIONS.into(),
|
||||
rpc_max_tracing_requests: constants::default_max_tracing_requests(),
|
||||
rpc_max_trace_filter_blocks: constants::DEFAULT_MAX_TRACE_FILTER_BLOCKS,
|
||||
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: constants::gas_oracle::RPC_DEFAULT_GAS_CAP,
|
||||
rpc_evm_memory_limit: (1 << 32) - 1,
|
||||
rpc_tx_fee_cap: constants::DEFAULT_TX_FEE_CAP_WEI,
|
||||
rpc_max_simulate_blocks: constants::DEFAULT_MAX_SIMULATE_BLOCKS,
|
||||
rpc_eth_proof_window: constants::DEFAULT_ETH_PROOF_WINDOW,
|
||||
rpc_pending_block: PendingBlockKind::Full,
|
||||
gas_price_oracle: GasPriceOracleArgs::default(),
|
||||
rpc_state_cache: RpcStateCacheArgs::default(),
|
||||
rpc_proof_permits: constants::DEFAULT_PROOF_PERMITS,
|
||||
rpc_forwarder: None,
|
||||
builder_disallow: Default::default(),
|
||||
rpc_send_raw_transaction_sync_timeout:
|
||||
constants::RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
|
||||
http,
|
||||
http_addr,
|
||||
http_port,
|
||||
http_disable_compression,
|
||||
http_api,
|
||||
http_corsdomain,
|
||||
ws,
|
||||
ws_addr,
|
||||
ws_port,
|
||||
ws_allowed_origins,
|
||||
ws_api,
|
||||
ipcdisable,
|
||||
ipcpath,
|
||||
ipc_socket_permissions,
|
||||
auth_addr,
|
||||
auth_port,
|
||||
auth_jwtsecret,
|
||||
auth_ipc,
|
||||
auth_ipc_path,
|
||||
disable_auth_server,
|
||||
rpc_jwtsecret,
|
||||
rpc_max_request_size,
|
||||
rpc_max_response_size,
|
||||
rpc_max_subscriptions_per_connection,
|
||||
rpc_max_connections,
|
||||
rpc_max_tracing_requests,
|
||||
rpc_max_blocking_io_requests,
|
||||
rpc_max_trace_filter_blocks,
|
||||
rpc_max_blocks_per_filter,
|
||||
rpc_max_logs_per_response,
|
||||
rpc_gas_cap,
|
||||
rpc_evm_memory_limit,
|
||||
rpc_tx_fee_cap,
|
||||
rpc_max_simulate_blocks,
|
||||
rpc_eth_proof_window,
|
||||
rpc_proof_permits,
|
||||
rpc_pending_block,
|
||||
rpc_forwarder,
|
||||
builder_disallow,
|
||||
rpc_state_cache,
|
||||
gas_price_oracle,
|
||||
rpc_send_raw_transaction_sync_timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -542,4 +964,159 @@ mod tests {
|
||||
let expected = 1_000_000_000_000_000_000u128;
|
||||
assert_eq!(args.rpc_tx_fee_cap, expected); // 1 ETH default cap
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rpc_server_args() {
|
||||
let args = RpcServerArgs {
|
||||
http: true,
|
||||
http_addr: "127.0.0.1".parse().unwrap(),
|
||||
http_port: 8545,
|
||||
http_disable_compression: false,
|
||||
http_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
|
||||
http_corsdomain: Some("*".to_string()),
|
||||
ws: true,
|
||||
ws_addr: "127.0.0.1".parse().unwrap(),
|
||||
ws_port: 8546,
|
||||
ws_allowed_origins: Some("*".to_string()),
|
||||
ws_api: Some(RpcModuleSelection::try_from_selection(["eth", "admin"]).unwrap()),
|
||||
ipcdisable: false,
|
||||
ipcpath: "reth.ipc".to_string(),
|
||||
ipc_socket_permissions: Some("0o666".to_string()),
|
||||
auth_addr: "127.0.0.1".parse().unwrap(),
|
||||
auth_port: 8551,
|
||||
auth_jwtsecret: Some(std::path::PathBuf::from("/tmp/jwt.hex")),
|
||||
auth_ipc: false,
|
||||
auth_ipc_path: "engine.ipc".to_string(),
|
||||
disable_auth_server: false,
|
||||
rpc_jwtsecret: Some(
|
||||
JwtSecret::from_hex(
|
||||
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
rpc_max_request_size: 15u32.into(),
|
||||
rpc_max_response_size: 160u32.into(),
|
||||
rpc_max_subscriptions_per_connection: 1024u32.into(),
|
||||
rpc_max_connections: 500u32.into(),
|
||||
rpc_max_tracing_requests: 16,
|
||||
rpc_max_blocking_io_requests: 256,
|
||||
rpc_max_trace_filter_blocks: 4000,
|
||||
rpc_max_blocks_per_filter: 1000u64.into(),
|
||||
rpc_max_logs_per_response: 10000u64.into(),
|
||||
rpc_gas_cap: 50_000_000,
|
||||
rpc_evm_memory_limit: 256,
|
||||
rpc_tx_fee_cap: 2_000_000_000_000_000_000u128,
|
||||
rpc_max_simulate_blocks: 256,
|
||||
rpc_eth_proof_window: 100_000,
|
||||
rpc_proof_permits: 16,
|
||||
rpc_pending_block: PendingBlockKind::Full,
|
||||
rpc_forwarder: Some("http://localhost:8545".parse().unwrap()),
|
||||
builder_disallow: None,
|
||||
rpc_state_cache: RpcStateCacheArgs {
|
||||
max_blocks: 5000,
|
||||
max_receipts: 2000,
|
||||
max_headers: 1000,
|
||||
max_concurrent_db_requests: 512,
|
||||
},
|
||||
gas_price_oracle: GasPriceOracleArgs {
|
||||
blocks: 20,
|
||||
ignore_price: 2,
|
||||
max_price: 500_000_000_000,
|
||||
percentile: 60,
|
||||
default_suggested_fee: None,
|
||||
},
|
||||
rpc_send_raw_transaction_sync_timeout: std::time::Duration::from_secs(30),
|
||||
};
|
||||
|
||||
let parsed_args = CommandParser::<RpcServerArgs>::parse_from([
|
||||
"reth",
|
||||
"--http",
|
||||
"--http.addr",
|
||||
"127.0.0.1",
|
||||
"--http.port",
|
||||
"8545",
|
||||
"--http.api",
|
||||
"eth,admin",
|
||||
"--http.corsdomain",
|
||||
"*",
|
||||
"--ws",
|
||||
"--ws.addr",
|
||||
"127.0.0.1",
|
||||
"--ws.port",
|
||||
"8546",
|
||||
"--ws.origins",
|
||||
"*",
|
||||
"--ws.api",
|
||||
"eth,admin",
|
||||
"--ipcpath",
|
||||
"reth.ipc",
|
||||
"--ipc.permissions",
|
||||
"0o666",
|
||||
"--authrpc.addr",
|
||||
"127.0.0.1",
|
||||
"--authrpc.port",
|
||||
"8551",
|
||||
"--authrpc.jwtsecret",
|
||||
"/tmp/jwt.hex",
|
||||
"--auth-ipc.path",
|
||||
"engine.ipc",
|
||||
"--rpc.jwtsecret",
|
||||
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"--rpc.max-request-size",
|
||||
"15",
|
||||
"--rpc.max-response-size",
|
||||
"160",
|
||||
"--rpc.max-subscriptions-per-connection",
|
||||
"1024",
|
||||
"--rpc.max-connections",
|
||||
"500",
|
||||
"--rpc.max-tracing-requests",
|
||||
"16",
|
||||
"--rpc.max-blocking-io-requests",
|
||||
"256",
|
||||
"--rpc.max-trace-filter-blocks",
|
||||
"4000",
|
||||
"--rpc.max-blocks-per-filter",
|
||||
"1000",
|
||||
"--rpc.max-logs-per-response",
|
||||
"10000",
|
||||
"--rpc.gascap",
|
||||
"50000000",
|
||||
"--rpc.evm-memory-limit",
|
||||
"256",
|
||||
"--rpc.txfeecap",
|
||||
"2.0",
|
||||
"--rpc.max-simulate-blocks",
|
||||
"256",
|
||||
"--rpc.eth-proof-window",
|
||||
"100000",
|
||||
"--rpc.proof-permits",
|
||||
"16",
|
||||
"--rpc.pending-block",
|
||||
"full",
|
||||
"--rpc.forwarder",
|
||||
"http://localhost:8545",
|
||||
"--rpc-cache.max-blocks",
|
||||
"5000",
|
||||
"--rpc-cache.max-receipts",
|
||||
"2000",
|
||||
"--rpc-cache.max-headers",
|
||||
"1000",
|
||||
"--rpc-cache.max-concurrent-db-requests",
|
||||
"512",
|
||||
"--gpo.blocks",
|
||||
"20",
|
||||
"--gpo.ignoreprice",
|
||||
"2",
|
||||
"--gpo.maxprice",
|
||||
"500000000000",
|
||||
"--gpo.percentile",
|
||||
"60",
|
||||
"--rpc.send-raw-transaction-sync-timeout",
|
||||
"30s",
|
||||
])
|
||||
.args;
|
||||
|
||||
assert_eq!(parsed_args, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +272,11 @@ where
|
||||
fn tracing_task_guard(&self) -> &BlockingTaskGuard {
|
||||
self.inner.eth_api.blocking_task_guard()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn blocking_io_task_guard(&self) -> &Arc<tokio::sync::Semaphore> {
|
||||
self.inner.eth_api.blocking_io_request_semaphore()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, Rpc> LoadFee for OpEthApi<N, Rpc>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use crate::{MessageValidationKind, PayloadAttributes};
|
||||
use alloc::vec::Vec;
|
||||
use alloy_eips::{eip1898::BlockWithParent, eip4895::Withdrawal, eip7685::Requests, BlockNumHash};
|
||||
use alloy_primitives::B256;
|
||||
use alloy_primitives::{Bytes, B256};
|
||||
use alloy_rpc_types_engine::ExecutionData;
|
||||
use core::fmt::Debug;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
@@ -40,6 +40,11 @@ pub trait ExecutionPayload:
|
||||
/// Returns `None` for pre-Shanghai blocks.
|
||||
fn withdrawals(&self) -> Option<&Vec<Withdrawal>>;
|
||||
|
||||
/// Returns the access list included in this payload.
|
||||
///
|
||||
/// Returns `None` for pre-Amsterdam blocks.
|
||||
fn block_access_list(&self) -> Option<&Bytes>;
|
||||
|
||||
/// Returns the beacon block root associated with this payload.
|
||||
///
|
||||
/// Returns `None` for pre-merge payloads.
|
||||
@@ -69,6 +74,10 @@ impl ExecutionPayload for ExecutionData {
|
||||
self.payload.withdrawals()
|
||||
}
|
||||
|
||||
fn block_access_list(&self) -> Option<&Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
self.sidecar.parent_beacon_block_root()
|
||||
}
|
||||
@@ -172,6 +181,10 @@ impl ExecutionPayload for op_alloy_rpc_types_engine::OpExecutionData {
|
||||
self.payload.as_v2().map(|p| &p.withdrawals)
|
||||
}
|
||||
|
||||
fn block_access_list(&self) -> Option<&Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn parent_beacon_block_root(&self) -> Option<B256> {
|
||||
self.sidecar.parent_beacon_block_root()
|
||||
}
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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,
|
||||
|
||||
45
crates/rpc/rpc-api/src/testing.rs
Normal file
45
crates/rpc/rpc-api/src/testing.rs
Normal file
@@ -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<Bytes>,
|
||||
/// Optional extra data for the block header.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub extra_data: Option<Bytes>,
|
||||
}
|
||||
|
||||
/// 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 <https://github.com/marcindsobczak/execution-apis/blob/main/src/testing/testing_buildBlockV1.md>
|
||||
#[method(name = "buildBlockV1")]
|
||||
async fn build_block_v1(
|
||||
&self,
|
||||
request: TestingBuildBlockRequestV1,
|
||||
) -> jsonrpsee::core::RpcResult<ExecutionPayloadEnvelopeV5>;
|
||||
}
|
||||
@@ -94,6 +94,7 @@ impl RethRpcServerConfig for RpcServerArgs {
|
||||
fn eth_config(&self) -> EthConfig {
|
||||
EthConfig::default()
|
||||
.max_tracing_requests(self.rpc_max_tracing_requests)
|
||||
.max_blocking_io_requests(self.rpc_max_blocking_io_requests)
|
||||
.max_trace_filter_blocks(self.rpc_max_trace_filter_blocks)
|
||||
.max_blocks_per_filter(self.rpc_max_blocks_per_filter.unwrap_or_max())
|
||||
.max_logs_per_response(self.rpc_max_logs_per_response.unwrap_or_max() as usize)
|
||||
|
||||
@@ -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<Provider, Pool, Network, EthApi, BlockExecutor, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, EthApi, BlockExecutor, Consensus>
|
||||
impl<Provider, Pool, Network, EthApi, Evm, Consensus>
|
||||
RpcRegistryInner<Provider, Pool, Network, EthApi, Evm, Consensus>
|
||||
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<Methods> {
|
||||
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()
|
||||
})
|
||||
|
||||
@@ -7,18 +7,29 @@ use reth_tasks::{
|
||||
pool::{BlockingTaskGuard, BlockingTaskPool},
|
||||
TaskSpawner,
|
||||
};
|
||||
use tokio::sync::{oneshot, AcquireError, OwnedSemaphorePermit};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{oneshot, AcquireError, OwnedSemaphorePermit, Semaphore};
|
||||
|
||||
use crate::EthApiTypes;
|
||||
|
||||
/// Executes code on a blocking thread.
|
||||
/// Helpers for spawning blocking operations.
|
||||
///
|
||||
/// Operations can be blocking because they require lots of CPU work and/or IO.
|
||||
///
|
||||
/// This differentiates between workloads that are primarily CPU bound and heavier in general (such
|
||||
/// as tracing tasks) and tasks that have a more balanced profile (io and cpu), such as `eth_call`
|
||||
/// and alike.
|
||||
///
|
||||
/// This provides access to semaphores that permit how many of those are permitted concurrently.
|
||||
/// It's expected that tracing related tasks are configured with a lower threshold, because not only
|
||||
/// are they CPU heavy but they can also accumulate more memory for the traces.
|
||||
pub trait SpawnBlocking: EthApiTypes + 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.
|
||||
/// Returns a handle for spawning __CPU heavy__ blocking tasks, such as tracing requests.
|
||||
///
|
||||
/// Thread pool access in default trait method implementations.
|
||||
fn tracing_task_pool(&self) -> &BlockingTaskPool;
|
||||
@@ -26,21 +37,121 @@ pub trait SpawnBlocking: EthApiTypes + Clone + Send + Sync + 'static {
|
||||
/// Returns handle to semaphore for pool of CPU heavy blocking tasks.
|
||||
fn tracing_task_guard(&self) -> &BlockingTaskGuard;
|
||||
|
||||
/// Returns handle to semaphore for blocking IO tasks.
|
||||
///
|
||||
/// This semaphore is used to limit concurrent blocking IO operations like `eth_call`,
|
||||
/// `eth_estimateGas`, and similar methods that require EVM execution.
|
||||
fn blocking_io_task_guard(&self) -> &Arc<Semaphore>;
|
||||
|
||||
/// Acquires a permit from the tracing task semaphore.
|
||||
///
|
||||
/// This should be used for __CPU heavy__ operations like `debug_traceTransaction`,
|
||||
/// `debug_traceCall`, and similar tracing methods. These tasks are typically:
|
||||
/// - Primarily CPU bound with intensive computation
|
||||
/// - Can accumulate significant memory for trace results
|
||||
/// - Expected to have lower concurrency limits than general blocking IO tasks
|
||||
///
|
||||
/// For blocking IO tasks like `eth_call` or `eth_estimateGas`, use
|
||||
/// [`acquire_owned_blocking_io`](Self::acquire_owned_blocking_io) instead.
|
||||
///
|
||||
/// See also [`Semaphore::acquire_owned`](`tokio::sync::Semaphore::acquire_owned`).
|
||||
fn acquire_owned(
|
||||
fn acquire_owned_tracing(
|
||||
&self,
|
||||
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send {
|
||||
self.tracing_task_guard().clone().acquire_owned()
|
||||
}
|
||||
|
||||
/// Acquires multiple permits from the tracing task semaphore.
|
||||
///
|
||||
/// This should be used for particularly heavy tracing operations that require more resources
|
||||
/// than a standard trace. The permit count should reflect the expected resource consumption
|
||||
/// relative to a standard tracing operation.
|
||||
///
|
||||
/// Like [`acquire_owned_tracing`](Self::acquire_owned_tracing), this is specifically for
|
||||
/// CPU-intensive tracing tasks, not general blocking IO operations.
|
||||
///
|
||||
/// See also [`Semaphore::acquire_many_owned`](`tokio::sync::Semaphore::acquire_many_owned`).
|
||||
fn acquire_many_owned(
|
||||
fn acquire_many_owned_tracing(
|
||||
&self,
|
||||
n: u32,
|
||||
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send {
|
||||
self.tracing_task_guard().clone().acquire_many_owned(n)
|
||||
}
|
||||
|
||||
/// Acquires a permit from the blocking IO request semaphore.
|
||||
///
|
||||
/// This should be used for operations like `eth_call`, `eth_estimateGas`, and similar methods
|
||||
/// that require EVM execution and are spawned as blocking tasks.
|
||||
///
|
||||
/// See also [`Semaphore::acquire_owned`](`tokio::sync::Semaphore::acquire_owned`).
|
||||
fn acquire_owned_blocking_io(
|
||||
&self,
|
||||
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send {
|
||||
self.blocking_io_task_guard().clone().acquire_owned()
|
||||
}
|
||||
|
||||
/// Acquires multiple permits from the blocking IO request semaphore.
|
||||
///
|
||||
/// This should be used for operations that may require more resources than a single permit
|
||||
/// allows.
|
||||
///
|
||||
/// See also [`Semaphore::acquire_many_owned`](`tokio::sync::Semaphore::acquire_many_owned`).
|
||||
fn acquire_many_owned_blocking_io(
|
||||
&self,
|
||||
n: u32,
|
||||
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send {
|
||||
self.blocking_io_task_guard().clone().acquire_many_owned(n)
|
||||
}
|
||||
|
||||
/// Acquires permits from the blocking IO request semaphore based on a calculated weight.
|
||||
///
|
||||
/// The weight determines the maximum number of concurrent requests of this type that can run.
|
||||
/// For example, if the semaphore has 256 total permits and `weight=10`, then at most 10
|
||||
/// concurrent requests of this type are allowed.
|
||||
///
|
||||
/// The permits acquired per request is calculated as `total_permits / weight`, with an
|
||||
/// adjustment: if this result is even, we add 1 to ensure that `weight - 1` permits are
|
||||
/// always available for other tasks, preventing complete semaphore exhaustion.
|
||||
///
|
||||
/// This should be used to explicitly limit concurrent requests based on their expected
|
||||
/// resource consumption:
|
||||
///
|
||||
/// - **Block range queries**: Higher weight for larger ranges (fewer concurrent requests)
|
||||
/// - **Complex calls**: Higher weight for expensive operations
|
||||
/// - **Batch operations**: Higher weight for larger batches
|
||||
/// - **Historical queries**: Higher weight for deeper history lookups
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// // For a heavy request, use higher weight to limit concurrency
|
||||
/// let weight = 20; // Allow at most 20 concurrent requests of this type
|
||||
/// let _permit = self.acquire_weighted_blocking_io(weight).await?;
|
||||
/// ```
|
||||
///
|
||||
/// This helps prevent resource exhaustion from concurrent expensive operations while allowing
|
||||
/// many cheap operations to run in parallel.
|
||||
///
|
||||
/// See also [`Semaphore::acquire_many_owned`](`tokio::sync::Semaphore::acquire_many_owned`).
|
||||
fn acquire_weighted_blocking_io(
|
||||
&self,
|
||||
weight: u32,
|
||||
) -> impl Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send {
|
||||
let guard = self.blocking_io_task_guard();
|
||||
let total_permits = guard.available_permits().max(1) as u32;
|
||||
let weight = weight.max(1);
|
||||
let mut permits_to_acquire = (total_permits / weight).max(1);
|
||||
|
||||
// If total_permits divides evenly by weight, add 1 to ensure that when `weight`
|
||||
// concurrent requests are running, at least `weight - 1` permits remain available
|
||||
// for other tasks
|
||||
if total_permits.is_multiple_of(weight) {
|
||||
permits_to_acquire += 1;
|
||||
}
|
||||
|
||||
guard.clone().acquire_many_owned(permits_to_acquire)
|
||||
}
|
||||
|
||||
/// Executes the future on a new blocking task.
|
||||
///
|
||||
/// Note: This is expected for futures that are dominated by blocking IO operations, for tracing
|
||||
|
||||
@@ -212,6 +212,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
||||
overrides: EvmOverrides,
|
||||
) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
|
||||
async move {
|
||||
let _permit = self.acquire_owned_blocking_io().await;
|
||||
let res =
|
||||
self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
|
||||
|
||||
|
||||
@@ -420,6 +420,7 @@ impl<H: BlockHeader> BuildPendingEnv<H> 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: parent.extra_data().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ use reth_rpc_eth_types::{
|
||||
error::FromEvmError, EthApiError, PendingBlockEnv, RpcInvalidTransactionError,
|
||||
};
|
||||
use reth_storage_api::{
|
||||
BlockIdReader, BlockNumReader, StateProvider, StateProviderBox, StateProviderFactory,
|
||||
BlockIdReader, BlockNumReader, BlockReaderIdExt, StateProvider, StateProviderBox,
|
||||
StateProviderFactory,
|
||||
};
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
|
||||
@@ -96,7 +97,7 @@ pub trait EthState: LoadState + SpawnBlocking {
|
||||
{
|
||||
Ok(async move {
|
||||
let _permit = self
|
||||
.acquire_owned()
|
||||
.acquire_owned_tracing()
|
||||
.await
|
||||
.map_err(RethError::other)
|
||||
.map_err(EthApiError::Internal)?;
|
||||
@@ -273,21 +274,20 @@ pub trait LoadState:
|
||||
let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
|
||||
Ok((evm_env, origin.state_block_id()))
|
||||
} else {
|
||||
// Use cached values if there is no pending block
|
||||
let block_hash = RpcNodeCore::provider(self)
|
||||
.block_hash_for_id(at)
|
||||
// we can assume that the blockid will be predominantly `Latest` (e.g. for
|
||||
// `eth_call`) and if requested by number or hash we can quickly fetch just the
|
||||
// header
|
||||
let header = RpcNodeCore::provider(self)
|
||||
.sealed_header_by_id(at)
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.ok_or(EthApiError::HeaderNotFound(at))?;
|
||||
|
||||
let header =
|
||||
self.cache().get_header(block_hash).await.map_err(Self::Error::from_eth_err)?;
|
||||
.ok_or_else(|| EthApiError::HeaderNotFound(at))?;
|
||||
let evm_env = self
|
||||
.evm_config()
|
||||
.evm_env(&header)
|
||||
.map_err(RethError::other)
|
||||
.map_err(Self::Error::from_eth_err)?;
|
||||
|
||||
Ok((evm_env, block_hash.into()))
|
||||
Ok((evm_env, header.hash().into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ use crate::{
|
||||
};
|
||||
use reqwest::Url;
|
||||
use reth_rpc_server_types::constants::{
|
||||
default_max_tracing_requests, DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKS_PER_FILTER,
|
||||
DEFAULT_MAX_LOGS_PER_RESPONSE, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_MAX_TRACE_FILTER_BLOCKS,
|
||||
DEFAULT_PROOF_PERMITS, RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
|
||||
default_max_tracing_requests, DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKING_IO_REQUEST,
|
||||
DEFAULT_MAX_BLOCKS_PER_FILTER, DEFAULT_MAX_LOGS_PER_RESPONSE, DEFAULT_MAX_SIMULATE_BLOCKS,
|
||||
DEFAULT_MAX_TRACE_FILTER_BLOCKS, DEFAULT_PROOF_PERMITS,
|
||||
RPC_DEFAULT_SEND_RAW_TX_SYNC_TIMEOUT_SECS,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -68,6 +69,15 @@ pub struct EthConfig {
|
||||
pub eth_proof_window: u64,
|
||||
/// The maximum number of tracing calls that can be executed in concurrently.
|
||||
pub max_tracing_requests: usize,
|
||||
/// The maximum number of blocking IO calls that can be executed in concurrently.
|
||||
///
|
||||
/// Requests such as `eth_call`, `eth_estimateGas` and alike require evm execution, which is
|
||||
/// considered blocking since it's usually more heavy on the IO side but also CPU constrained.
|
||||
/// It is expected that these are spawned as short lived blocking tokio tasks. This config
|
||||
/// determines how many can be spawned concurrently, to avoid a build up in the tokio's
|
||||
/// blocking pool queue since there's only a limited number of threads available. This setting
|
||||
/// restricts how many tasks are spawned concurrently.
|
||||
pub max_blocking_io_requests: usize,
|
||||
/// Maximum number of blocks for `trace_filter` requests.
|
||||
pub max_trace_filter_blocks: u64,
|
||||
/// Maximum number of blocks that could be scanned per filter request in `eth_getLogs` calls.
|
||||
@@ -116,6 +126,7 @@ impl Default for EthConfig {
|
||||
gas_oracle: GasPriceOracleConfig::default(),
|
||||
eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
|
||||
max_tracing_requests: default_max_tracing_requests(),
|
||||
max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
|
||||
max_trace_filter_blocks: DEFAULT_MAX_TRACE_FILTER_BLOCKS,
|
||||
max_blocks_per_filter: DEFAULT_MAX_BLOCKS_PER_FILTER,
|
||||
max_logs_per_response: DEFAULT_MAX_LOGS_PER_RESPONSE,
|
||||
@@ -152,6 +163,12 @@ impl EthConfig {
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the maximum number of blocking IO requests
|
||||
pub const fn max_blocking_io_requests(mut self, max_requests: usize) -> Self {
|
||||
self.max_blocking_io_requests = max_requests;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the maximum block length to scan per `eth_getLogs` request
|
||||
pub const fn max_blocks_per_filter(mut self, max_blocks: u64) -> Self {
|
||||
self.max_blocks_per_filter = max_blocks;
|
||||
|
||||
@@ -18,6 +18,20 @@ pub const DEFAULT_MAX_LOGS_PER_RESPONSE: usize = 20_000;
|
||||
/// The default maximum number of blocks for `trace_filter` requests.
|
||||
pub const DEFAULT_MAX_TRACE_FILTER_BLOCKS: u64 = 100;
|
||||
|
||||
/// Setting for how many concurrent (heavier) _blocking_ IO requests are allowed.
|
||||
///
|
||||
/// What is considered a blocking IO request can depend on the RPC method. In general anything that
|
||||
/// requires IO is considered blocking and should be spawned as blocking. This setting is however,
|
||||
/// primarily intended for heavier blocking requests that require evm execution for example,
|
||||
/// `eth_call` and alike. This is intended to be used with a semaphore that must be acquired before
|
||||
/// a new task is spawned to avoid unnecessary pooling if the number of inflight requests exceeds
|
||||
/// the available threads in the pool.
|
||||
///
|
||||
/// tokio's blocking pool, has a default of 512 and could grow unbounded, since requests like
|
||||
/// `eth_call` also require a lot of cpu which will occupy the thread, we can set this to a lower
|
||||
/// value.
|
||||
pub const DEFAULT_MAX_BLOCKING_IO_REQUEST: usize = 256;
|
||||
|
||||
/// The default maximum number tracing requests we're allowing concurrently.
|
||||
/// Tracing is mostly CPU bound so we're limiting the number of concurrent requests to something
|
||||
/// lower that the number of cores, in order to minimize the impact on the rest of the system.
|
||||
|
||||
@@ -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<str> 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()),
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ use reth_rpc_eth_types::{
|
||||
FeeHistoryCacheConfig, ForwardConfig, GasCap, GasPriceOracle, GasPriceOracleConfig,
|
||||
};
|
||||
use reth_rpc_server_types::constants::{
|
||||
DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_PROOF_PERMITS,
|
||||
DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKING_IO_REQUEST, DEFAULT_MAX_SIMULATE_BLOCKS,
|
||||
DEFAULT_PROOF_PERMITS,
|
||||
};
|
||||
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
@@ -41,6 +42,7 @@ pub struct EthApiBuilder<N: RpcNodeCore, Rpc, NextEnv = ()> {
|
||||
task_spawner: Box<dyn TaskSpawner + 'static>,
|
||||
next_env: NextEnv,
|
||||
max_batch_size: usize,
|
||||
max_blocking_io_requests: usize,
|
||||
pending_block_kind: PendingBlockKind,
|
||||
raw_tx_forwarder: ForwardConfig,
|
||||
send_raw_transaction_sync_timeout: Duration,
|
||||
@@ -92,6 +94,7 @@ impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
|
||||
task_spawner,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -113,6 +116,7 @@ impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
|
||||
task_spawner,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -145,6 +149,7 @@ where
|
||||
eth_state_cache_config: Default::default(),
|
||||
next_env: Default::default(),
|
||||
max_batch_size: 1,
|
||||
max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
|
||||
pending_block_kind: PendingBlockKind::Full,
|
||||
raw_tx_forwarder: ForwardConfig::default(),
|
||||
send_raw_transaction_sync_timeout: Duration::from_secs(30),
|
||||
@@ -184,6 +189,7 @@ where
|
||||
gas_oracle_config,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -205,6 +211,7 @@ where
|
||||
gas_oracle_config,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -233,6 +240,7 @@ where
|
||||
gas_oracle_config,
|
||||
next_env: _,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -254,6 +262,7 @@ where
|
||||
gas_oracle_config,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -335,6 +344,12 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum number of concurrent blocking IO requests.
|
||||
pub const fn max_blocking_io_requests(mut self, max_blocking_io_requests: usize) -> Self {
|
||||
self.max_blocking_io_requests = max_blocking_io_requests;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the pending block kind
|
||||
pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
|
||||
self.pending_block_kind = pending_block_kind;
|
||||
@@ -482,6 +497,7 @@ where
|
||||
task_spawner,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder,
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -523,6 +539,7 @@ where
|
||||
rpc_converter,
|
||||
next_env,
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder.forwarder_client(),
|
||||
send_raw_transaction_sync_timeout,
|
||||
|
||||
@@ -33,7 +33,7 @@ use reth_transaction_pool::{
|
||||
blobstore::BlobSidecarConverter, noop::NoopTransactionPool, AddedTransactionOutcome,
|
||||
BatchTxProcessor, BatchTxRequest, TransactionPool,
|
||||
};
|
||||
use tokio::sync::{broadcast, mpsc, Mutex};
|
||||
use tokio::sync::{broadcast, mpsc, Mutex, Semaphore};
|
||||
|
||||
const DEFAULT_BROADCAST_CAPACITY: usize = 2000;
|
||||
|
||||
@@ -152,6 +152,7 @@ where
|
||||
proof_permits: usize,
|
||||
rpc_converter: Rpc,
|
||||
max_batch_size: usize,
|
||||
max_blocking_io_requests: usize,
|
||||
pending_block_kind: PendingBlockKind,
|
||||
raw_tx_forwarder: ForwardConfig,
|
||||
send_raw_transaction_sync_timeout: Duration,
|
||||
@@ -171,6 +172,7 @@ where
|
||||
rpc_converter,
|
||||
(),
|
||||
max_batch_size,
|
||||
max_blocking_io_requests,
|
||||
pending_block_kind,
|
||||
raw_tx_forwarder.forwarder_client(),
|
||||
send_raw_transaction_sync_timeout,
|
||||
@@ -263,6 +265,11 @@ where
|
||||
fn tracing_task_guard(&self) -> &BlockingTaskGuard {
|
||||
self.inner.blocking_task_guard()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn blocking_io_task_guard(&self) -> &std::sync::Arc<tokio::sync::Semaphore> {
|
||||
self.inner.blocking_io_request_semaphore()
|
||||
}
|
||||
}
|
||||
|
||||
/// Container type `EthApi`
|
||||
@@ -296,6 +303,9 @@ pub struct EthApiInner<N: RpcNodeCore, Rpc: RpcConvert> {
|
||||
/// Guard for getproof calls
|
||||
blocking_task_guard: BlockingTaskGuard,
|
||||
|
||||
/// Semaphore to limit concurrent blocking IO requests (`eth_call`, `eth_estimateGas`, etc.)
|
||||
blocking_io_request_semaphore: Arc<Semaphore>,
|
||||
|
||||
/// Transaction broadcast channel
|
||||
raw_tx_sender: broadcast::Sender<Bytes>,
|
||||
|
||||
@@ -346,6 +356,7 @@ where
|
||||
converter: Rpc,
|
||||
next_env: impl PendingEnvBuilder<N::Evm>,
|
||||
max_batch_size: usize,
|
||||
max_blocking_io_requests: usize,
|
||||
pending_block_kind: PendingBlockKind,
|
||||
raw_tx_forwarder: Option<RpcClient>,
|
||||
send_raw_transaction_sync_timeout: Duration,
|
||||
@@ -384,6 +395,7 @@ where
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
blocking_task_guard: BlockingTaskGuard::new(proof_permits),
|
||||
blocking_io_request_semaphore: Arc::new(Semaphore::new(max_blocking_io_requests)),
|
||||
raw_tx_sender,
|
||||
raw_tx_forwarder,
|
||||
converter,
|
||||
@@ -440,6 +452,8 @@ where
|
||||
}
|
||||
|
||||
/// Returns a handle to the blocking thread pool.
|
||||
///
|
||||
/// This is intended for tasks that are CPU bound.
|
||||
#[inline]
|
||||
pub const fn blocking_task_pool(&self) -> &BlockingTaskPool {
|
||||
&self.blocking_task_pool
|
||||
@@ -525,7 +539,7 @@ where
|
||||
|
||||
/// Returns the transaction batch sender
|
||||
#[inline]
|
||||
const fn tx_batch_sender(
|
||||
pub const fn tx_batch_sender(
|
||||
&self,
|
||||
) -> &mpsc::UnboundedSender<BatchTxRequest<<N::Pool as TransactionPool>::Transaction>> {
|
||||
&self.tx_batch_sender
|
||||
@@ -576,6 +590,12 @@ where
|
||||
pub const fn evm_memory_limit(&self) -> u64 {
|
||||
self.evm_memory_limit
|
||||
}
|
||||
|
||||
/// Returns a reference to the blocking IO request semaphore.
|
||||
#[inline]
|
||||
pub const fn blocking_io_request_semaphore(&self) -> &Arc<Semaphore> {
|
||||
&self.blocking_io_request_semaphore
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -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};
|
||||
|
||||
127
crates/rpc/rpc/src/testing.rs
Normal file
127
crates/rpc/rpc/src/testing.rs
Normal file
@@ -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, Evm> {
|
||||
eth_api: Eth,
|
||||
evm_config: Evm,
|
||||
}
|
||||
|
||||
impl<Eth, Evm> TestingApi<Eth, Evm> {
|
||||
/// Create a new testing API handler.
|
||||
pub const fn new(eth_api: Eth, evm_config: Evm) -> Self {
|
||||
Self { eth_api, evm_config }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Eth, Evm> TestingApi<Eth, Evm>
|
||||
where
|
||||
Eth: Call<Provider: BlockReader<Header = Header>>,
|
||||
Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes, Primitives = EthPrimitives>
|
||||
+ 'static,
|
||||
{
|
||||
async fn build_block_v1(
|
||||
&self,
|
||||
request: TestingBuildBlockRequestV1,
|
||||
) -> Result<ExecutionPayloadEnvelopeV5, Eth::Error> {
|
||||
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.unwrap_or_default(),
|
||||
};
|
||||
|
||||
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<TxTy<Evm::Primitives>> = 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<Eth, Evm> TestingApiServer for TestingApi<Eth, Evm>
|
||||
where
|
||||
Eth: Call<Provider: BlockReader<Header = Header>>,
|
||||
Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes, Primitives = EthPrimitives>
|
||||
+ '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<ExecutionPayloadEnvelopeV5> {
|
||||
self.build_block_v1(request).await.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@ pub struct StorageSettings {
|
||||
/// Whether `TransactionHashNumbers` is stored in `RocksDB`.
|
||||
#[serde(default)]
|
||||
pub transaction_hash_numbers_in_rocksdb: bool,
|
||||
/// Whether `AccountsHistory` is stored in `RocksDB`.
|
||||
#[serde(default)]
|
||||
pub account_history_in_rocksdb: bool,
|
||||
}
|
||||
|
||||
impl StorageSettings {
|
||||
@@ -39,6 +42,7 @@ impl StorageSettings {
|
||||
transaction_senders_in_static_files: false,
|
||||
storages_history_in_rocksdb: false,
|
||||
transaction_hash_numbers_in_rocksdb: false,
|
||||
account_history_in_rocksdb: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,4 +69,10 @@ impl StorageSettings {
|
||||
self.transaction_hash_numbers_in_rocksdb = value;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the `account_history_in_rocksdb` flag to the provided value.
|
||||
pub const fn with_account_history_in_rocksdb(mut self, value: bool) -> Self {
|
||||
self.account_history_in_rocksdb = value;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Abstractions
|
||||
|
||||
- We created a [Database trait abstraction](https://github.com/paradigmxyz/reth/blob/main/crates/cli/commands/src/db/mod.rs) using Rust Stable GATs which frees us from being bound to a single database implementation. We currently use MDBX, but are exploring [redb](https://github.com/cberner/redb) as an alternative.
|
||||
- We then iterated on [`Transaction`](https://github.com/paradigmxyz/reth/blob/main/crates/storage/errors/src/db.rs) as a non-leaky abstraction with helpers for strictly-typed and unit-tested higher-level database abstractions.
|
||||
- We created a [Database trait abstraction](https://github.com/paradigmxyz/reth/blob/main/crates/storage/db-api/src/database.rs) using Rust Stable GATs which frees us from being bound to a single database implementation. We currently use MDBX, but are exploring [redb](https://github.com/cberner/redb) as an alternative.
|
||||
- We then iterated on [`Transaction`](https://github.com/paradigmxyz/reth/blob/main/crates/storage/db-api/src/transaction.rs) as a non-leaky abstraction with helpers for strictly-typed and unit-tested higher-level database abstractions.
|
||||
|
||||
## Codecs
|
||||
|
||||
|
||||
@@ -40,10 +40,19 @@ All binaries are stored in [`bin`](../../bin).
|
||||
These crates are related to the database.
|
||||
|
||||
- [`storage/codecs`](../../crates/storage/codecs): Different storage codecs.
|
||||
- [`storage/codecs/derive`](../../crates/storage/codecs/derive): Derive macros for storage codecs.
|
||||
- [`storage/libmdbx-rs`](../../crates/storage/libmdbx-rs): Rust bindings for [libmdbx](https://github.com/erthink/libmdbx). A fork of an earlier Apache-licensed version of [libmdbx-rs][libmdbx-rs].
|
||||
- [`storage/db`](../../crates/storage/db): Strongly typed Database abstractions (transactions, cursors, tables) over lower level database backends.
|
||||
- Implemented backends: mdbx
|
||||
- [`storage/db-api`](../../crates/storage/db-api): High-level database access traits used across storage crates.
|
||||
- [`storage/db-common`](../../crates/storage/db-common): Shared database helpers and utilities.
|
||||
- [`storage/db-models`](../../crates/storage/db-models): Typed database models for on-disk tables.
|
||||
- [`storage/storage-api`](../../crates/storage/storage-api): Storage-facing APIs used by higher-level components.
|
||||
- [`storage/provider`](../../crates/storage/provider): Traits which provide a higher level api over the database to access the Ethereum state and historical data (transactions, blocks etc.)
|
||||
- [`storage/rpc-provider`](../../crates/storage/rpc-provider): Storage provider implementations tailored for RPC access patterns.
|
||||
- [`storage/errors`](../../crates/storage/errors): Common error types used by storage crates.
|
||||
- [`storage/nippy-jar`](../../crates/storage/nippy-jar): Compressed columnar storage for historical data.
|
||||
- [`storage/zstd-compressors`](../../crates/storage/zstd-compressors): Zstandard-based compressors used by storage components.
|
||||
|
||||
|
||||
### Networking
|
||||
@@ -62,16 +71,21 @@ The networking component mainly lives in [`net/network`](../../crates/net/networ
|
||||
- Contains: Peer banlist.
|
||||
- [`net/network-api`](../../crates/net/network-api): Contains traits that define the networking component as a whole. Other components that interface with the network stack only need to depend on this crate for the relevant types.
|
||||
- [`net/nat`](../../crates/net/nat): A small helper crate that resolves the external IP of the running node using various methods (such as a manually provided IP, using UPnP etc.)
|
||||
- [`net/network-types`](../../crates/net/network-types): Common networking types (peer identifiers, capabilities, messages, etc.).
|
||||
- [`net/p2p`](../../crates/net/p2p): Higher-level P2P networking helpers and utilities.
|
||||
- [`net/peers`](../../crates/net/peers): Peer set management, scoring and reputation support.
|
||||
|
||||
#### Discovery
|
||||
|
||||
- [`net/discv4`](../../crates/net/discv4): An implementation of the [discv4][discv4] protocol
|
||||
- [`net/discv5`](../../crates/net/discv5): An implementation of the discv5 node discovery protocol.
|
||||
- [`net/dns`](../../crates/net/dns): An implementation of node discovery via DNS ([EIP-1459][eip-1459])
|
||||
|
||||
#### Protocol
|
||||
|
||||
- [`net/eth-wire`](../../crates/net/eth-wire): Implements the `eth` wire protocol and the ``RLPx`` networking stack.
|
||||
- [`net/ecies`](../../crates/net/ecies): Implementation of the Elliptic Curve Integrated Encryption Scheme used in the ``RLPx`` handshake.
|
||||
- [`net/eth-wire-types`](../../crates/net/eth-wire-types): Common types used by the `eth` wire protocol and RLPx networking stack.
|
||||
|
||||
#### Downloaders
|
||||
|
||||
@@ -81,7 +95,9 @@ The networking component mainly lives in [`net/network`](../../crates/net/networ
|
||||
|
||||
Different consensus mechanisms.
|
||||
|
||||
- [`consensus/common`](../../crates/consensus/common): Common consensus functions and traits (e.g. fee calculation)
|
||||
- [`consensus/common`](../../crates/consensus/common): Common consensus functions and traits (e.g. fee calculation).
|
||||
- [`consensus/consensus`](../../crates/consensus/consensus): Core consensus engine interfaces and implementations.
|
||||
- [`consensus/debug-client`](../../crates/consensus/debug-client): Utilities for interacting with the consensus engine in debugging and testing scenarios.
|
||||
|
||||
### Execution
|
||||
|
||||
@@ -96,7 +112,9 @@ Crates related to transaction execution.
|
||||
|
||||
These crates implement the main syncing drivers of reth.
|
||||
|
||||
- [`stages`](../../crates/stages): A pipelined sync, including implementation of various stages. This is used during initial sync and is faster than the tree-like structure for longer sync ranges.
|
||||
- [`stages/api`](../../crates/stages/api): Public API for the staged sync pipeline.
|
||||
- [`stages/stages`](../../crates/stages/stages): Implementations of the individual sync stages and the pipeline driver. This is used during initial sync and is faster than the tree-like structure for longer sync ranges.
|
||||
- [`stages/types`](../../crates/stages/types): Shared types used by the staged sync pipeline.
|
||||
|
||||
### RPC
|
||||
|
||||
@@ -146,6 +164,10 @@ Crates related to building and validating payloads (blocks).
|
||||
- [`transaction-pool`](../../crates/transaction-pool): An in-memory pending transactions pool.
|
||||
- [`payload/builder`](../../crates/payload/builder): Abstractions for payload building and a payload builder service that works with multiple kinds of payload resolvers.
|
||||
- [`payload/basic`](../../crates/payload/basic): A basic payload generator.
|
||||
- [`payload/builder-primitives`](../../crates/payload/builder-primitives): Common primitives used by payload builders.
|
||||
- [`payload/primitives`](../../crates/payload/primitives): Shared types used when building and validating payloads.
|
||||
- [`payload/util`](../../crates/payload/util): Utility helpers used by payload building and validation logic.
|
||||
- [`payload/validator`](../../crates/payload/validator): Payload validation helpers and utilities.
|
||||
|
||||
### Primitives
|
||||
|
||||
@@ -169,6 +191,12 @@ Small utility crates.
|
||||
- [`metrics/metrics-derive`](https://github.com/rkrasiuk/metrics-derive): A derive-style API for creating metrics
|
||||
- [`metrics/reth-node-metrics`](../../crates/node/metrics/): The implementation of metrics server, recorder, hooks.
|
||||
- [`tracing`](../../crates/tracing): A small utility crate to install a uniform [`tracing`][tracing] subscriber
|
||||
- [`fs-util`](../../crates/fs-util): Small filesystem utilities shared across the node.
|
||||
- [`tokio-util`](../../crates/tokio-util): Tokio-related utilities used by reth.
|
||||
- [`static-file`](../../crates/static-file): Utilities for bundling and serving static files.
|
||||
- [`tracing-otlp`](../../crates/tracing-otlp): Exporter for sending [`tracing`][tracing] spans to OTLP/OTel backends.
|
||||
- [`errors`](../../crates/errors): Common error types shared across multiple crates.
|
||||
- [`e2e-test-utils`](../../crates/e2e-test-utils): Helpers for end-to-end tests of the node.
|
||||
|
||||
[libmdbx-rs]: https://crates.io/crates/libmdbx
|
||||
[discv4]: https://github.com/ethereum/devp2p/blob/master/discv4.md
|
||||
|
||||
@@ -302,7 +302,7 @@ RPC:
|
||||
--http.api <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>
|
||||
Http Corsdomain to allow request from
|
||||
@@ -326,7 +326,7 @@ RPC:
|
||||
--ws.api <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
|
||||
@@ -404,6 +404,13 @@ RPC:
|
||||
|
||||
[default: <NUM CPU CORES-2>]
|
||||
|
||||
--rpc.max-blocking-io-requests <COUNT>
|
||||
Maximum number of concurrent blocking IO requests.
|
||||
|
||||
Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that require EVM execution. These are spawned as blocking tasks to avoid blocking the async runtime.
|
||||
|
||||
[default: 256]
|
||||
|
||||
--rpc.max-trace-filter-blocks <COUNT>
|
||||
Maximum number of blocks for `trace_filter` requests
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@ RPC:
|
||||
--http.api <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>
|
||||
Http Corsdomain to allow request from
|
||||
@@ -326,7 +326,7 @@ RPC:
|
||||
--ws.api <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
|
||||
@@ -404,6 +404,13 @@ RPC:
|
||||
|
||||
[default: <NUM CPU CORES-2>]
|
||||
|
||||
--rpc.max-blocking-io-requests <COUNT>
|
||||
Maximum number of concurrent blocking IO requests.
|
||||
|
||||
Blocking IO requests include `eth_call`, `eth_estimateGas`, and similar methods that require EVM execution. These are spawned as blocking tasks to avoid blocking the async runtime.
|
||||
|
||||
[default: 256]
|
||||
|
||||
--rpc.max-trace-filter-blocks <COUNT>
|
||||
Maximum number of blocks for `trace_filter` requests
|
||||
|
||||
|
||||
@@ -4,6 +4,28 @@ description: How Execution Extensions (ExExes) work in Reth.
|
||||
|
||||
# How do ExExes work?
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Reth
|
||||
participant ExEx
|
||||
|
||||
Note over Reth,ExEx: Normal Flow
|
||||
Reth->>ExEx: ChainCommit Notification
|
||||
activate ExEx
|
||||
ExEx->>ExEx: Process Block Data
|
||||
ExEx->>Reth: FinishedHeight Event
|
||||
deactivate ExEx
|
||||
|
||||
Note over Reth,ExEx: Reorg Flow
|
||||
Reth->>ExEx: ChainReorg Notification
|
||||
activate ExEx
|
||||
ExEx->>ExEx: Rollback & Re-process
|
||||
ExEx->>Reth: New FinishedHeight Event
|
||||
deactivate ExEx
|
||||
```
|
||||
|
||||
ExExes are just [Futures](https://doc.rust-lang.org/std/future/trait.Future.html) that run indefinitely alongside Reth
|
||||
– as simple as that.
|
||||
|
||||
|
||||
@@ -17,6 +17,27 @@ initiated by Reth.
|
||||
|
||||
Read more about things you can build with Execution Extensions in the [Paradigm blog](https://www.paradigm.xyz/2024/05/reth-exex).
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "Reth Process"
|
||||
Reth[Reth Core]
|
||||
|
||||
Reth -->|Notifications| ExEx1[ExEx 1]
|
||||
Reth -->|Notifications| ExEx2[ExEx 2]
|
||||
Reth -->|Notifications| ExEx3[ExEx N]
|
||||
|
||||
ExEx1 -->|Events| Reth
|
||||
ExEx2 -->|Events| Reth
|
||||
ExEx3 -->|Events| Reth
|
||||
end
|
||||
|
||||
ExEx1 --> External1[External System 1]
|
||||
ExEx2 --> External2[External System 2]
|
||||
ExEx3 --> External3[External System N]
|
||||
```
|
||||
|
||||
## What Execution Extensions are not
|
||||
|
||||
Execution Extensions are not separate processes that connect to the main Reth node process.
|
||||
|
||||
@@ -13,6 +13,13 @@ This section provides essential information about the ports used by the system,
|
||||
- **Purpose:** Peering with other nodes for synchronization of blockchain data. Nodes communicate through this port to maintain network consensus and share updated information.
|
||||
- **Exposure Recommendation:** This port should be exposed to enable seamless interaction and synchronization with other nodes in the network.
|
||||
|
||||
## Discovery v5 Port
|
||||
|
||||
- **Port:** `9200`
|
||||
- **Protocol:** UDP
|
||||
- **Purpose:** Used for discv5 peer discovery protocol. This is a newer discovery protocol that can be enabled with `--enable-discv5-discovery`. It operates independently from the legacy discv4 discovery on port 30303.
|
||||
- **Exposure Recommendation:** This port should be exposed if discv5 discovery is enabled to allow peer discovery.
|
||||
|
||||
## Metrics Port
|
||||
|
||||
- **Port:** `9001`
|
||||
|
||||
@@ -2757,11 +2757,11 @@
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "builder",
|
||||
"expr": "reth_engine_rpc_get_blobs_v1{$instance_label=\"$instance\", quantile=\"0.5\"}",
|
||||
"expr": "reth_engine_rpc_get_blobs_v2{$instance_label=\"$instance\", quantile=\"0.5\"}",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"legendFormat": "engine_getBlobsV1 p50",
|
||||
"legendFormat": "engine_getBlobsV2 p50",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"useBackend": false
|
||||
@@ -2773,11 +2773,11 @@
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "builder",
|
||||
"expr": "reth_engine_rpc_get_blobs_v1{$instance_label=\"$instance\", quantile=\"0.95\"}",
|
||||
"expr": "reth_engine_rpc_get_blobs_v2{$instance_label=\"$instance\", quantile=\"0.95\"}",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"legendFormat": "engine_getBlobsV1 p95",
|
||||
"legendFormat": "engine_getBlobsV2 p95",
|
||||
"range": true,
|
||||
"refId": "B",
|
||||
"useBackend": false
|
||||
@@ -2789,11 +2789,11 @@
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "builder",
|
||||
"expr": "reth_engine_rpc_get_blobs_v1{$instance_label=\"$instance\", quantile=\"0.99\"}",
|
||||
"expr": "reth_engine_rpc_get_blobs_v2{$instance_label=\"$instance\", quantile=\"0.99\"}",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"legendFormat": "engine_getBlobsV1 p99",
|
||||
"legendFormat": "engine_getBlobsV2 p99",
|
||||
"range": true,
|
||||
"refId": "C",
|
||||
"useBackend": false
|
||||
@@ -2805,11 +2805,11 @@
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "builder",
|
||||
"expr": "reth_engine_rpc_get_blobs_v1{$instance_label=\"$instance\", quantile=\"0\"}",
|
||||
"expr": "reth_engine_rpc_get_blobs_v2{$instance_label=\"$instance\", quantile=\"0\"}",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"legendFormat": "engine_getBlobsV1 min",
|
||||
"legendFormat": "engine_getBlobsV2 min",
|
||||
"range": true,
|
||||
"refId": "D",
|
||||
"useBackend": false
|
||||
@@ -2821,11 +2821,11 @@
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "builder",
|
||||
"expr": "reth_engine_rpc_get_blobs_v1{$instance_label=\"$instance\", quantile=\"1\"}",
|
||||
"expr": "reth_engine_rpc_get_blobs_v2{$instance_label=\"$instance\", quantile=\"1\"}",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"legendFormat": "engine_getBlobsV1 max",
|
||||
"legendFormat": "engine_getBlobsV2 max",
|
||||
"range": true,
|
||||
"refId": "E",
|
||||
"useBackend": false
|
||||
|
||||
@@ -41,7 +41,7 @@ use reth_ethereum::{
|
||||
builder::{
|
||||
components::{BasicPayloadServiceBuilder, ComponentsBuilder, PayloadBuilderBuilder},
|
||||
rpc::{PayloadValidatorBuilder, RpcAddOns},
|
||||
BuilderContext, Node, NodeAdapter, NodeBuilder,
|
||||
BuilderContext, Node, NodeAdapter, NodeBuilder, PayloadBuilderConfig,
|
||||
},
|
||||
core::{args::RpcServerArgs, node_config::NodeConfig},
|
||||
node::{
|
||||
@@ -337,7 +337,8 @@ where
|
||||
ctx.provider().clone(),
|
||||
pool,
|
||||
evm_config,
|
||||
EthereumBuilderConfig::new(),
|
||||
EthereumBuilderConfig::new()
|
||||
.with_extra_data(ctx.payload_builder_config().extra_data_bytes()),
|
||||
),
|
||||
};
|
||||
Ok(payload_builder)
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::{
|
||||
CustomNode,
|
||||
};
|
||||
use alloy_eips::eip2718::WithEncoded;
|
||||
use alloy_primitives::Bytes;
|
||||
use op_alloy_rpc_types_engine::{OpExecutionData, OpExecutionPayload};
|
||||
use reth_engine_primitives::EngineApiValidator;
|
||||
use reth_ethereum::{
|
||||
@@ -54,6 +55,10 @@ impl ExecutionPayload for CustomExecutionData {
|
||||
None
|
||||
}
|
||||
|
||||
fn block_access_list(&self) -> Option<&Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn parent_beacon_block_root(&self) -> Option<revm_primitives::B256> {
|
||||
self.inner.parent_beacon_block_root()
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ where
|
||||
ctx.provider().clone(),
|
||||
pool,
|
||||
evm_config,
|
||||
EthereumBuilderConfig::new(),
|
||||
EthereumBuilderConfig::new()
|
||||
.with_extra_data(ctx.payload_builder_config().extra_data_bytes()),
|
||||
);
|
||||
|
||||
let conf = ctx.payload_builder_config();
|
||||
|
||||
@@ -81,7 +81,7 @@ where
|
||||
let _eth_pubsub = rpc_handle.eth_handlers().pubsub.clone();
|
||||
// The TraceApi type that provides all the trace_ handlers
|
||||
let _trace_api = rpc_handle.trace_api();
|
||||
// The DebugApi type that provides all the trace_ handlers
|
||||
// The DebugApi type that provides all the debug_ handlers
|
||||
let _debug_api = rpc_handle.debug_api();
|
||||
|
||||
while let Some(notification) = ctx.notifications.try_next().await? {
|
||||
|
||||
Reference in New Issue
Block a user