This document explains how to run Ethereum reference tests in Besu and how to enable JSON tracing during test and block execution. This is useful for debugging EVM behavior, inspecting opcode execution, and verifying correctness against official test vectors.
To run the Ethereum reference tests included in the Besu codebase, use the following Gradle task:
./gradlew referenceTestsThis will execute the available test suites (such as GeneralStateTests) and validate Besu's EVM behavior.
Note:
- Out-of-memory (OOM) errors are common due to the size and number of tests. You may need to increase the heap size using
-Xmx(e.g.,./gradlew referenceTests -Dorg.gradle.jvmargs="-Xmx8g")
Besu supports detailed opcode-level JSON tracing. You can enable it using either a JVM system property or an environment variable.
-Dbesu.debug.traceBlocks=trueexport BESU_TRACE_BLOCKS=trueThis enables a fallback implementation of BlockAwareOperationTracer if no plugin is configured. The default tracer used is BlockAwareJsonTracer.
JSON trace output does not appear in the console. To view it, open the associated Gradle test report (usually located in build/reports/tests/test/index.html) and find the specific test case output.
When enabled, tracing includes:
- Opcode execution and names
- Stack state
- Gas remaining and gas cost
- Memory size
- Precompile execution
- Contract creation and call frames
- Transaction lifecycle events (start, prepare, end)
- Exceptional halts
Each traced operation emits structured JSON data representing the EVM state at that point.
The tracer prints a complete JSON trace of each block’s execution to standard output at the end of the block:
==== JSON Trace for Block <BLOCK_NUMBER> (<BLOCK_HASH>) ====
<trace entries>
Example:
{
"pc": 0,
"op": "0x60",
"opName": "PUSH1",
"gas": 999999,
"gasCost": 3,
"stack": [],
"memSize": 0,
"depth": 1,
"refund": 0
}The tracer is implemented in:
org.hyperledger.besu.ethereum.mainnet.BlockAwareJsonTracer
It uses a StringWriter and a StandardJsonTracer to collect and format execution traces. Output is flushed during the traceEndBlock(...) callback.
The BlockAwareJsonTracer is enabled automatically when no plugin provides a custom tracer and one of the tracing flags is set:
if (Boolean.getBoolean("besu.debug.traceBlocks")
|| "true".equalsIgnoreCase(System.getenv("BESU_TRACE_BLOCKS"))) {
return new BlockAwareJsonTracer();
}- Tracing is for debugging purposes only and should not be enabled in production environments.
- Trace output can become large, especially for blocks with many transactions.
- Tracing does not affect EVM execution semantics.