Skip to main content

Requirements

The examples in this guide call the debug JSON-RPC endpoints directly with curl — no SDK or additional libraries are required. Optionally install jq to pretty-print the JSON responses:
Debug tracing is your primary tool for understanding EVM transaction execution on Sei. This comprehensive system allows you to analyze transaction flow, optimize gas usage, debug smart contract interactions, and troubleshoot production issues.

What You Can Trace

Transaction Execution

  • Step-by-step opcode execution
  • Contract call hierarchy
  • Gas consumption breakdown
  • State changes and storage access

Contract Interactions

  • Cross-contract calls and returns
  • Event emission analysis
  • Precompile usage tracking
  • External library calls

Performance Analysis

  • Gas optimization opportunities
  • Bottleneck identification
  • Cache hit/miss patterns
  • State access efficiency

Security Analysis

  • Suspicious operation detection
  • Reentrancy pattern analysis
  • Access control verification
  • Vulnerability scanning

Available Tracing Methods

Transaction Analysis Example

Tracing an ERC-20 transfer transaction:
Response:

Debugging Failed Transactions

Steps to analyze and resolve transaction failures:

Step 1: Identify the Problem

Step 2: Trace the Execution

Response

Step 3: Fix and Test

Common Debugging Scenarios

Transaction Reverted

Problem: Transaction failed with revert Solution: Use callTracer to find the exact revert reason

Out of Gas

Problem: Transaction ran out of gas Solution: Use gas analysis tracer to optimize gas usage

Unexpected Behavior

Problem: Transaction succeeded but wrong result Solution: Use opcode tracer for step-by-step analysis

Slow Performance

Problem: Transaction uses too much gas Solution: Use state access tracer to find inefficiencies

Quick Reference

Essential Commands

Common Tracers

  • callTracer: Contract call hierarchy
  • opcodeTracer: Opcode-level execution
  • Custom JS: Custom analysis logic

Pre-Baked Trace Cache

RPC nodes can optionally pre-compute and cache debug_trace* results in the background so that trace requests are served from a local on-disk cache instead of re-executing the block live on every call. This is an opt-in feature configured through new [evm] fields in app.toml and is recommended for RPC nodes only. When enabled, a background worker re-executes each committed block with the configured tracers and stores the results in a Pebble database at <home>/data/trace_db. The following methods serve from this cache on hit, and otherwise fall through to live re-execution:
  • debug_traceTransaction
  • debug_traceBlockByNumber and debug_traceBlockByHash

When the cache is used

A request is only served from cache when trace baking is enabled and the request uses a bakeable tracer configuration:
  • The tracer is one of callTracer, prestateTracer, or flatCallTracer.
  • No custom tracerConfig is supplied. A per-call tracerConfig (for example {"withLog": true}) is not part of the cache key, so any custom tracer config makes the request un-bakeable and it falls through to live re-execution.
Requests that use the struct logger (no tracer), a JavaScript tracer, or any other named tracer are always executed live.

Configuration

Trace baking is controlled by these [evm] fields in app.toml:
Enabling trace baking adds a persistent on-disk store at <home>/data/trace_db and increases disk usage. The store’s write-ahead log is flushed when the node shuts down cleanly.

*ExcludeTraceFail filtering semantics

The *ExcludeTraceFail endpoints (sei_getTransactionReceiptExcludeTraceFail, sei_getBlockByNumberExcludeTraceFail, and sei_getBlockByHashExcludeTraceFail) filter out transactions whose trace would be empty or meaningless — specifically, transactions that were included in a block but never actually executed in the VM. These are deprecated legacy endpoints and are disabled by default: each method must be enabled through enabled_legacy_sei_apis in the [evm] section of app.toml. The filter keys off the receipt shape — any receipt with EffectiveGasPrice == 0 && GasUsed == 0, plus chain-generated synthetics — which excludes three classes:
  • Ante-deferred stub transactions: txs that passed the nonce check but failed a later ante step (for example insufficient funds or insufficient fee) and so never reached the VM. The chain writes a stub receipt for these with both fields unset.
  • Nonce-bumping state-transition failures: txs that fail inside go-ethereum’s Execute() before any opcode runs (for example an EIP-7623 floor-data-gas shortfall). Their synthetic EndBlock receipt carries the same EffectiveGasPrice == 0 && GasUsed == 0 shape, so it is filtered identically.
  • Chain-generated synthetic transactions: txs with the internal ShellEVMTxType, which have no real EVM execution.
Everything that executed opcodes in the VM is included, even if it failed. Reverted and out-of-gas (OOG) transactions have Status == 0 but GasUsed > 0 (intrinsic gas at minimum) and, on chains with a positive minimum gas price, EffectiveGasPrice > 0, and produce a real trace (the REVERT or OOG condition simply appears inside that trace), so they are returned rather than filtered out.
This filter applies to the block endpoints (sei_getBlockByNumberExcludeTraceFail and sei_getBlockByHashExcludeTraceFail, plus their sei2_ equivalents) and the receipt endpoint (sei_getTransactionReceiptExcludeTraceFail): all of them drop these ante-deferred stub transactions. The former sei_traceBlockByNumberExcludeTraceFail and sei_traceBlockByHashExcludeTraceFail endpoints were removed in v6.6.0 — use debug_traceBlockByNumber or debug_traceBlockByHash for block tracing. The regular eth_getBlockBy* endpoints continue to include them, so a tx that appears in a normal block response may be absent from the *ExcludeTraceFail variant. The filter checks the underlying receipt shape (EffectiveGasPrice and GasUsed) rather than any tracer-reported error field.

Next Steps

  1. JavaScript Tracers - Custom analysis scripts
  2. Troubleshooting - Common issues and solutions
Start with callTracer for general debugging, then use specialized tracers for specific analysis needs.