|
| 1 | +--- |
| 2 | +description: Self-host debug_* and trace_* RPC methods for MegaETH by replaying blocks with SALT witnesses — no archive node required. |
| 3 | +--- |
| 4 | + |
| 5 | +# Debug trace server |
| 6 | + |
| 7 | +The **debug-trace-server** provides `debug_*` and `trace_*` JSON-RPC methods for MegaETH. |
| 8 | +It re-executes blocks against [SALT](https://github.com/megaeth-labs/salt) witness data instead of a full state database, so it needs no archive node and runs on commodity hardware. |
| 9 | + |
| 10 | +Point it at any MegaETH RPC endpoint, and it can trace any block or transaction that endpoint serves. |
| 11 | + |
| 12 | +## When to use this |
| 13 | + |
| 14 | +Run your own debug-trace-server when you need a **self-hosted** trace endpoint — for example, to power a block explorer backend, an indexer, or high-volume trace queries that would exceed public RPC rate limits. |
| 15 | + |
| 16 | +If you only need occasional traces, the public MegaETH RPC already serves `debug_traceTransaction` and related methods directly — see [Debugging Transactions](../dev/send-tx/debugging.md). |
| 17 | + |
| 18 | +## Installation |
| 19 | + |
| 20 | +The server is built from source alongside the [stateless validator](stateless-validation.md). |
| 21 | + |
| 22 | +```bash |
| 23 | +git clone https://github.com/megaeth-labs/stateless-validator.git |
| 24 | +cd stateless-validator |
| 25 | +cargo build --release --bin debug-trace-server |
| 26 | +``` |
| 27 | + |
| 28 | +The binary is at `./target/release/debug-trace-server`. |
| 29 | +The project pins a nightly Rust toolchain via `rust-toolchain.toml`; `cargo build` downloads it automatically on first run. |
| 30 | + |
| 31 | +## Quick start |
| 32 | + |
| 33 | +The server needs two upstream endpoints to operate: |
| 34 | + |
| 35 | +| Flag | What it connects to | Methods called | |
| 36 | +| -------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------ | |
| 37 | +| `--rpc-endpoint` | A MegaETH JSON-RPC node that serves standard Ethereum block data. | `eth_getBlockByNumber`, `eth_getHeaderByHash`, `eth_getCodeByHash` | |
| 38 | +| `--witness-endpoint` | A MegaETH endpoint that serves SALT block witnesses. | [`mega_getBlockWitness`](witness.md) | |
| 39 | + |
| 40 | +{% hint style="info" %} |
| 41 | +Most external teams do not run their own witness generator. |
| 42 | +Point `--witness-endpoint` at the MegaETH public RPC — it serves `mega_getBlockWitness` for all historical blocks. |
| 43 | +In the common case both flags point to the same URL. |
| 44 | +{% endhint %} |
| 45 | + |
| 46 | +{% tabs %} |
| 47 | +{% tab title="Mainnet" %} |
| 48 | + |
| 49 | +```bash |
| 50 | +./target/release/debug-trace-server \ |
| 51 | + --rpc-endpoint https://mainnet.megaeth.com/rpc \ |
| 52 | + --witness-endpoint https://mainnet.megaeth.com/rpc |
| 53 | +``` |
| 54 | + |
| 55 | +{% endtab %} |
| 56 | + |
| 57 | +{% tab title="Testnet" %} |
| 58 | + |
| 59 | +```bash |
| 60 | +./target/release/debug-trace-server \ |
| 61 | + --rpc-endpoint https://carrot.megaeth.com/rpc \ |
| 62 | + --witness-endpoint https://carrot.megaeth.com/rpc |
| 63 | +``` |
| 64 | + |
| 65 | +{% endtab %} |
| 66 | +{% endtabs %} |
| 67 | + |
| 68 | +The server listens on `0.0.0.0:8545` by default. |
| 69 | +Verify it is running: |
| 70 | + |
| 71 | +```bash |
| 72 | +curl -s http://localhost:8545 \ |
| 73 | + -H 'Content-Type: application/json' \ |
| 74 | + -d '{"jsonrpc":"2.0","method":"debug_traceBlockByNumber","params":["latest",{"tracer":"callTracer"}],"id":1}' \ |
| 75 | + | head -c 200 |
| 76 | +``` |
| 77 | + |
| 78 | +### Production setup |
| 79 | + |
| 80 | +For production traffic, add `--data-dir` to enable **local cache mode**. |
| 81 | +The server starts a background pipeline that pre-fetches blocks and witnesses into a local database, so trace requests read locally instead of hitting upstream RPC on every call. |
| 82 | + |
| 83 | +```bash |
| 84 | +./target/release/debug-trace-server \ |
| 85 | + --rpc-endpoint https://mainnet.megaeth.com/rpc \ |
| 86 | + --witness-endpoint https://mainnet.megaeth.com/rpc \ |
| 87 | + --data-dir ./dts-data \ |
| 88 | + --blocks-to-keep 5000 \ |
| 89 | + --response-cache-max-size 2GB \ |
| 90 | + --metrics-enabled |
| 91 | +``` |
| 92 | + |
| 93 | +| Flag | Effect | |
| 94 | +| ------------------------------- | ------------------------------------------------------------------------------------------------- | |
| 95 | +| `--data-dir ./dts-data` | Enable local cache mode. Creates a `trace_server.redb` database and starts background block sync. | |
| 96 | +| `--blocks-to-keep 5000` | Retain the most recent 5 000 blocks; older blocks are pruned automatically. | |
| 97 | +| `--response-cache-max-size 2GB` | Cache serialized trace responses in memory so repeated requests return instantly. | |
| 98 | +| `--metrics-enabled` | Expose a Prometheus `/metrics` endpoint on port 9090. | |
| 99 | + |
| 100 | +{% hint style="warning" %} |
| 101 | +On the first start with `--data-dir`, the server fetches the latest block from upstream as an anchor and begins syncing forward. |
| 102 | +To anchor at a specific block, pass `--start-block <BLOCK_HASH>` — this accepts a block **hash**, not a number. |
| 103 | +{% endhint %} |
| 104 | + |
| 105 | +## Supported RPC methods |
| 106 | + |
| 107 | +### Geth-style (`debug_*`) |
| 108 | + |
| 109 | +| Method | Description | |
| 110 | +| -------------------------- | --------------------------------------------- | |
| 111 | +| `debug_traceBlockByNumber` | Trace all transactions in a block, by number. | |
| 112 | +| `debug_traceBlockByHash` | Trace all transactions in a block, by hash. | |
| 113 | +| `debug_traceTransaction` | Trace a single transaction by hash. | |
| 114 | +| `debug_getCacheStatus` | Query current response cache statistics. | |
| 115 | + |
| 116 | +The trace methods accept an optional second parameter with [Geth debug tracing options](https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers): |
| 117 | + |
| 118 | +```json |
| 119 | +{ |
| 120 | + "method": "debug_traceBlockByNumber", |
| 121 | + "params": ["latest", { "tracer": "callTracer" }] |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +Supported tracers: |
| 126 | + |
| 127 | +| Tracer | `tracer` value | Output | |
| 128 | +| ----------------------- | ------------------ | ----------------------------------------------------------------------------- | |
| 129 | +| Default (struct logger) | _(omit)_ | Opcode-level trace with gas, stack, memory, storage at each step. | |
| 130 | +| Call tracer | `"callTracer"` | Nested call tree with inputs, outputs, gas per frame. | |
| 131 | +| Prestate tracer | `"prestateTracer"` | Account state before execution; add `"diffMode": true` for before/after diff. | |
| 132 | +| 4-byte tracer | `"4byteTracer"` | Function selector frequency statistics. | |
| 133 | +| Flat call tracer | `"flatCallTracer"` | Parity-style flat list of all internal calls. | |
| 134 | +| Noop tracer | `"noopTracer"` | No output — useful for benchmarking execution time. | |
| 135 | +| Mux tracer | `"muxTracer"` | Run multiple tracers in a single pass. | |
| 136 | + |
| 137 | +Custom JavaScript tracers are also supported. |
| 138 | + |
| 139 | +### Parity-style (`trace_*`) |
| 140 | + |
| 141 | +| Method | Description | |
| 142 | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | |
| 143 | +| `trace_block` | Flat call traces for all transactions in a block. | |
| 144 | +| `trace_transaction` | Flat call traces for a single transaction. Returns `null` (not an error) when the transaction is not found, matching `mega-reth` behavior. | |
| 145 | + |
| 146 | +Every method also has a `timed_`-prefixed alias (e.g. `timed_debug_traceBlockByNumber`) with identical behavior, letting callers tag client-side metrics separately. |
| 147 | + |
| 148 | +## Command-line reference |
| 149 | + |
| 150 | +Every flag has an equivalent environment variable. |
| 151 | +Command-line flags take precedence. |
| 152 | + |
| 153 | +### Core flags |
| 154 | + |
| 155 | +| Flag | Env variable | Required? | Description | |
| 156 | +| -------------------- | ------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| 157 | +| `--addr` | `DEBUG_TRACE_SERVER_ADDR` | No | Listen address. Default: `0.0.0.0:8545`. | |
| 158 | +| `--rpc-endpoint` | `DEBUG_TRACE_SERVER_RPC_ENDPOINT` | Yes | MegaETH JSON-RPC endpoint(s) for block data. Comma-separated or repeated for failover (round-robin). | |
| 159 | +| `--witness-endpoint` | `DEBUG_TRACE_SERVER_WITNESS_ENDPOINT` | Yes | MegaETH endpoint(s) serving [`mega_getBlockWitness`](witness.md). Comma-separated or repeated for failover (primary-failover: first endpoint takes all traffic while healthy). | |
| 160 | +| `--genesis-file` | `DEBUG_TRACE_SERVER_GENESIS_FILE` | No | Path to genesis JSON. Uses the built-in chain spec when unset. | |
| 161 | + |
| 162 | +### Local cache |
| 163 | + |
| 164 | +Omit `--data-dir` to run in stateless mode (no local storage). |
| 165 | + |
| 166 | +| Flag | Env variable | Default | Description | |
| 167 | +| ------------------------ | ----------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------- | |
| 168 | +| `--data-dir` | `DEBUG_TRACE_SERVER_DATA_DIR` | _(unset)_ | Directory for the local database. Enables local cache mode when set. | |
| 169 | +| `--start-block` | `DEBUG_TRACE_SERVER_START_BLOCK` | _(unset)_ | Block **hash** for the initial anchor. When unset, the server fetches the latest block. Only used on first start. | |
| 170 | +| `--blocks-to-keep` | `DEBUG_TRACE_SERVER_BLOCKS_TO_KEEP` | `1000` | Recent blocks to retain. Older blocks are pruned. | |
| 171 | +| `--db-max-size` | `DEBUG_TRACE_SERVER_DB_MAX_SIZE` | `0` (off) | Max database file size (e.g. `10GB`). Triggers extra pruning (100-block batches) when exceeded. | |
| 172 | +| `--pruner-interval-secs` | `DEBUG_TRACE_SERVER_PRUNER_INTERVAL_SECS` | `300` | Seconds between pruning cycles. | |
| 173 | + |
| 174 | +### Timeout and concurrency |
| 175 | + |
| 176 | +| Flag | Env variable | Default | Description | |
| 177 | +| ----------------------------------- | ---------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------- | |
| 178 | +| `--witness-timeout` | `DEBUG_TRACE_SERVER_WITNESS_TIMEOUT` | `8` | Witness fetch timeout in seconds. | |
| 179 | +| `--block-fetch-timeout` | `DEBUG_TRACE_SERVER_BLOCK_FETCH_TIMEOUT_SECS` | `13` | Total timeout in seconds for all data needed for one block (header + witness + body + contracts). | |
| 180 | +| `--rpc-per-attempt-timeout-ms` | `DEBUG_TRACE_SERVER_RPC_PER_ATTEMPT_TIMEOUT_MS` | _(unset)_ | Per-attempt RPC timeout in milliseconds. Must be ≥ 100. | |
| 181 | +| `--data-max-concurrent-requests` | `DEBUG_TRACE_SERVER_DATA_MAX_CONCURRENT_REQUESTS` | unlimited | Cap on concurrent in-flight data requests (blocks, headers, code). | |
| 182 | +| `--witness-max-concurrent-requests` | `DEBUG_TRACE_SERVER_WITNESS_MAX_CONCURRENT_REQUESTS` | unlimited | Cap on concurrent in-flight witness fetches, independent of the data cap. | |
| 183 | + |
| 184 | +{% hint style="info" %} |
| 185 | +The data and witness concurrency caps are independent semaphores — a burst on one path cannot starve the other. |
| 186 | +When using the public RPC, setting both to `4` prevents HTTP 429 rate-limiting. |
| 187 | +{% endhint %} |
| 188 | + |
| 189 | +### Response cache |
| 190 | + |
| 191 | +| Flag | Env variable | Default | Description | |
| 192 | +| ---------------------------------- | --------------------------------------------------- | ------- | ----------------------------------------------------------------------- | |
| 193 | +| `--response-cache-max-size` | `DEBUG_TRACE_SERVER_RESPONSE_CACHE_MAX_SIZE` | `1GB` | Maximum memory for cached responses. Accepts `KB`, `MB`, `GB` suffixes. | |
| 194 | +| `--response-cache-estimated-items` | `DEBUG_TRACE_SERVER_RESPONSE_CACHE_ESTIMATED_ITEMS` | `1000` | Initial capacity hint. Set to `0` to disable the cache entirely. | |
| 195 | + |
| 196 | +The cache stores pre-serialized JSON responses keyed by `(block_number, tracer_type)`. |
| 197 | +Different tracers on the same block are cached independently. |
| 198 | +Entries are invalidated automatically on chain reorganization. |
| 199 | + |
| 200 | +### Monitoring |
| 201 | + |
| 202 | +| Flag | Env variable | Default | Description | |
| 203 | +| ------------------- | ------------------------------------ | ------- | --------------------------------------- | |
| 204 | +| `--metrics-enabled` | `DEBUG_TRACE_SERVER_METRICS_ENABLED` | `false` | Enable the Prometheus metrics endpoint. | |
| 205 | +| `--metrics-port` | `DEBUG_TRACE_SERVER_METRICS_PORT` | `9090` | Port for the metrics HTTP endpoint. | |
| 206 | + |
| 207 | +When enabled, scrape `http://<HOST>:9090/metrics`. |
| 208 | + |
| 209 | +| Metric | Type | What it tells you | |
| 210 | +| ----------------------------------------------------------------- | --------- | ------------------------------------------------ | |
| 211 | +| `debug_trace_rpc_requests_total` | Counter | Total RPC requests, labelled by method. | |
| 212 | +| `debug_trace_rpc_errors_total` | Counter | Total RPC errors, labelled by method. | |
| 213 | +| `debug_trace_request_duration_seconds` | Histogram | End-to-end request latency. | |
| 214 | +| `debug_trace_inflight_requests` | Gauge | Currently in-flight requests. | |
| 215 | +| `debug_trace_cache_hits_total` / `debug_trace_cache_misses_total` | Counter | Response cache hit/miss. | |
| 216 | +| `debug_trace_evm_execution_seconds` | Histogram | EVM trace execution time per request. | |
| 217 | +| `debug_trace_upstream_duration_seconds` | Histogram | Upstream RPC latency, labelled by method. | |
| 218 | +| `debug_trace_witness_bytes` | Histogram | Witness payload size. | |
| 219 | +| `debug_trace_local_chain_height` | Gauge | Latest block in the local database. | |
| 220 | +| `debug_trace_db_size_bytes` | Gauge | Database file size on disk. | |
| 221 | +| `debug_trace_reorg_depth` | Histogram | Chain reorg depth detected by the sync pipeline. | |
| 222 | + |
| 223 | +### Logging |
| 224 | + |
| 225 | +Logging shares the same `--log.*` flags and `STATELESS_LOG_*` environment variables as the [stateless validator](stateless-validation.md#logging-flags). |
| 226 | +See that page for the full flag table. |
| 227 | + |
| 228 | +Recommended production settings: |
| 229 | + |
| 230 | +```bash |
| 231 | +--log.stdout-format json \ |
| 232 | +--log.stdout-filter info \ |
| 233 | +--log.file-directory /var/log/dts \ |
| 234 | +--log.file-filter debug \ |
| 235 | +--log.file-max-size 500 \ |
| 236 | +--log.file-max-files 10 |
| 237 | +``` |
| 238 | + |
| 239 | +## Environment variables |
| 240 | + |
| 241 | +All flags can be set via environment variables — convenient for container or orchestrator-based deployments: |
| 242 | + |
| 243 | +```bash |
| 244 | +DEBUG_TRACE_SERVER_ADDR=0.0.0.0:8545 |
| 245 | +DEBUG_TRACE_SERVER_RPC_ENDPOINT=https://mainnet.megaeth.com/rpc |
| 246 | +DEBUG_TRACE_SERVER_WITNESS_ENDPOINT=https://mainnet.megaeth.com/rpc |
| 247 | +DEBUG_TRACE_SERVER_DATA_DIR=/data/dts |
| 248 | +DEBUG_TRACE_SERVER_BLOCKS_TO_KEEP=5000 |
| 249 | +DEBUG_TRACE_SERVER_RESPONSE_CACHE_MAX_SIZE=2GB |
| 250 | +DEBUG_TRACE_SERVER_METRICS_ENABLED=true |
| 251 | +STATELESS_LOG_STDOUT=info |
| 252 | +STATELESS_LOG_STDOUT_FORMAT=json |
| 253 | +``` |
| 254 | + |
| 255 | +## Troubleshooting |
| 256 | + |
| 257 | +**Database needs a reset.** |
| 258 | +Stop the service, delete `trace_server.redb` from the data directory, and restart. |
| 259 | +The server re-syncs from the latest block automatically. |
| 260 | + |
| 261 | +```bash |
| 262 | +rm /data/dts/trace_server.redb |
| 263 | +systemctl restart dts |
| 264 | +``` |
| 265 | + |
| 266 | +**Upstream RPC is unreachable.** |
| 267 | +The server retries with round-robin failover and exponential backoff. |
| 268 | +While all endpoints are down, the sync pipeline stalls (it does not crash) and trace requests return error `-32001` after `--block-fetch-timeout` expires. |
| 269 | +Service resumes automatically once any endpoint recovers. |
| 270 | + |
| 271 | +**High memory usage.** |
| 272 | +Lower `--response-cache-max-size` if the response cache is consuming too much memory. |
| 273 | +The contract bytecode cache is process-lifetime — chains with many deployed contracts accumulate bytecode in memory over time. |
| 274 | + |
| 275 | +**Slow trace requests.** |
| 276 | +Use Prometheus metrics to isolate the bottleneck: |
| 277 | + |
| 278 | +- `debug_trace_upstream_duration_seconds` high — upstream RPC is slow. |
| 279 | +- `debug_trace_evm_execution_seconds` high — the block has many or complex transactions. |
| 280 | +- `debug_trace_witness_bytes` large — witness payloads are large, causing slow fetches. |
| 281 | + |
| 282 | +The server logs a warning (`slow stages detected`) for any request stage exceeding 1 second. |
| 283 | + |
| 284 | +## Related pages |
| 285 | + |
| 286 | +- [Debugging Transactions](../dev/send-tx/debugging.md) — trace via the public RPC or `mega-evme` without running your own server |
| 287 | +- [Stateless Validation](stateless-validation.md) — the stateless validator that cryptographically verifies every block |
| 288 | +- [Get Block Witness](witness.md) — `mega_getBlockWitness` RPC reference and witness data layout |
| 289 | +- [debug-trace-server source](https://github.com/megaeth-labs/stateless-validator/tree/main/bin/debug-trace-server) — upstream Rust implementation |
0 commit comments