From c1dff1642ef0b4fdeb738236c0fbe39c1b2c98d4 Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Mon, 23 Mar 2026 22:37:44 +0800 Subject: [PATCH 1/3] refactor: foundation cleanup - rename, edition fixes, constants, coverage CI - Rename `validator-core` crate to `stateless-core` (directory, Cargo.toml, all `use validator_core::` references across workspace, docs, CODEOWNERS, and logging filter directives) - Fix `debug-trace-server`: set `edition.workspace = true` and `version.workspace = true` (was 2021 / 0.1.0) - Move `DEFAULT_METRICS_PORT` to `stateless-common` and re-export from both binaries; deduplicate `SLOW_STAGE_THRESHOLD_MS` in `debug-trace-server` (was declared in both `data_provider.rs` and `rpc_service.rs`) - Add `scripts/coverage_stateless_core.sh` and `.github/workflows/coverage.yml` for coverage reporting via `cargo-llvm-cov` + Codecov (following mega-evm pattern) - Add `.github/codecov.yml` config targeting `stateless-core` package --- .github/CODEOWNERS | 4 +- .github/codecov.yml | 26 +++++ .github/workflows/coverage.yml | 61 +++++++++++ AGENTS.md | 22 ++-- Cargo.lock | 100 +++++++++--------- Cargo.toml | 2 +- README.md | 2 +- bin/debug-trace-server/Cargo.toml | 10 +- bin/debug-trace-server/src/data_provider.rs | 58 +++++----- bin/debug-trace-server/src/main.rs | 16 +-- bin/debug-trace-server/src/metrics.rs | 4 +- bin/debug-trace-server/src/response_cache.rs | 12 +-- bin/debug-trace-server/src/rpc_service.rs | 23 ++-- bin/debug-trace-server/src/timing.rs | 2 +- .../tests/block_tag_test.rs | 2 +- .../tests/cache_metrics_test.rs | 2 +- .../tests/consistency_test.rs | 2 +- .../tests/performance_test.rs | 2 +- bin/debug-trace-server/tests/prune_test.rs | 2 +- .../tests/timing_header_test.rs | 2 +- bin/stateless-validator/Cargo.toml | 4 +- bin/stateless-validator/src/main.rs | 10 +- bin/stateless-validator/src/metrics.rs | 10 +- crates/stateless-common/src/lib.rs | 3 + crates/stateless-common/src/logging.rs | 2 +- .../Cargo.toml | 2 +- .../src/chain_spec.rs | 0 .../src/chain_sync.rs | 0 .../src/data_types.rs | 0 .../src/database.rs | 0 .../src/executor.rs | 0 .../src/lib.rs | 0 .../src/light_witness.rs | 0 .../src/rpc_client.rs | 0 .../src/tracing_executor.rs | 0 .../src/validator_db.rs | 0 .../src/withdrawals.rs | 0 scripts/coverage_stateless_core.sh | 50 +++++++++ 38 files changed, 283 insertions(+), 152 deletions(-) create mode 100644 .github/codecov.yml create mode 100644 .github/workflows/coverage.yml rename crates/{validator-core => stateless-core}/Cargo.toml (98%) rename crates/{validator-core => stateless-core}/src/chain_spec.rs (100%) rename crates/{validator-core => stateless-core}/src/chain_sync.rs (100%) rename crates/{validator-core => stateless-core}/src/data_types.rs (100%) rename crates/{validator-core => stateless-core}/src/database.rs (100%) rename crates/{validator-core => stateless-core}/src/executor.rs (100%) rename crates/{validator-core => stateless-core}/src/lib.rs (100%) rename crates/{validator-core => stateless-core}/src/light_witness.rs (100%) rename crates/{validator-core => stateless-core}/src/rpc_client.rs (100%) rename crates/{validator-core => stateless-core}/src/tracing_executor.rs (100%) rename crates/{validator-core => stateless-core}/src/validator_db.rs (100%) rename crates/{validator-core => stateless-core}/src/withdrawals.rs (100%) create mode 100755 scripts/coverage_stateless_core.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dfd34f3f..496f6edd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,8 +1,8 @@ # Default: repo owner owns everything * @Troublor -# validator-core -/crates/validator-core/ @flyq +# stateless-core +/crates/stateless-core/ @flyq # stateless-common (shared by both) /crates/stateless-common/ @flyq @krabat-l diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 00000000..bc0103c5 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,26 @@ +coverage: + range: 60..100 + round: down + precision: 1 + status: + project: + stateless-core: + threshold: 1% + patch: + stateless-core: + target: auto + threshold: 1% + base: auto + only_pulls: true + +comment: + layout: "condensed_header, condensed_files, condensed_footer" + require_changes: true + hide_project_coverage: false + +ignore: + - "bin/**/*" + - "crates/stateless-common/**/*" + +fixes: + - "/home/runner/work/stateless-validator/stateless-validator/::" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..e9d5f6fd --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,61 @@ +name: Coverage + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + stateless-core: + name: stateless-core coverage + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + components: llvm-tools-preview + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: Generate coverage reports + run: scripts/coverage_stateless_core.sh + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: stateless-core-coverage + path: target/coverage/stateless-core + if-no-files-found: error + + - name: Record Rust version + run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV" + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + disable_search: true + fail_ci_if_error: false + files: target/coverage/stateless-core/lcov.info + flags: stateless-core + name: stateless-core + token: ${{ secrets.CODECOV_TOKEN }} + env_vars: RUST + verbose: true diff --git a/AGENTS.md b/AGENTS.md index 384a454e..ceb3ce4f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,12 +17,12 @@ cargo build --release # Test cargo test # all tests -cargo test -p validator-core # core crate only -cargo test -p validator-core -- test_name # single test +cargo test -p stateless-core # core crate only +cargo test -p stateless-core -- test_name # single test # Check compiler errors (preferred over clippy for quick checks) cargo check -cargo check -p validator-core +cargo check -p stateless-core # Lint (CI runs all of these) cargo fmt --all --check @@ -36,7 +36,7 @@ The project uses nightly `2026-02-03` toolchain (edition 2024, rust-version 1.95 | Crate | Path | Purpose | | -------------------- | -------------------------- | ---------------------------------------------------------- | -| `validator-core` | `crates/validator-core` | Core validation logic, database, EVM execution, RPC client | +| `stateless-core` | `crates/stateless-core` | Core validation logic, database, EVM execution, RPC client | | `stateless-common` | `crates/stateless-common` | Common utilities including logging configuration | | `stateless-validator`| `bin/stateless-validator` | Main binary: chain sync, parallel validation workers | | `debug-trace-server` | `bin/debug-trace-server` | Standalone RPC server for debug/trace methods | @@ -103,13 +103,13 @@ The server includes an HTTP response cache (`quick_cache`) for pre-serialized JS | File | Purpose | | -------------------------------------------------- | ------------------------------------------------- | -| `crates/validator-core/src/validator_db.rs` | Central database with 10 redb tables | -| `crates/validator-core/src/executor.rs` | Block validation and EVM replay | -| `crates/validator-core/src/tracing_executor.rs` | Block tracing with TracerKind deduplication | -| `crates/validator-core/src/database.rs` | WitnessDatabase implementing `revm::DatabaseRef` | -| `crates/validator-core/src/rpc_client.rs` | RPC client for blocks, witnesses, and bytecode | -| `crates/validator-core/src/chain_sync.rs` | Chain synchronization and remote chain tracking | -| `crates/validator-core/src/withdrawals.rs` | Withdrawal validation and MPT witness handling | +| `crates/stateless-core/src/validator_db.rs` | Central database with 10 redb tables | +| `crates/stateless-core/src/executor.rs` | Block validation and EVM replay | +| `crates/stateless-core/src/tracing_executor.rs` | Block tracing with TracerKind deduplication | +| `crates/stateless-core/src/database.rs` | WitnessDatabase implementing `revm::DatabaseRef` | +| `crates/stateless-core/src/rpc_client.rs` | RPC client for blocks, witnesses, and bytecode | +| `crates/stateless-core/src/chain_sync.rs` | Chain synchronization and remote chain tracking | +| `crates/stateless-core/src/withdrawals.rs` | Withdrawal validation and MPT witness handling | | `bin/stateless-validator/src/main.rs` | CLI, chain sync loop, parallel validation workers | | `bin/debug-trace-server/src/rpc_service.rs` | RPC method definitions and handlers | | `bin/debug-trace-server/src/data_provider.rs` | Block data fetching with single-flight coalescing | diff --git a/Cargo.lock b/Cargo.lock index 8dbdf649..94084b7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,7 +1890,7 @@ dependencies = [ [[package]] name = "debug-trace-server" -version = "0.1.0" +version = "2.0.8" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -1921,11 +1921,11 @@ dependencies = [ "serde", "serde_json", "stateless-common", + "stateless-core", "tempfile", "tokio", "tower 0.4.13", "tracing", - "validator-core", ] [[package]] @@ -5911,6 +5911,53 @@ dependencies = [ "tracing-subscriber 0.3.20", ] +[[package]] +name = "stateless-core" +version = "2.0.8" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-genesis", + "alloy-hardforks", + "alloy-op-evm", + "alloy-op-hardforks", + "alloy-primitives", + "alloy-provider", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-rpc-types-trace", + "alloy-serde", + "alloy-trie", + "base64", + "bincode 2.0.1", + "dyn-clone", + "eyre", + "futures", + "lz4_flex", + "mega-evm", + "num_cpus", + "op-alloy-network", + "op-alloy-rpc-types", + "rayon", + "redb", + "reth-ethereum-forks", + "reth-optimism-chainspec", + "reth-trie", + "reth-trie-common", + "reth-trie-sparse", + "revm", + "revm-inspectors", + "rustc-hash", + "salt", + "serde", + "serde_json", + "thiserror 2.0.17", + "tokio", + "tracing", + "zstd", +] + [[package]] name = "stateless-validator" version = "2.0.8" @@ -5934,12 +5981,12 @@ dependencies = [ "serde", "serde_json", "stateless-common", + "stateless-core", "tempfile", "tokio", "tokio-util", "tracing", "tracing-subscriber 0.3.20", - "validator-core", "zstd", ] @@ -6573,53 +6620,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "validator-core" -version = "2.0.8" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-evm", - "alloy-genesis", - "alloy-hardforks", - "alloy-op-evm", - "alloy-op-hardforks", - "alloy-primitives", - "alloy-provider", - "alloy-rlp", - "alloy-rpc-types-eth", - "alloy-rpc-types-trace", - "alloy-serde", - "alloy-trie", - "base64", - "bincode 2.0.1", - "dyn-clone", - "eyre", - "futures", - "lz4_flex", - "mega-evm", - "num_cpus", - "op-alloy-network", - "op-alloy-rpc-types", - "rayon", - "redb", - "reth-ethereum-forks", - "reth-optimism-chainspec", - "reth-trie", - "reth-trie-common", - "reth-trie-sparse", - "revm", - "revm-inspectors", - "rustc-hash", - "salt", - "serde", - "serde_json", - "thiserror 2.0.17", - "tokio", - "tracing", - "zstd", -] - [[package]] name = "valuable" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 8efa419d..7f1a3bae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "bin/debug-trace-server", "bin/stateless-validator", "crates/stateless-common", - "crates/validator-core", + "crates/stateless-core", ] resolver = "2" diff --git a/README.md b/README.md index ee2601a4..dbfc6095 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This validator enables efficient block verification using cryptographic witness ## Project Structure - **`bin/stateless-validator`**: Main validator binary that coordinates chain synchronization and manages validation workers -- **`crates/validator-core`**: Core library providing validation logic, database operations, and EVM execution +- **`crates/stateless-core`**: Core library providing validation logic, database operations, and EVM execution - **`test_data/`**: Integration test data including blocks, witnesses, and contract bytecode ## Quick Start diff --git a/bin/debug-trace-server/Cargo.toml b/bin/debug-trace-server/Cargo.toml index 83ec99b7..e2975a90 100644 --- a/bin/debug-trace-server/Cargo.toml +++ b/bin/debug-trace-server/Cargo.toml @@ -1,7 +1,11 @@ [package] name = "debug-trace-server" -version = "0.1.0" -edition = "2021" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +exclude.workspace = true [dependencies] @@ -46,7 +50,7 @@ tracing.workspace = true # Reuse validator-core stateless-common = { path = "../../crates/stateless-common" } -validator-core = { path = "../../crates/validator-core" } +stateless-core = { path = "../../crates/stateless-core" } [dev-dependencies] alloy-consensus.workspace = true diff --git a/bin/debug-trace-server/src/data_provider.rs b/bin/debug-trace-server/src/data_provider.rs index 9f03450a..ef255aef 100644 --- a/bin/debug-trace-server/src/data_provider.rs +++ b/bin/debug-trace-server/src/data_provider.rs @@ -25,9 +25,9 @@ use eyre::Result; use op_alloy_rpc_types::Transaction; use revm::state::Bytecode; use salt::SaltWitness; +use stateless_core::{LightWitness, RpcClient, ValidatorDB, withdrawals::MptWitness}; use tokio::sync::broadcast; use tracing::{debug, instrument, trace, warn}; -use validator_core::{withdrawals::MptWitness, LightWitness, RpcClient, ValidatorDB}; use crate::metrics::{ ChainSyncMetrics, DataSourceMetrics, SingleFlightMetrics, UpstreamMetrics, WitnessSourceMetrics, @@ -59,7 +59,7 @@ pub const DEFAULT_WITNESS_TIMEOUT_SECS: u64 = 8; const WITNESS_RETRY_INTERVAL_MS: u64 = 200; /// Slow stage threshold: any individual stage exceeding this triggers a warn log. -const SLOW_STAGE_THRESHOLD_MS: u128 = 1000; +pub(crate) const SLOW_STAGE_THRESHOLD_MS: u128 = 1000; /// Broadcast sender type for single-flight request pattern. /// Used to notify all waiters when a block fetch completes. @@ -122,10 +122,10 @@ impl DataProvider { /// * `Err` - If the block cannot be fetched from any source pub async fn get_block_data(&self, block_num: u64) -> Result { // Try to get block hash from local database first - if let Some(db) = &self.validator_db { - if let Ok(Some(hash)) = db.get_block_hash(block_num) { - return self.get_block_data_by_hash(hash).await; - } + if let Some(db) = &self.validator_db && + let Ok(Some(hash)) = db.get_block_hash(block_num) + { + return self.get_block_data_by_hash(hash).await; } // Fall back to RPC - fetch header to get hash, then delegate to get_block_data_by_hash @@ -148,19 +148,19 @@ impl DataProvider { let start = std::time::Instant::now(); // Try to get from local database - if let Some(db) = &self.validator_db { - if let Ok(data) = self.get_block_data_from_db(db, block_hash).await { - trace!( - block_hash = %block_hash, - source = "database", - elapsed_ms = start.elapsed().as_millis() as u64, - "Block data retrieved from local DB" - ); - DataSourceMetrics::new_for_source("db").record(); - SingleFlightMetrics::new_for_type("bypassed").record(); - self.record_block_distance(data.block.header.number); - return Ok(data); - } + if let Some(db) = &self.validator_db && + let Ok(data) = self.get_block_data_from_db(db, block_hash).await + { + trace!( + block_hash = %block_hash, + source = "database", + elapsed_ms = start.elapsed().as_millis() as u64, + "Block data retrieved from local DB" + ); + DataSourceMetrics::new_for_source("db").record(); + SingleFlightMetrics::new_for_type("bypassed").record(); + self.record_block_distance(data.block.header.number); + return Ok(data); } // Fall back to RPC @@ -253,11 +253,11 @@ impl DataProvider { /// Records the distance of a requested block from the local chain tip. fn record_block_distance(&self, block_number: u64) { - if let Some(db) = &self.validator_db { - if let Ok(Some((tip, _))) = db.get_local_tip() { - let distance = tip.saturating_sub(block_number); - ChainSyncMetrics::create().record_block_distance(distance); - } + if let Some(db) = &self.validator_db && + let Ok(Some((tip, _))) = db.get_local_tip() + { + let distance = tip.saturating_sub(block_number); + ChainSyncMetrics::create().record_block_distance(distance); } } @@ -280,7 +280,7 @@ impl DataProvider { // Extract code hashes and get contracts let start = std::time::Instant::now(); - let code_hashes = validator_core::extract_code_hashes(&witness); + let code_hashes = stateless_core::extract_code_hashes(&witness); let num_contracts = code_hashes.len(); let contracts = self.get_contracts_with_db(db, &code_hashes).await?; let fetch_contracts_ms = start.elapsed().as_millis(); @@ -413,7 +413,7 @@ impl DataProvider { // Step 4: Extract code hashes and fetch contracts let start = std::time::Instant::now(); - let code_hashes = validator_core::extract_code_hashes(&witness); + let code_hashes = stateless_core::extract_code_hashes(&witness); let num_contracts = code_hashes.len(); let contracts = self.get_contracts(&code_hashes).await?; let fetch_contracts_ms = start.elapsed().as_millis(); @@ -507,8 +507,7 @@ impl DataProvider { // Block is newer than DB max: retry witness endpoint until timeout trace!( block_number, - db_max_height, - "Block is new, using retry loop for witness endpoint" + db_max_height, "Block is new, using retry loop for witness endpoint" ); let start = std::time::Instant::now(); @@ -541,8 +540,7 @@ impl DataProvider { // Block is older/pruned: single attempt on witness endpoint, then immediate Cloudflare trace!( block_number, - db_max_height, - "Block is old/pruned, single attempt then Cloudflare fallback" + db_max_height, "Block is old/pruned, single attempt then Cloudflare fallback" ); let start = std::time::Instant::now(); diff --git a/bin/debug-trace-server/src/main.rs b/bin/debug-trace-server/src/main.rs index 183e436b..4f935fb9 100644 --- a/bin/debug-trace-server/src/main.rs +++ b/bin/debug-trace-server/src/main.rs @@ -43,18 +43,18 @@ use std::{path::PathBuf, sync::Arc}; use alloy_genesis::Genesis; -use alloy_primitives::{hex, BlockHash, B256}; +use alloy_primitives::{B256, BlockHash, hex}; use alloy_rpc_types_eth::BlockId; use clap::Parser; -use eyre::{anyhow, ensure, Result}; +use eyre::{Result, anyhow, ensure}; use jsonrpsee::server::Server; use stateless_common::logging::LogArgs; +use stateless_core::{ + ChainSyncConfig, RpcClient, RpcClientConfig, ValidatorDB, chain_spec::ChainSpec, + remote_chain_tracker, +}; use tokio::task; use tracing::{debug, error, info, instrument, warn}; -use validator_core::{ - chain_spec::ChainSpec, remote_chain_tracker, ChainSyncConfig, RpcClient, RpcClientConfig, - ValidatorDB, -}; mod data_provider; mod metrics; @@ -64,7 +64,7 @@ mod rpc_service; mod timing; use data_provider::DataProvider; -use response_cache::{ResponseCache, ResponseCacheConfig, DEFAULT_RESPONSE_CACHE_ESTIMATED_ITEMS}; +use response_cache::{DEFAULT_RESPONSE_CACHE_ESTIMATED_ITEMS, ResponseCache, ResponseCacheConfig}; use rpc_service::RpcContext; /// Command line arguments for the debug-trace-server. @@ -317,7 +317,7 @@ async fn main() -> Result<()> { } } }), - Some(move |result: &validator_core::FetchResult| { + Some(move |result: &stateless_core::FetchResult| { if let Some(height) = result.remote_chain_height { fetch_metrics.set_remote_height(height); } diff --git a/bin/debug-trace-server/src/metrics.rs b/bin/debug-trace-server/src/metrics.rs index 348b6d5e..9e537ace 100644 --- a/bin/debug-trace-server/src/metrics.rs +++ b/bin/debug-trace-server/src/metrics.rs @@ -11,9 +11,7 @@ use eyre::Result; use metrics::{Counter, Gauge, Histogram}; use metrics_derive::Metrics; use metrics_exporter_prometheus::PrometheusBuilder; - -/// Default port for Prometheus metrics HTTP endpoint. -pub const DEFAULT_METRICS_PORT: u16 = 9090; +pub use stateless_common::DEFAULT_METRICS_PORT; // --------------------------------------------------------------------------- // RPC Method Name Constants diff --git a/bin/debug-trace-server/src/response_cache.rs b/bin/debug-trace-server/src/response_cache.rs index 8e567582..97df8d13 100644 --- a/bin/debug-trace-server/src/response_cache.rs +++ b/bin/debug-trace-server/src/response_cache.rs @@ -13,17 +13,17 @@ use std::{ collections::{HashMap, HashSet}, hash::RandomState, sync::{ - atomic::{AtomicU64, Ordering}, Arc, + atomic::{AtomicU64, Ordering}, }, }; use alloy_primitives::B256; use alloy_rpc_types_trace::geth::GethDebugTracingOptions; -use quick_cache::{sync::Cache, Lifecycle, Weighter}; +use quick_cache::{Lifecycle, Weighter, sync::Cache}; use tracing::{debug, trace}; -use crate::metrics::{CacheMetrics, CACHE_TYPE_DEBUG_TRACE, CACHE_TYPE_TRACE}; +use crate::metrics::{CACHE_TYPE_DEBUG_TRACE, CACHE_TYPE_TRACE, CacheMetrics}; // --------------------------------------------------------------------------- // Configuration @@ -593,11 +593,7 @@ impl CacheStats { /// Returns the cache hit rate as a percentage. pub fn hit_rate(&self) -> f64 { let total = self.hits + self.misses; - if total == 0 { - 0.0 - } else { - (self.hits as f64 / total as f64) * 100.0 - } + if total == 0 { 0.0 } else { (self.hits as f64 / total as f64) * 100.0 } } } diff --git a/bin/debug-trace-server/src/rpc_service.rs b/bin/debug-trace-server/src/rpc_service.rs index 6e3384cd..f35c82fc 100644 --- a/bin/debug-trace-server/src/rpc_service.rs +++ b/bin/debug-trace-server/src/rpc_service.rs @@ -5,8 +5,8 @@ use std::{ sync::{ - atomic::{AtomicU64, Ordering}, Arc, + atomic::{AtomicU64, Ordering}, }, time::{Duration, Instant}, }; @@ -16,15 +16,15 @@ use alloy_rpc_types_eth::BlockNumberOrTag; use alloy_rpc_types_trace::geth::GethDebugTracingOptions; use dashmap::DashMap; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use stateless_core::chain_spec::ChainSpec; use tracing::{trace, warn}; -use validator_core::chain_spec::ChainSpec; use crate::{ - data_provider::{BlockData, DataProvider}, + data_provider::{BlockData, DataProvider, SLOW_STAGE_THRESHOLD_MS}, metrics::{ - self, DataSourceMetrics, EvmExecutionMetrics, ResponseSizeMetrics, RpcGlobalMetrics, - SingleFlightMetrics, METHOD_DEBUG_TRACE_BLOCK_BY_HASH, METHOD_DEBUG_TRACE_BLOCK_BY_NUMBER, - METHOD_DEBUG_TRACE_TRANSACTION, METHOD_TRACE_BLOCK, METHOD_TRACE_TRANSACTION, + self, DataSourceMetrics, EvmExecutionMetrics, METHOD_DEBUG_TRACE_BLOCK_BY_HASH, + METHOD_DEBUG_TRACE_BLOCK_BY_NUMBER, METHOD_DEBUG_TRACE_TRANSACTION, METHOD_TRACE_BLOCK, + METHOD_TRACE_TRANSACTION, ResponseSizeMetrics, RpcGlobalMetrics, SingleFlightMetrics, }, response_cache::{CachedResource, ResponseCache, ResponseVariant}, }; @@ -32,9 +32,6 @@ use crate::{ /// Slow request threshold for logging warnings. const SLOW_REQUEST_THRESHOLD: Duration = Duration::from_secs(5); -/// Slow stage threshold: any individual stage exceeding this triggers a warn log. -const SLOW_STAGE_THRESHOLD_MS: u128 = 1000; - // --------------------------------------------------------------------------- // RPC Trait Definitions (proc-macro) // --------------------------------------------------------------------------- @@ -283,7 +280,7 @@ async fn compute_debug_trace_block( ) -> Result { let start = Instant::now(); - let results = validator_core::trace_block( + let results = stateless_core::trace_block( chain_spec, &data.block, data.witness.clone(), @@ -325,7 +322,7 @@ async fn compute_parity_trace_block( ) -> Result { let start = Instant::now(); - let results = validator_core::parity_trace_block( + let results = stateless_core::parity_trace_block( chain_spec, &data.block, data.witness.clone(), @@ -595,7 +592,7 @@ impl DebugTraceRpcServer for RpcContext { })?; let evm_start = Instant::now(); - let result = validator_core::trace_transaction( + let result = stateless_core::trace_transaction( &self.chain_spec, &data.block, tx_index, @@ -735,7 +732,7 @@ impl TraceRpcServer for RpcContext { }; let evm_start = Instant::now(); - let result = validator_core::parity_trace_transaction( + let result = stateless_core::parity_trace_transaction( &self.chain_spec, &data.block, tx_index, diff --git a/bin/debug-trace-server/src/timing.rs b/bin/debug-trace-server/src/timing.rs index 956e86bf..26f563c6 100644 --- a/bin/debug-trace-server/src/timing.rs +++ b/bin/debug-trace-server/src/timing.rs @@ -128,7 +128,7 @@ where /// CPU time, which excludes time spent sleeping or waiting for I/O. /// Returns [`Duration::ZERO`] if the system call fails. fn thread_cpu_time() -> Duration { - use libc::{clock_gettime, timespec, CLOCK_THREAD_CPUTIME_ID}; + use libc::{CLOCK_THREAD_CPUTIME_ID, clock_gettime, timespec}; unsafe { let mut ts = timespec { tv_sec: 0, tv_nsec: 0 }; if clock_gettime(CLOCK_THREAD_CPUTIME_ID, std::ptr::addr_of_mut!(ts)) != 0 { diff --git a/bin/debug-trace-server/tests/block_tag_test.rs b/bin/debug-trace-server/tests/block_tag_test.rs index 58356c8d..cbac651b 100644 --- a/bin/debug-trace-server/tests/block_tag_test.rs +++ b/bin/debug-trace-server/tests/block_tag_test.rs @@ -30,7 +30,7 @@ use alloy_primitives::{Bytes, TxKind, U256}; use alloy_signer_local::PrivateKeySigner; use reqwest::blocking::Client; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::{Value, json}; // --------------------------------------------------------------------------- // Test Infrastructure diff --git a/bin/debug-trace-server/tests/cache_metrics_test.rs b/bin/debug-trace-server/tests/cache_metrics_test.rs index 45d5ba14..7bf53dd5 100644 --- a/bin/debug-trace-server/tests/cache_metrics_test.rs +++ b/bin/debug-trace-server/tests/cache_metrics_test.rs @@ -23,7 +23,7 @@ use std::{env, time::Duration}; use reqwest::blocking::Client; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::{Value, json}; /// Test configuration loaded from environment variables. struct TestConfig { diff --git a/bin/debug-trace-server/tests/consistency_test.rs b/bin/debug-trace-server/tests/consistency_test.rs index 15f3cbae..698a06ba 100644 --- a/bin/debug-trace-server/tests/consistency_test.rs +++ b/bin/debug-trace-server/tests/consistency_test.rs @@ -33,7 +33,7 @@ use alloy_primitives::{Address, Bytes, TxKind, U256}; use alloy_signer_local::PrivateKeySigner; use reqwest::blocking::Client; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::{Value, json}; /// Test configuration loaded from environment variables. struct TestConfig { diff --git a/bin/debug-trace-server/tests/performance_test.rs b/bin/debug-trace-server/tests/performance_test.rs index 46569404..76701f9c 100644 --- a/bin/debug-trace-server/tests/performance_test.rs +++ b/bin/debug-trace-server/tests/performance_test.rs @@ -25,7 +25,7 @@ use alloy_primitives::{Bytes, TxKind, U256}; use alloy_signer_local::PrivateKeySigner; use reqwest::blocking::Client; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::{Value, json}; // --------------------------------------------------------------------------- // Test Infrastructure diff --git a/bin/debug-trace-server/tests/prune_test.rs b/bin/debug-trace-server/tests/prune_test.rs index 16728035..67b2937e 100644 --- a/bin/debug-trace-server/tests/prune_test.rs +++ b/bin/debug-trace-server/tests/prune_test.rs @@ -10,8 +10,8 @@ //! ``` use alloy_primitives::B256; +use stateless_core::ValidatorDB; use tempfile::TempDir; -use validator_core::ValidatorDB; /// Test that prune_history removes blocks older than the specified block number. #[test] diff --git a/bin/debug-trace-server/tests/timing_header_test.rs b/bin/debug-trace-server/tests/timing_header_test.rs index 0c87b9be..7a110f1f 100644 --- a/bin/debug-trace-server/tests/timing_header_test.rs +++ b/bin/debug-trace-server/tests/timing_header_test.rs @@ -19,7 +19,7 @@ use std::{env, time::Duration}; use reqwest::blocking::Client; use serde::Serialize; -use serde_json::{json, Value}; +use serde_json::{Value, json}; /// JSON-RPC request structure. #[derive(Serialize)] diff --git a/bin/stateless-validator/Cargo.toml b/bin/stateless-validator/Cargo.toml index d5d510af..e8f634b6 100644 --- a/bin/stateless-validator/Cargo.toml +++ b/bin/stateless-validator/Cargo.toml @@ -37,10 +37,10 @@ salt.workspace = true serde.workspace = true serde_json.workspace = true stateless-common = { path = "../../crates/stateless-common" } +stateless-core = { path = "../../crates/stateless-core" } tokio.workspace = true tokio-util.workspace = true tracing.workspace = true -validator-core = { path = "../../crates/validator-core" } [dev-dependencies] base64.workspace = true @@ -51,4 +51,4 @@ tracing-subscriber.workspace = true zstd.workspace = true [features] -test-bucket-resize = ["salt/test-bucket-resize", "validator-core/test-bucket-resize"] +test-bucket-resize = ["salt/test-bucket-resize", "stateless-core/test-bucket-resize"] diff --git a/bin/stateless-validator/src/main.rs b/bin/stateless-validator/src/main.rs index 8c110233..bb910b43 100644 --- a/bin/stateless-validator/src/main.rs +++ b/bin/stateless-validator/src/main.rs @@ -15,16 +15,16 @@ use futures::future; use revm::{primitives::KECCAK_EMPTY, state::Bytecode}; use salt::SaltWitness; use stateless_common::logging::{LogArgs, migrate_legacy_env_vars}; -use tokio::{signal, task, task::JoinHandle}; -use tokio_util::sync::CancellationToken; -use tracing::{debug, error, info, warn}; -use validator_core::{ +use stateless_core::{ ChainSyncConfig, FetchResult, RpcClient, RpcClientConfig, ValidatorDB, chain_spec::ChainSpec, data_types::{PlainKey, PlainValue}, executor::{ValidationResult, validate_block}, remote_chain_tracker, }; +use tokio::{signal, task, task::JoinHandle}; +use tokio_util::sync::CancellationToken; +use tracing::{debug, error, info, warn}; mod metrics; @@ -810,8 +810,8 @@ mod tests { }; use op_alloy_rpc_types::Transaction; use serde::{Deserialize, Serialize, de::DeserializeOwned}; + use stateless_core::{rpc_client::WitnessRequestKeys, withdrawals::MptWitness}; use tracing_subscriber::EnvFilter; - use validator_core::{rpc_client::WitnessRequestKeys, withdrawals::MptWitness}; use super::*; diff --git a/bin/stateless-validator/src/metrics.rs b/bin/stateless-validator/src/metrics.rs index 26f44653..82aaa166 100644 --- a/bin/stateless-validator/src/metrics.rs +++ b/bin/stateless-validator/src/metrics.rs @@ -9,16 +9,14 @@ use alloy_primitives::B256; use eyre::Result; use metrics::{counter, describe_counter, describe_gauge, describe_histogram, gauge, histogram}; use metrics_exporter_prometheus::PrometheusBuilder; +pub use stateless_common::DEFAULT_METRICS_PORT; +pub use stateless_core::RpcMethod; +use stateless_core::RpcMetrics; use tracing::info; -pub use validator_core::RpcMethod; -use validator_core::RpcMetrics; - -/// Default metrics port. -pub const DEFAULT_METRICS_PORT: u16 = 9090; /// Metrics callback implementation for RPC client. /// -/// This struct implements the `RpcMetrics` trait from validator-core, +/// This struct implements the `RpcMetrics` trait from stateless-core, /// allowing the RPC client to report metrics through the stateless validator's /// Prometheus metrics system. pub struct ValidatorMetrics; diff --git a/crates/stateless-common/src/lib.rs b/crates/stateless-common/src/lib.rs index 31348d2f..defa9816 100644 --- a/crates/stateless-common/src/lib.rs +++ b/crates/stateless-common/src/lib.rs @@ -1 +1,4 @@ pub mod logging; + +/// Default port for Prometheus metrics HTTP endpoint. +pub const DEFAULT_METRICS_PORT: u16 = 9090; diff --git a/crates/stateless-common/src/logging.rs b/crates/stateless-common/src/logging.rs index 7c8c8488..5623da7a 100644 --- a/crates/stateless-common/src/logging.rs +++ b/crates/stateless-common/src/logging.rs @@ -121,7 +121,7 @@ pub struct LogArgs { /// workspace crates while defaulting everything else to `warn`. fn build_env_filter(filter: &str) -> Result { Ok(EnvFilter::new("warn") - .add_directive(format!("validator_core={filter}").parse()?) + .add_directive(format!("stateless_core={filter}").parse()?) .add_directive(format!("stateless_validator={filter}").parse()?) .add_directive(format!("stateless_common={filter}").parse()?) .add_directive(format!("debug_trace_server={filter}").parse()?)) diff --git a/crates/validator-core/Cargo.toml b/crates/stateless-core/Cargo.toml similarity index 98% rename from crates/validator-core/Cargo.toml rename to crates/stateless-core/Cargo.toml index cfaf6d5e..0b8f394c 100644 --- a/crates/validator-core/Cargo.toml +++ b/crates/stateless-core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "validator-core" +name = "stateless-core" version.workspace = true edition.workspace = true rust-version.workspace = true diff --git a/crates/validator-core/src/chain_spec.rs b/crates/stateless-core/src/chain_spec.rs similarity index 100% rename from crates/validator-core/src/chain_spec.rs rename to crates/stateless-core/src/chain_spec.rs diff --git a/crates/validator-core/src/chain_sync.rs b/crates/stateless-core/src/chain_sync.rs similarity index 100% rename from crates/validator-core/src/chain_sync.rs rename to crates/stateless-core/src/chain_sync.rs diff --git a/crates/validator-core/src/data_types.rs b/crates/stateless-core/src/data_types.rs similarity index 100% rename from crates/validator-core/src/data_types.rs rename to crates/stateless-core/src/data_types.rs diff --git a/crates/validator-core/src/database.rs b/crates/stateless-core/src/database.rs similarity index 100% rename from crates/validator-core/src/database.rs rename to crates/stateless-core/src/database.rs diff --git a/crates/validator-core/src/executor.rs b/crates/stateless-core/src/executor.rs similarity index 100% rename from crates/validator-core/src/executor.rs rename to crates/stateless-core/src/executor.rs diff --git a/crates/validator-core/src/lib.rs b/crates/stateless-core/src/lib.rs similarity index 100% rename from crates/validator-core/src/lib.rs rename to crates/stateless-core/src/lib.rs diff --git a/crates/validator-core/src/light_witness.rs b/crates/stateless-core/src/light_witness.rs similarity index 100% rename from crates/validator-core/src/light_witness.rs rename to crates/stateless-core/src/light_witness.rs diff --git a/crates/validator-core/src/rpc_client.rs b/crates/stateless-core/src/rpc_client.rs similarity index 100% rename from crates/validator-core/src/rpc_client.rs rename to crates/stateless-core/src/rpc_client.rs diff --git a/crates/validator-core/src/tracing_executor.rs b/crates/stateless-core/src/tracing_executor.rs similarity index 100% rename from crates/validator-core/src/tracing_executor.rs rename to crates/stateless-core/src/tracing_executor.rs diff --git a/crates/validator-core/src/validator_db.rs b/crates/stateless-core/src/validator_db.rs similarity index 100% rename from crates/validator-core/src/validator_db.rs rename to crates/stateless-core/src/validator_db.rs diff --git a/crates/validator-core/src/withdrawals.rs b/crates/stateless-core/src/withdrawals.rs similarity index 100% rename from crates/validator-core/src/withdrawals.rs rename to crates/stateless-core/src/withdrawals.rs diff --git a/scripts/coverage_stateless_core.sh b/scripts/coverage_stateless_core.sh new file mode 100755 index 00000000..4188c66f --- /dev/null +++ b/scripts/coverage_stateless_core.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +COV_DIR="${COV_DIR:-$ROOT_DIR/target/coverage/stateless-core}" +HTML_INDEX="$COV_DIR/html/index.html" +LCOV_PATH="$COV_DIR/lcov.info" +REPORT="$COV_DIR/report.txt" +IGNORE_FILENAME_REGEX="${IGNORE_FILENAME_REGEX:-(/tests/|/benches/|/examples/|/\.cargo/registry/|/rustc/)}" + +if ! cargo llvm-cov --version >/dev/null 2>&1; then + echo "cargo-llvm-cov is required. Install it with 'cargo install cargo-llvm-cov --locked'." >&2 + exit 1 +fi + +cd "$ROOT_DIR" +rm -rf "$COV_DIR" +mkdir -p "$COV_DIR" + +cargo llvm-cov clean --workspace + +cargo llvm-cov \ + --locked \ + --package stateless-core \ + --all-features \ + --lib \ + --tests \ + --no-fail-fast \ + --no-report + +cargo llvm-cov report \ + --package stateless-core \ + --ignore-filename-regex "$IGNORE_FILENAME_REGEX" \ + --lcov \ + --output-path "$LCOV_PATH" + +cargo llvm-cov report \ + --package stateless-core \ + --ignore-filename-regex "$IGNORE_FILENAME_REGEX" \ + --html \ + --output-dir "$COV_DIR" + +cargo llvm-cov report \ + --package stateless-core \ + --ignore-filename-regex "$IGNORE_FILENAME_REGEX" > "$REPORT" + +echo +echo "Coverage artifacts written to $COV_DIR" +echo "Open $HTML_INDEX to inspect the HTML report." +echo "Upload $LCOV_PATH to Codecov to annotate pull requests." From 6cdb09e046f3ac9b328c761de4ce5985d8aaf9cb Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Tue, 24 Mar 2026 10:02:33 +0800 Subject: [PATCH 2/3] fix clippy --- .../tests/block_tag_test.rs | 42 ++++----- .../tests/cache_metrics_test.rs | 81 +++++++---------- .../tests/consistency_test.rs | 68 ++++++-------- .../tests/performance_test.rs | 90 +++++++++---------- 4 files changed, 118 insertions(+), 163 deletions(-) diff --git a/bin/debug-trace-server/tests/block_tag_test.rs b/bin/debug-trace-server/tests/block_tag_test.rs index cbac651b..997a8000 100644 --- a/bin/debug-trace-server/tests/block_tag_test.rs +++ b/bin/debug-trace-server/tests/block_tag_test.rs @@ -132,14 +132,12 @@ fn find_block_with_txs(client: &RpcClient) -> Option<(u64, String)> { let resp = client .call("eth_getBlockByNumber", json!([format!("0x{:x}", block_num), false])) .ok()?; - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if !txs.is_empty() { - let hash = - block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); - return Some((block_num, hash)); - } - } + if let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + !txs.is_empty() + { + let hash = block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); + return Some((block_num, hash)); } } None @@ -657,14 +655,12 @@ fn test_send_tx_and_trace() { for _ in 0..120 { std::thread::sleep(Duration::from_millis(500)); let resp = mega_reth.call("eth_getTransactionReceipt", json!([&tx_hash])).unwrap(); - if let Some(receipt) = resp.result { - if !receipt.is_null() { - if let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) { - block_number = - Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); - break; - } - } + if let Some(receipt) = resp.result && + !receipt.is_null() && + let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) + { + block_number = Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); + break; } } @@ -822,14 +818,12 @@ fn test_deploy_contract_and_trace() { for _ in 0..120 { std::thread::sleep(Duration::from_millis(500)); let resp = mega_reth.call("eth_getTransactionReceipt", json!([&tx_hash])).unwrap(); - if let Some(receipt) = resp.result { - if !receipt.is_null() { - if let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) { - block_number = - Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); - break; - } - } + if let Some(receipt) = resp.result && + !receipt.is_null() && + let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) + { + block_number = Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); + break; } } diff --git a/bin/debug-trace-server/tests/cache_metrics_test.rs b/bin/debug-trace-server/tests/cache_metrics_test.rs index 7bf53dd5..215e4aa5 100644 --- a/bin/debug-trace-server/tests/cache_metrics_test.rs +++ b/bin/debug-trace-server/tests/cache_metrics_test.rs @@ -181,14 +181,12 @@ fn get_recent_block_with_txs(client: &RpcClient) -> Result<(u64, String), String let resp = client.call("eth_getBlockByNumber", json!([format!("0x{:x}", block_num), false]))?; - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if !txs.is_empty() { - let hash = - block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); - return Ok((block_num, hash)); - } - } + if let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + !txs.is_empty() + { + let hash = block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); + return Ok((block_num, hash)); } } @@ -478,47 +476,32 @@ fn test_cache_multiple_blocks() { // Check if block has transactions let block_resp = mega_reth.call("eth_getBlockByNumber", json!([&block_hex, false])).ok(); - if let Some(resp) = block_resp { - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if !txs.is_empty() { - println!("\n Block {} ({} txs):", block_num, txs.len()); - - // First request (miss) - let stats_before = - get_cache_stats(&debug_server).expect("Failed to get cache stats"); - - let _ = debug_server.call( - "debug_traceBlockByNumber", - json!([&block_hex, {"tracer": "callTracer"}]), - ); - - let stats_after = - get_cache_stats(&debug_server).expect("Failed to get cache stats"); - - println!( - " First request: misses {} -> {}", - stats_before.misses, stats_after.misses - ); - - // Second request (hit) - let _ = debug_server.call( - "debug_traceBlockByNumber", - json!([&block_hex, {"tracer": "callTracer"}]), - ); - - let stats_final = - get_cache_stats(&debug_server).expect("Failed to get cache stats"); - - println!( - " Second request: hits {} -> {}", - stats_after.hits, stats_final.hits - ); - - tested_blocks += 1; - } - } - } + if let Some(resp) = block_resp && + let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + !txs.is_empty() + { + println!("\n Block {} ({} txs):", block_num, txs.len()); + + // First request (miss) + let stats_before = get_cache_stats(&debug_server).expect("Failed to get cache stats"); + + let _ = debug_server + .call("debug_traceBlockByNumber", json!([&block_hex, {"tracer": "callTracer"}])); + + let stats_after = get_cache_stats(&debug_server).expect("Failed to get cache stats"); + + println!(" First request: misses {} -> {}", stats_before.misses, stats_after.misses); + + // Second request (hit) + let _ = debug_server + .call("debug_traceBlockByNumber", json!([&block_hex, {"tracer": "callTracer"}])); + + let stats_final = get_cache_stats(&debug_server).expect("Failed to get cache stats"); + + println!(" Second request: hits {} -> {}", stats_after.hits, stats_final.hits); + + tested_blocks += 1; } } diff --git a/bin/debug-trace-server/tests/consistency_test.rs b/bin/debug-trace-server/tests/consistency_test.rs index 698a06ba..794f49a1 100644 --- a/bin/debug-trace-server/tests/consistency_test.rs +++ b/bin/debug-trace-server/tests/consistency_test.rs @@ -503,21 +503,19 @@ fn get_blocks_with_transactions( let resp = client.call("eth_getBlockByNumber", json!([format!("0x{:x}", block_num), true]))?; - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if !txs.is_empty() { - let hash = - block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); - - let tx_hashes: Vec = txs - .iter() - .filter_map(|tx| tx.get("hash").and_then(|h| h.as_str()).map(String::from)) - .collect(); - - if !tx_hashes.is_empty() { - blocks.push(BlockInfo { number: block_num, hash, tx_hashes }); - } - } + if let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + !txs.is_empty() + { + let hash = block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); + + let tx_hashes: Vec = txs + .iter() + .filter_map(|tx| tx.get("hash").and_then(|h| h.as_str()).map(String::from)) + .collect(); + + if !tx_hashes.is_empty() { + blocks.push(BlockInfo { number: block_num, hash, tx_hashes }); } } } @@ -1162,32 +1160,20 @@ fn test_large_block() { .call("eth_getBlockByNumber", json!([format!("0x{:x}", block_num), true])) .ok(); - if let Some(resp) = resp { - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if txs.len() >= min_tx_count { - let hash = block - .get("hash") - .and_then(|h| h.as_str()) - .unwrap_or_default() - .to_string(); - let tx_hashes: Vec = txs - .iter() - .filter_map(|tx| { - tx.get("hash").and_then(|h| h.as_str()).map(String::from) - }) - .collect(); - - println!( - " Found block {} with {} transactions", - block_num, - tx_hashes.len() - ); - large_block = Some(BlockInfo { number: block_num, hash, tx_hashes }); - break; - } - } - } + if let Some(resp) = resp && + let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + txs.len() >= min_tx_count + { + let hash = block.get("hash").and_then(|h| h.as_str()).unwrap_or_default().to_string(); + let tx_hashes: Vec = txs + .iter() + .filter_map(|tx| tx.get("hash").and_then(|h| h.as_str()).map(String::from)) + .collect(); + + println!(" Found block {} with {} transactions", block_num, tx_hashes.len()); + large_block = Some(BlockInfo { number: block_num, hash, tx_hashes }); + break; } } diff --git a/bin/debug-trace-server/tests/performance_test.rs b/bin/debug-trace-server/tests/performance_test.rs index 76701f9c..e73d01fb 100644 --- a/bin/debug-trace-server/tests/performance_test.rs +++ b/bin/debug-trace-server/tests/performance_test.rs @@ -203,15 +203,13 @@ fn test_tracer_performance_cache_hit() { for bn in (1..latest.saturating_sub(5)).rev() { let resp = mega_reth.call("eth_getBlockByNumber", json!([format!("0x{:x}", bn), false])).ok(); - if let Some(resp) = resp { - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if !txs.is_empty() { - test_block = bn; - break; - } - } - } + if let Some(resp) = resp && + let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + !txs.is_empty() + { + test_block = bn; + break; } } @@ -354,14 +352,12 @@ fn test_tracer_performance_fresh_block() { for _ in 0..60 { std::thread::sleep(Duration::from_millis(500)); let resp = mega_reth.call("eth_getTransactionReceipt", json!([&tx_hash])).unwrap(); - if let Some(receipt) = resp.result { - if !receipt.is_null() { - if let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) { - block_number = - Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); - break; - } - } + if let Some(receipt) = resp.result && + !receipt.is_null() && + let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) + { + block_number = Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); + break; } } @@ -431,14 +427,12 @@ fn test_tracer_performance_cold_request() { } let resp = mega_reth.call("eth_getBlockByNumber", json!([format!("0x{:x}", bn), false])).ok(); - if let Some(resp) = resp { - if let Some(block) = resp.result { - if let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) { - if !txs.is_empty() { - test_blocks.push(bn); - } - } - } + if let Some(resp) = resp && + let Some(block) = resp.result && + let Some(txs) = block.get("transactions").and_then(|t| t.as_array()) && + !txs.is_empty() + { + test_blocks.push(bn); } } @@ -566,14 +560,12 @@ fn test_tracer_performance_comparison() { for _ in 0..60 { std::thread::sleep(Duration::from_millis(500)); let resp = mega_reth.call("eth_getTransactionReceipt", json!([&tx_hash])).unwrap(); - if let Some(receipt) = resp.result { - if !receipt.is_null() { - if let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) { - block_number = - Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); - break; - } - } + if let Some(receipt) = resp.result && + !receipt.is_null() && + let Some(bn) = receipt.get("blockNumber").and_then(|v| v.as_str()) + { + block_number = Some(u64::from_str_radix(bn.trim_start_matches("0x"), 16).unwrap()); + break; } } @@ -634,18 +626,18 @@ fn test_tracer_performance_comparison() { println!("{}", "=".repeat(80)); let resp = dts.call("debug_getCacheStatus", json!([])).unwrap(); - if let Some(result) = resp.result { - if let Some(cache) = result.get("responseCache") { - println!(" Entries: {}", cache.get("entryCount").unwrap_or(&json!("?"))); - println!( - " Total Bytes: {} ({} MB)", - cache.get("totalBytes").unwrap_or(&json!("?")), - cache.get("totalBytesMB").unwrap_or(&json!("?")) - ); - println!(" Hits: {}", cache.get("hits").unwrap_or(&json!("?"))); - println!(" Misses: {}", cache.get("misses").unwrap_or(&json!("?"))); - println!(" Hit Rate: {}", cache.get("hitRate").unwrap_or(&json!("?"))); - } + if let Some(result) = resp.result && + let Some(cache) = result.get("responseCache") + { + println!(" Entries: {}", cache.get("entryCount").unwrap_or(&json!("?"))); + println!( + " Total Bytes: {} ({} MB)", + cache.get("totalBytes").unwrap_or(&json!("?")), + cache.get("totalBytesMB").unwrap_or(&json!("?")) + ); + println!(" Hits: {}", cache.get("hits").unwrap_or(&json!("?"))); + println!(" Misses: {}", cache.get("misses").unwrap_or(&json!("?"))); + println!(" Hit Rate: {}", cache.get("hitRate").unwrap_or(&json!("?"))); } println!("\n{}", "=".repeat(80)); @@ -716,10 +708,10 @@ fn test_trace_transaction_performance() { for _ in 0..60 { std::thread::sleep(Duration::from_millis(500)); let resp = mega_reth.call("eth_getTransactionReceipt", json!([&tx_hash])).unwrap(); - if let Some(receipt) = resp.result { - if !receipt.is_null() { - break; - } + if let Some(receipt) = resp.result && + !receipt.is_null() + { + break; } } From 46d1e68f0dd2ebfba694784f72a3b179bbfd379f Mon Sep 17 00:00:00 2001 From: "liquan.eth" Date: Tue, 24 Mar 2026 10:05:48 +0800 Subject: [PATCH 3/3] fix comments --- bin/debug-trace-server/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/debug-trace-server/Cargo.toml b/bin/debug-trace-server/Cargo.toml index e2975a90..596a53a0 100644 --- a/bin/debug-trace-server/Cargo.toml +++ b/bin/debug-trace-server/Cargo.toml @@ -48,7 +48,7 @@ tower = "0.4" # Logging and metrics tracing.workspace = true -# Reuse validator-core +# Reuse stateless-core stateless-common = { path = "../../crates/stateless-common" } stateless-core = { path = "../../crates/stateless-core" }