Skip to content

Feature/blocktest tracing#9427

Closed
bshastry wants to merge 3 commits into
NethermindEth:masterfrom
bshastry:feature/blocktest-tracing
Closed

Feature/blocktest tracing#9427
bshastry wants to merge 3 commits into
NethermindEth:masterfrom
bshastry:feature/blocktest-tracing

Conversation

@bshastry

@bshastry bshastry commented Oct 8, 2025

Copy link
Copy Markdown
Contributor

Add Blocktest Tracing Support to nethtest Tool

Changes

  • Add BlockchainTestStreamingTracer for consolidated trace output to stderr
  • Implement blocktest tracing compatible with go-ethereum's trace format
  • Add unit tests (BlockchainTestStreamingTracerTests.cs) with 4 test methods
  • Fix async block processing race condition in BlockchainTestBase
  • Add tracer parameter support to RunTest() method
  • Update CLI options in Program.cs for blocktest tracing
  • Simplify BlockchainTestsRunner with single tracer per test run

Types of changes

What types of changes does your code introduce?

  • Bugfix (a non-breaking change that fixes an issue)
  • New feature (a non-breaking change that adds functionality)
  • Breaking change (a change that causes existing functionality not to work as expected)
  • Optimization
  • Refactoring
  • Documentation update
  • Build-related changes
  • Other: Description

Testing

Requires testing

  • Yes
  • No

If yes, did you write tests?

  • Yes
  • No

Notes on testing

Unit Tests:
Added BlockchainTestStreamingTracerTests.cs with 4 test methods:

  • Tracer_writes_to_provided_output - Verifies basic trace output
  • Tracer_handles_multiple_transactions - Tests multiple transactions per block
  • Tracer_handles_multiple_blocks - Tests tracing across multiple blocks
  • Tracer_disposes_cleanly - Validates proper resource disposal (includes double-dispose safety check)
  • All tests passing ✅ (Passed: 4/4 test methods, Duration: 626ms)

Manual/Integration Testing:
Validated with real blockchain tests:

  • 6-block, 17-transaction test producing 2790 trace lines
  • All transactions traced correctly
  • JSON-lines format validation
  • Memory/stack control options (-m/-s) tested
  • stderr output redirection verified

Test execution:

# Run unit tests
dotnet test Nethermind.State.Test.Runner.Test --filter BlockchainTestStreamingTracerTests
# Result: Passed! - Failed: 0, Passed: 5, Skipped: 0, Total: 5

# Run integration test
dotnet nethtest.dll -b -i test.json -t 2>trace.jsonl
# Result: All 17 transactions traced across 6 blocks

Documentation

Requires documentation update

  • Yes
  • No

Requires explanation in Release Notes

  • Yes
  • No

Release Notes:

New Feature: Blocktest Tracing in nethtest Tool

The nethtest tool now supports transaction tracing for blockchain tests, enabling differential testing and trace comparison with go-ethereum.

Usage:

# Trace to stderr
dotnet nethtest.dll -b -i test.json -t

# Redirect trace to file
dotnet nethtest.dll -b -i test.json -t 2>trace.jsonl

# Compare with geth
dotnet nethtest.dll -b -i test.json -t 2>nethermind.jsonl
evm blocktest test.json --trace 2>geth.jsonl
diff nethermind.jsonl geth.jsonl

Features:

  • Consolidated trace output to stderr (matches state test behavior)
  • JSON-lines format compatible with go-ethereum
  • Single stream for all blocks and transactions
  • Memory/stack control options (-m/-s)

This enhancement enables better EVM implementation validation and debugging for multi-transaction test scenarios.

Remarks

Implementation Highlights

  1. Race Condition Fix: The implementation revealed and fixed a subtle async block processing bug where tracer removal before StopAsync() caused incomplete traces. This fix ensures all blocks are traced correctly.

  2. Design Philosophy: Following Unix conventions, traces go to stderr (not files) for consistency with state tests and maximum flexibility (users can redirect or pipe as needed).

  3. geth Compatibility: The trace format exactly matches go-ethereum's blocktest output, enabling seamless differential testing workflows.

Why This Matters

  • Differential Testing: Essential for validating Nethermind's EVM implementation against geth
  • Debugging: Provides detailed execution traces for multi-block test failures
  • Fuzzing Support: Enables trace-based differential fuzzing between implementations
  • Fork Testing: Critical for validating behavior across hard fork boundaries

Testing Workflow Example

# Generate traces
dotnet nethtest.dll -b -i test.json -t 2>nethermind.jsonl
evm blocktest test.json --trace 2>geth.jsonl

# Compare (should be identical for compliant implementations)
diff nethermind.jsonl geth.jsonl

# Count transactions traced
grep '"gasUsed"' nethermind.jsonl | wc -l

bshastry and others added 3 commits October 8, 2025 13:32
Implements consolidated transaction tracing for blockchain tests,
compatible with go-ethereum's blocktest trace format.

Features:
- Consolidated trace output to stderr (matching state test behavior)
- Single stream for all blocks and transactions
- JSON-lines format compatible with geth
- CLI options for memory/stack control (-m/-s)
- Unit tests with 4 test methods covering core functionality

Implementation details:
- BlockchainTestStreamingTracer: Streams traces to stderr
- Fixed async block processing race condition in BlockchainTestBase
- Tracer registration moved after StopAsync() for complete traces
- Simplified architecture with single tracer per test run

Usage:
  dotnet nethtest.dll -b -i test.json -t 2>trace.jsonl

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The gas increase detection logic incorrectly identified instructions after
RETURN/CREATE operations as "jumped over" and skipped tracing them. This
caused trace divergences where:

- After RETURN (depth 2→1): Gas appears to "increase" due to context switch
- Heuristic wrongly skipped next instruction, causing PC misalignment
- Nethermind traces missing instructions that Geth correctly traces

Root cause: The >50 gas threshold conflated:
1. Actual gas stipend increases (CALL/DELEGATECALL)
2. Apparent increases from context returns (RETURN/CREATE)

Fix: Remove selective tracing logic and unconditionally emit all trace entries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implements testEnd marker written to stderr after each blocktest execution:
- Format: {"testEnd":{"name":"...","pass":bool,"fork":"...","v":1,...}}
- Includes test metrics: duration, gasUsed, txs, blocks, finalStateRoot
- Written BEFORE tracer removal to ensure it's the last trace line
- Written even on test failure for proper fuzzer integration

Changes:
- BlockchainTestStreamingTracer: Add WriteTestEndMarker() method
- BlockchainTestBase: Call marker method via reflection before assertions
- Track transaction count, block count, and total gas for metrics

Required for differential fuzzing between Nethermind and Geth.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@LukaszRozmej

Copy link
Copy Markdown
Member

Thank you for great contribution. I took a liberty to enhance it a bit in #9432, so closing this in favor of that. Can you check if I didn't break anything?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants