diff --git a/.github/assets/check_wasm.sh b/.github/assets/check_wasm.sh index 5ead9d285eb..5caab112f30 100755 --- a/.github/assets/check_wasm.sh +++ b/.github/assets/check_wasm.sh @@ -12,6 +12,7 @@ exclude_crates=( reth-basic-payload-builder reth-bench reth-bench-compare + op-reth-proof-bench reth-cli reth-cli-commands reth-cli-runner diff --git a/.github/workflows/compact.yml b/.github/workflows/compact.yml index c8875f586c1..095e830671b 100644 --- a/.github/workflows/compact.yml +++ b/.github/workflows/compact.yml @@ -23,7 +23,7 @@ jobs: matrix: bin: - cargo run --bin reth --features "dev" - - cargo run --bin op-reth --features "dev" --manifest-path crates/optimism/bin/Cargo.toml + - cargo run --bin op-reth --features "dev" --manifest-path crates/optimism/bin/op-reth/Cargo.toml steps: - uses: rui314/setup-mold@v1 - uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/kurtosis-op.yml b/.github/workflows/kurtosis-op.yml index 009b8f2d45a..d66d1b5e996 100644 --- a/.github/workflows/kurtosis-op.yml +++ b/.github/workflows/kurtosis-op.yml @@ -25,7 +25,7 @@ jobs: image_tag: ghcr.io/paradigmxyz/op-reth:kurtosis-ci binary_name: op-reth cargo_features: asm-keccak - cargo_package: crates/optimism/bin/Cargo.toml + cargo_package: crates/optimism/bin/op-reth/Cargo.toml test: timeout-minutes: 60 diff --git a/Cargo.lock b/Cargo.lock index 2df5375efc3..7b4d24548b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4615,7 +4615,11 @@ version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" dependencies = [ + "base64 0.21.7", "byteorder", + "crossbeam-channel", + "flate2", + "nom", "num-traits", ] @@ -6560,6 +6564,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "op-reth-proof-bench" +version = "1.10.0" +dependencies = [ + "alloy-primitives", + "anyhow", + "clap", + "futures", + "hdrhistogram", + "reqwest", + "reth-cli-runner", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "op-revm" version = "14.1.0" diff --git a/Cargo.toml b/Cargo.toml index c1ec0bd20cd..4e7f3680132 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,8 @@ members = [ "crates/node/events/", "crates/node/metrics", "crates/node/types", - "crates/optimism/bin", + "crates/optimism/bin/op-reth", + "crates/optimism/bin/proof-bench", "crates/optimism/chainspec", "crates/optimism/cli", "crates/optimism/consensus", @@ -339,12 +340,13 @@ incremental = false [workspace.dependencies] # reth -op-reth = { path = "crates/optimism/bin" } +op-reth = { path = "crates/optimism/bin/op-reth" } reth = { path = "bin/reth" } reth-storage-rpc-provider = { path = "crates/storage/rpc-provider" } reth-basic-payload-builder = { path = "crates/payload/basic" } reth-bench = { path = "bin/reth-bench" } reth-bench-compare = { path = "bin/reth-bench-compare" } +op-reth-proof-bench = { path = "crates/optimism/bin/proof-bench" } reth-chain-state = { path = "crates/chain-state" } reth-chainspec = { path = "crates/chainspec", default-features = false } reth-cli = { path = "crates/cli/cli" } diff --git a/DockerfileOp b/DockerfileOp index 802800a497d..04aa139d6d6 100644 --- a/DockerfileOp +++ b/DockerfileOp @@ -40,7 +40,7 @@ RUN cargo chef cook \ --profile $BUILD_PROFILE \ --features "$FEATURES" \ --recipe-path recipe.json \ - --manifest-path /app/crates/optimism/bin/Cargo.toml + --manifest-path /app/crates/optimism/bin/op-reth/Cargo.toml # Build op-reth COPY . . @@ -48,7 +48,7 @@ RUN cargo build \ --profile $BUILD_PROFILE \ --features "$FEATURES" \ --bin op-reth \ - --manifest-path /app/crates/optimism/bin/Cargo.toml + --manifest-path /app/crates/optimism/bin/op-reth/Cargo.toml # Copy resulting binary RUN ls -la /app/target/$BUILD_PROFILE/op-reth diff --git a/DockerfileOpProof b/DockerfileOpProof index 0fedaff5ab7..8e967516453 100644 --- a/DockerfileOpProof +++ b/DockerfileOpProof @@ -23,10 +23,10 @@ ENV RUSTFLAGS="$RUSTFLAGS" ARG FEATURES="" ENV FEATURES=$FEATURES -RUN cargo chef cook --profile $BUILD_PROFILE --features "$FEATURES" --recipe-path recipe.json --manifest-path /app/crates/optimism/bin/Cargo.toml +RUN cargo chef cook --profile $BUILD_PROFILE --features "$FEATURES" --recipe-path recipe.json --manifest-path /app/crates/optimism/bin/op-reth/Cargo.toml COPY . . -RUN cargo build --profile $BUILD_PROFILE --features "$FEATURES" --bin op-reth --manifest-path /app/crates/optimism/bin/Cargo.toml +RUN cargo build --profile $BUILD_PROFILE --features "$FEATURES" --bin op-reth --manifest-path /app/crates/optimism/bin/op-reth/Cargo.toml RUN ls -la /app/target/$BUILD_PROFILE/op-reth RUN cp /app/target/$BUILD_PROFILE/op-reth /app/op-reth diff --git a/Makefile b/Makefile index 703fc0b58ae..18fce7b171d 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ install: ## Build and install the reth binary under `$(CARGO_HOME)/bin`. .PHONY: install-op install-op: ## Build and install the op-reth binary under `$(CARGO_HOME)/bin`. - cargo install --path crates/optimism/bin --bin op-reth --force --locked \ + cargo install --path crates/optimism/bin/op-reth --bin op-reth --force --locked \ --features "$(FEATURES)" \ --profile "$(PROFILE)" \ $(CARGO_INSTALL_EXTRA_FLAGS) @@ -89,18 +89,17 @@ build-debug: ## Build the reth binary into `target/debug` directory. cargo build --bin reth --features "$(FEATURES)" .PHONY: build-debug-op build-debug-op: ## Build the op-reth binary into `target/debug` directory. - cargo build --bin op-reth --features "$(FEATURES)" --manifest-path crates/optimism/bin/Cargo.toml + cargo build --bin op-reth --features "$(FEATURES)" --manifest-path crates/optimism/bin/op-reth/Cargo.toml .PHONY: build-op build-op: ## Build the op-reth binary into `target` directory. - cargo build --bin op-reth --features "$(FEATURES)" --profile "$(PROFILE)" --manifest-path crates/optimism/bin/Cargo.toml - + cargo build --bin op-reth --features "$(FEATURES)" --profile "$(PROFILE)" --manifest-path crates/optimism/bin/op-reth/Cargo.toml # Builds the reth binary natively. build-native-%: cargo build --bin reth --target $* --features "$(FEATURES)" --profile "$(PROFILE)" op-build-native-%: - cargo build --bin op-reth --target $* --features "$(FEATURES)" --profile "$(PROFILE)" --manifest-path crates/optimism/bin/Cargo.toml + cargo build --bin op-reth --target $* --features "$(FEATURES)" --profile "$(PROFILE)" --manifest-path crates/optimism/bin/op-reth/Cargo.toml # The following commands use `cross` to build a cross-compile. # @@ -132,7 +131,7 @@ build-%: op-build-%: RUSTFLAGS="-C link-arg=-lgcc -Clink-arg=-static-libgcc" \ - cross build --bin op-reth --target $* --features "$(FEATURES)" --profile "$(PROFILE)" --manifest-path crates/optimism/bin/Cargo.toml + cross build --bin op-reth --target $* --features "$(FEATURES)" --profile "$(PROFILE)" --manifest-path crates/optimism/bin/op-reth/Cargo.toml # Unfortunately we can't easily use cross to build for Darwin because of licensing issues. # If we wanted to, we would need to build a custom Docker image with the SDK available. @@ -410,7 +409,7 @@ profiling: ## Builds `reth` with optimisations, but also symbols. .PHONY: profiling-op profiling-op: ## Builds `op-reth` with optimisations, but also symbols. - RUSTFLAGS="-C target-cpu=native" cargo build --profile profiling --features jemalloc,asm-keccak --bin op-reth --manifest-path crates/optimism/bin/Cargo.toml + RUSTFLAGS="-C target-cpu=native" cargo build --profile profiling --features jemalloc,asm-keccak --bin op-reth --manifest-path crates/optimism/bin/op-reth/Cargo.toml .PHONY: maxperf maxperf: ## Builds `reth` with the most aggressive optimisations. @@ -418,7 +417,7 @@ maxperf: ## Builds `reth` with the most aggressive optimisations. .PHONY: maxperf-op maxperf-op: ## Builds `op-reth` with the most aggressive optimisations. - RUSTFLAGS="-C target-cpu=native" cargo build --profile maxperf --features jemalloc,asm-keccak --bin op-reth --manifest-path crates/optimism/bin/Cargo.toml + RUSTFLAGS="-C target-cpu=native" cargo build --profile maxperf --features jemalloc,asm-keccak --bin op-reth --manifest-path crates/optimism/bin/op-reth/Cargo.toml .PHONY: maxperf-no-asm maxperf-no-asm: ## Builds `reth` with the most aggressive optimisations, minus the "asm-keccak" feature. diff --git a/bin/reth-bench-compare/src/compilation.rs b/bin/reth-bench-compare/src/compilation.rs index 06e3d533782..7e3b3e49246 100644 --- a/bin/reth-bench-compare/src/compilation.rs +++ b/bin/reth-bench-compare/src/compilation.rs @@ -112,7 +112,7 @@ impl CompilationManager { cmd.arg("--bin") .arg("op-reth") .arg("--manifest-path") - .arg("crates/optimism/bin/Cargo.toml"); + .arg("crates/optimism/bin/op-reth/Cargo.toml"); } cmd.current_dir(&self.repo_root); diff --git a/crates/optimism/bin/Cargo.toml b/crates/optimism/bin/op-reth/Cargo.toml similarity index 100% rename from crates/optimism/bin/Cargo.toml rename to crates/optimism/bin/op-reth/Cargo.toml diff --git a/crates/optimism/bin/src/lib.rs b/crates/optimism/bin/op-reth/src/lib.rs similarity index 100% rename from crates/optimism/bin/src/lib.rs rename to crates/optimism/bin/op-reth/src/lib.rs diff --git a/crates/optimism/bin/src/main.rs b/crates/optimism/bin/op-reth/src/main.rs similarity index 100% rename from crates/optimism/bin/src/main.rs rename to crates/optimism/bin/op-reth/src/main.rs diff --git a/crates/optimism/bin/proof-bench/Cargo.toml b/crates/optimism/bin/proof-bench/Cargo.toml new file mode 100644 index 00000000000..68398abe835 --- /dev/null +++ b/crates/optimism/bin/proof-bench/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "op-reth-proof-bench" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +# reth +reth-cli-runner.workspace = true + +# alloy +alloy-primitives = { workspace = true, features = ["serde"] } + +tokio = { workspace = true, features = ["macros"] } +reqwest = { workspace = true, features = ["json"] } +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +clap = { workspace = true, features = ["derive"] } +futures.workspace = true +anyhow.workspace = true +hdrhistogram = "7.5" diff --git a/crates/optimism/bin/proof-bench/README.md b/crates/optimism/bin/proof-bench/README.md new file mode 100644 index 00000000000..62844ecf22e --- /dev/null +++ b/crates/optimism/bin/proof-bench/README.md @@ -0,0 +1,82 @@ +# Reth Proof Benchmark Tool + +`op-reth-proof-bench` is a specialized CLI tool designed to benchmark the performance of the `eth_getProof` RPC method on Optimism/Ethereum nodes. It iterates through a range of blocks, sending concurrent proof requests to valid addresses, and reports detailed latency and throughput metrics. + +## Features + +- **Concurrent Execution:** Sends multiple requests in parallel to stress test the RPC. +- **Detailed Reporting:** + - Real-time per-block stats (Req/s, P95 Latency, Min/Max). + - Final summary with histogram-based percentiles (P50, P95, P99). +- **Customizable Workload:** Configure worker count, request count per block, and block step. +- **Robustness:** Handles network errors gracefully and reports error counts. + +## Installation + +This tool is part of the `op-reth` workspace. You can run it directly using Cargo. + +```bash +# Build and run directly +cargo run -p reth-proof-bench -- --help +``` + +## Usage + +### Basic Example + +Benchmark 100 blocks from block `10,000,000` to `10,000,100` against a local node: + +```bash +cargo run --release -p reth-proof-bench -- \ + --rpc http://localhost:8545 \ + --from 10000000 \ + --to 10000100 +``` + +### Advanced Usage + +Stress test a remote node with higher concurrency: + +```bash +cargo run --release -p reth-proof-bench -- \ + --rpc http://remote-node:8545 \ + --from 4000000 \ + --to 4100000 \ + --step 10000 \ + --reqs 50 \ + --workers 10 +``` + +### Arguments + +| Flag | Default | Description | +|------|---------|-------------| +| `--rpc` | `http://localhost:8545` | The HTTP RPC endpoint of the node. | +| `--from` | **Required** | Start block number. | +| `--to` | **Required** | End block number. | +| `--step` | `10000` | Number of blocks to skip between benchmark iterations. | +| `--reqs` | `10` | Number of `eth_getProof` requests to send *per block*. | +| `--workers` | `2` | Number of concurrent async workers to run. | + +## Output Example + +```text +Block | Req/s | Min(ms) | P95(ms) | Max(ms) | Errors +--------------------------------------------------------------------------- +36441154 | 245.50 | 25.12 | 45.20 | 55.10 | 0 +36451154 | 230.10 | 26.05 | 48.10 | 60.15 | 0 + +--------------------------------------------------------------------------- +Summary: +Total Requests: 100 +Total Time: 0.85s +Throughput (Req/s): 117.65 +Total Errors: 0 +----------------------------------- +Min Latency: 25.12 ms +Median Latency: 32.00 ms +P95 Latency: 48.10 ms +P99 Latency: 60.15 ms +Max Latency: 60.15 ms +--------------------------------------------------------------------------- +``` diff --git a/crates/optimism/bin/proof-bench/src/args.rs b/crates/optimism/bin/proof-bench/src/args.rs new file mode 100644 index 00000000000..ad6ae48e46c --- /dev/null +++ b/crates/optimism/bin/proof-bench/src/args.rs @@ -0,0 +1,23 @@ +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(author, version, about = "Benchmark eth_getProof performance", long_about = None)] +pub struct Args { + #[arg(long, default_value = "http://localhost:8545")] + pub rpc: String, + + #[arg(long)] + pub from: u64, + + #[arg(long)] + pub to: u64, + + #[arg(long, default_value_t = 10000)] + pub step: u64, + + #[arg(long, default_value_t = 10)] + pub reqs: usize, + + #[arg(long, default_value_t = 2)] + pub workers: usize, +} diff --git a/crates/optimism/bin/proof-bench/src/main.rs b/crates/optimism/bin/proof-bench/src/main.rs new file mode 100644 index 00000000000..ff5a18ad88f --- /dev/null +++ b/crates/optimism/bin/proof-bench/src/main.rs @@ -0,0 +1,92 @@ +//! # reth-proof-bench +//! +//! A benchmarking tool for measuring the performance of historical state proofs +//! retrieval using the `eth_getProof` RPC method. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] + +mod args; +mod report; +mod rpc; +mod utils; + +use anyhow::Result; +use clap::Parser; +use futures::stream::{self, StreamExt}; +use std::time::Instant; + +use crate::{ + args::Args, + report::{BenchMetrics, BenchSummary, Reporter}, + rpc::run_proof, + utils::get_addresses, +}; +use reth_cli_runner::CliRunner; + +#[allow(missing_docs)] +fn main() -> Result<()> { + let args = Args::parse(); + + if args.from > args.to { + anyhow::bail!("--from must be less than or equal to --to"); + } + + let runner = CliRunner::try_default_runtime()?; + runner.run_command_until_exit(|_| run(args)) +} + +async fn run(args: Args) -> Result<()> { + let client = reqwest::Client::new(); + let addresses = get_addresses(); + + // Use the reporter for output + Reporter::print_header(); + + let start_time = Instant::now(); + let mut current_block = args.from; + + // Initialize Summary + let mut summary = BenchSummary::new(); + + while current_block <= args.to { + let block_start = Instant::now(); + + let target_block = current_block; + + let work_items = (0..args.reqs).map(|i| { + let addr = addresses[i % addresses.len()]; + let client = client.clone(); + let rpc_url = args.rpc.clone(); + (i, addr, client, rpc_url, target_block) + }); + + let mut stream = stream::iter(work_items) + .map(|(attempt, addr, client, url, block)| async move { + run_proof(client, url, block, attempt, addr).await + }) + .buffer_unordered(args.workers); + + let mut samples = Vec::with_capacity(args.reqs); + while let Some(sample) = stream.next().await { + summary.add(&sample); + samples.push(sample); + } + + let block_duration = block_start.elapsed().as_secs_f64(); + + // Clean logic: Create metrics -> Report metrics + let metrics = BenchMetrics::new(current_block, &samples, block_duration); + Reporter::print_metrics(&metrics); + + current_block += args.step; + } + + let total_duration = start_time.elapsed().as_secs_f64(); + Reporter::print_summary(&summary, total_duration); + + Ok(()) +} diff --git a/crates/optimism/bin/proof-bench/src/report.rs b/crates/optimism/bin/proof-bench/src/report.rs new file mode 100644 index 00000000000..2a098e7dd66 --- /dev/null +++ b/crates/optimism/bin/proof-bench/src/report.rs @@ -0,0 +1,165 @@ +use crate::rpc::Sample; +use hdrhistogram::Histogram; +use std::io::{self, Write}; + +// --- Per-Block Metrics --- + +pub struct BenchMetrics { + pub block: u64, + pub p95_ms: f64, + pub min_ms: f64, + pub max_ms: f64, + pub errors: usize, + pub throughput: f64, +} + +impl BenchMetrics { + pub fn new(block: u64, samples: &[Sample], duration_secs: f64) -> Self { + if samples.is_empty() { + return Self::empty(block); + } + + // 1. Prepare data + let mut latencies: Vec = samples.iter().map(|s| s.latency_ms).collect(); + // Sorting is efficient enough for small N (batch size) and gives exact precision + latencies.sort_by(|a, b| a.partial_cmp(b).unwrap()); + + let errors = samples.iter().filter(|s| !s.success).count(); + + // 2. Calculate Stats + let min_ms = *latencies.first().unwrap_or(&0.0); + let max_ms = *latencies.last().unwrap_or(&0.0); + let p95_ms = calculate_percentile(&latencies, 0.95); + + let throughput = + if duration_secs > 0.0 { samples.len() as f64 / duration_secs } else { 0.0 }; + + Self { block, p95_ms, min_ms, max_ms, errors, throughput } + } + + fn empty(block: u64) -> Self { + Self { block, p95_ms: 0.0, min_ms: 0.0, max_ms: 0.0, errors: 0, throughput: 0.0 } + } +} + +// --- Global Accumulator --- + +pub struct BenchSummary { + pub hist: Histogram, + pub total_errors: usize, + pub total_requests: usize, + pub min_ms: f64, + pub max_ms: f64, +} + +impl BenchSummary { + pub fn new() -> Self { + Self { + hist: Histogram::::new_with_bounds(1, 3_600_000, 3).unwrap(), + total_errors: 0, + total_requests: 0, + min_ms: f64::MAX, + max_ms: 0.0, + } + } + + pub fn add(&mut self, sample: &Sample) { + self.total_requests += 1; + + if !sample.success { + self.total_errors += 1; + } + + let lat = sample.latency_ms; + + if lat < self.min_ms { + self.min_ms = lat; + } + if lat > self.max_ms { + self.max_ms = lat; + } + + // Update Histogram (saturating cast to avoid crashes on bad data) + let val = (lat as u64).max(1); + self.hist.record(val).ok(); + } +} + +// --- Output Handling --- + +pub struct Reporter; + +impl Reporter { + const SEP: &'static str = + "---------------------------------------------------------------------------"; + + pub fn print_header() { + let header = format!( + "{:<10} | {:<10} | {:<10} | {:<10} | {:<10} | {:<10}", + "Block", "Req/s", "Min(ms)", "P95(ms)", "Max(ms)", "Errors" + ); + + let stdout = io::stdout(); + let mut handle = stdout.lock(); + writeln!(handle, "{}", header).unwrap(); + writeln!(handle, "{}", Self::SEP).unwrap(); + } + + pub fn print_metrics(metrics: &BenchMetrics) { + let line = format!( + "{:<10} | {:<10.2} | {:<10.2} | {:<10.2} | {:<10.2} | {:<10}", + metrics.block, + metrics.throughput, + metrics.min_ms, + metrics.p95_ms, + metrics.max_ms, + metrics.errors + ); + + let stdout = io::stdout(); + let mut handle = stdout.lock(); + writeln!(handle, "{}", line).unwrap(); + } + + pub fn print_summary(summary: &BenchSummary, total_duration: f64) { + if summary.total_requests == 0 { + println!("\nNo requests processed."); + return; + } + + let throughput = summary.total_requests as f64 / total_duration; + + // Histogram percentiles + let p50 = summary.hist.value_at_quantile(0.50); + let p95 = summary.hist.value_at_quantile(0.95); + let p99 = summary.hist.value_at_quantile(0.99); + + // Sanity check min in case it stayed at MAX + let min_print = if summary.min_ms == f64::MAX { 0.0 } else { summary.min_ms }; + + println!("\n{:-<75}", ""); + println!("Summary:"); + println!("{:<20} {}", "Total Requests:", summary.total_requests); + println!("{:<20} {:.2}s", "Total Time:", total_duration); + println!("{:<20} {:.2}", "Throughput (Req/s):", throughput); + println!("{:<20} {}", "Total Errors:", summary.total_errors); + println!("{:-<35}", ""); + println!("{:<20} {:.2} ms", "Min Latency:", min_print); + println!("{:<20} {} ms", "Median Latency:", p50); + println!("{:<20} {} ms", "P95 Latency:", p95); + println!("{:<20} {} ms", "P99 Latency:", p99); + println!("{:<20} {:.2} ms", "Max Latency:", summary.max_ms); + println!("{:-<75}", ""); + } +} + +// --- Helpers --- + +// Helper to extract clean math logic from struct initialization +fn calculate_percentile(sorted_data: &[f64], percentile: f64) -> f64 { + if sorted_data.is_empty() { + return 0.0; + } + let idx = ((sorted_data.len() as f64 * percentile).ceil() as usize).saturating_sub(1); + sorted_data.get(idx).copied().unwrap_or(0.0) +} diff --git a/crates/optimism/bin/proof-bench/src/rpc.rs b/crates/optimism/bin/proof-bench/src/rpc.rs new file mode 100644 index 00000000000..ade53ca2f7e --- /dev/null +++ b/crates/optimism/bin/proof-bench/src/rpc.rs @@ -0,0 +1,59 @@ +use crate::utils::{balance_of_slot, CONTRACT}; +use alloy_primitives::Address; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use std::time::Instant; + +#[derive(Debug, Serialize, Deserialize)] +struct RpcResponse { + jsonrpc: String, + id: usize, + result: Option, + error: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +struct RpcError { + code: i32, + message: String, +} + +pub struct Sample { + pub latency_ms: f64, + pub success: bool, +} + +pub async fn run_proof( + client: reqwest::Client, + url: String, + block: u64, + id: usize, + addr: Address, +) -> Sample { + let start = Instant::now(); + let slot = balance_of_slot(addr); + + // Format hash with 0x used by alloy B256 debug/display + let params = json!([CONTRACT, [format!("{}", slot)], format!("0x{:x}", block)]); + + let body = json!({ + "jsonrpc": "2.0", + "id": id, + "method": "eth_getProof", + "params": params + }); + + let resp = client.post(&url).json(&body).send().await; + + let latency = start.elapsed().as_secs_f64() * 1000.0; + + let success = match resp { + Ok(res) => match res.json::().await { + Ok(rpc_resp) => rpc_resp.error.is_none() && rpc_resp.result.is_some(), + Err(_) => false, + }, + Err(_) => false, + }; + + Sample { latency_ms: latency, success } +} diff --git a/crates/optimism/bin/proof-bench/src/utils.rs b/crates/optimism/bin/proof-bench/src/utils.rs new file mode 100644 index 00000000000..dfeb0222f32 --- /dev/null +++ b/crates/optimism/bin/proof-bench/src/utils.rs @@ -0,0 +1,38 @@ +use alloy_primitives::{keccak256, Address, B256, U256}; + +pub const CONTRACT: &str = "0x4200000000000000000000000000000000000006"; + +/// Calculate the storage slot for `balanceOf[addr]` +/// Solidity mappings: keccak256(abi.encode(key, slot_position)) +pub fn balance_of_slot(addr: Address) -> B256 { + // Left-pad address (20 bytes) to 32 bytes + let mut data = Vec::with_capacity(64); + data.extend_from_slice(&[0u8; 12]); + data.extend_from_slice(addr.as_slice()); + + // Pad slot position (3) to 32 bytes + let slot_bytes: [u8; 32] = U256::from(3).to_be_bytes(); + data.extend_from_slice(&slot_bytes); + + keccak256(data) +} + +pub fn get_addresses() -> Vec
{ + vec![ + "0x48107537B9e358B1894c7a491C17E4bF035AFC74".parse().unwrap(), + "0x917AbB78953902213F63e16268E78feBAC362846".parse().unwrap(), + "0xA32Ce4EB5802809EB89032E6cc0FB06EB51bde38".parse().unwrap(), + "0x8AE9Ed8aB2abF45376cDFb671c05170353dd1F0E".parse().unwrap(), + "0x2195DbA1ab41966E91C22e4C601Be6517a40f2aB".parse().unwrap(), + "0x04bF3799798077629cb627DfF76E48a015f0B3CB".parse().unwrap(), + "0x5aaFa65D234e962121C6f44fd570EE353Ac52Bf5".parse().unwrap(), + "0x2a58adA546c2e9cd3134c163FBfC0E335Ff91AfA".parse().unwrap(), + "0x8AE9Ed8aB2abF45376cDFb671c05170353dd1F0E".parse().unwrap(), + "0x8524771B4c5a8122E8959cFDeB641E3f498188AF".parse().unwrap(), + "0xf530AD425154CC9635CAaD538e8bf3C638191a4E".parse().unwrap(), + "0x73a5bB60b0B0fc35710DDc0ea9c407031E31Bdbb".parse().unwrap(), + "0xfE978E4Dc6f3d716121c603311b0c37a9acd7234".parse().unwrap(), + "0xcAAd4EB9ABfc93Ab9eA86FB5733B8F85c952200b".parse().unwrap(), + "0xd15b5531050AC78Aa78AeF8A6DE4256Fa4536107".parse().unwrap(), + ] +} diff --git a/crates/optimism/tests/Makefile b/crates/optimism/tests/Makefile index c6fa968aaa2..459b8e09301 100644 --- a/crates/optimism/tests/Makefile +++ b/crates/optimism/tests/Makefile @@ -17,7 +17,7 @@ all: build-docker run # Build op-reth build: @echo "Building op-reth binary..." - cd ../../../ && cargo build --bin op-reth --manifest-path crates/optimism/bin/Cargo.toml + cd ../../../ && cargo build --bin op-reth --manifest-path crates/optimism/bin/op-reth/Cargo.toml # Build the op-reth Docker image build-docker: