To trace an XDC transaction with xOne, call debug_traceTransaction with a tracer option. xOneRS serves callTracer, prestateTracer, flatCallTracer and, when tracer is absent, the struct (opcode) logger. A trace re-executes the transaction, so the node needs the state of the parent block.
This post gives one example request per tracer, the shape of each answer, and what is not served. For the whole RPC list, see the RPC surface post.
How do I turn tracing on?
The debug namespace is never enabled by default. A listener serves only the namespaces of its --http.api or --ws.api list (methods.md).
xone --network net2040 --datadir <datadir> --http --http.api eth,net,debug
Each debug_trace* call costs 100 units and has a 30 s deadline (class C3).
Which methods take a tracer?
Five methods take a tracer: debug_traceTransaction, debug_traceBlockByNumber, debug_traceBlockByHash, debug_traceBlock (raw block RLP) and debug_traceCall. The trace config is {"tracer": "<name>", "tracerConfig": {...}}.
The block methods return one {txHash, result} entry per transaction. debug_traceCall takes a call object, a block and the trace config. Its config also accepts stateOverrides and blockOverrides, which apply to that call only (debug.rs).
What does callTracer return?
callTracer returns the tree of calls of the transaction. Each frame has type, from, gas, gasUsed, to, input and value. It adds output, error, revertReason, calls and logs when they are not empty. Options: onlyTopCall and withLog.
Example request (composed from the documented method and options, not a recorded call):
{"jsonrpc":"2.0","id":1,"method":"debug_traceTransaction",
"params":["<tx-hash>",{"tracer":"callTracer","tracerConfig":{"onlyTopCall":false,"withLog":true}}]}
callTracer errors name the opcode and the stack depth, for example invalid opcode: INVALID and stack underflow (1 <=> 2) (PR #860).
What does prestateTracer return?
prestateTracer returns the accounts the transaction reads, keyed by address. Each account has balance, and nonce, code, codeHash and storage when they apply. With diffMode, the answer is {"pre": ..., "post": ...}.
Example request (not a recorded call):
{"jsonrpc":"2.0","id":2,"method":"debug_traceTransaction",
"params":["<tx-hash>",{"tracer":"prestateTracer","tracerConfig":{"diffMode":true}}]}
Accounts that were empty are left out, and the coinbase is looked up as geth does (PR #860).
What does flatCallTracer return?
flatCallTracer returns the call tree as a flat list of Parity-style traces, the format of the trace_* namespace. Each transaction gets its tracer context: block hash, block number, transaction hash and index. Options: convertParityErrors and includePrecompiles (PR #880).
Example request (not a recorded call):
{"jsonrpc":"2.0","id":3,"method":"debug_traceBlockByNumber",
"params":["0x<block-number>",{"tracer":"flatCallTracer","tracerConfig":{"convertParityErrors":true}}]}
One gap: for debug_traceBlock with a raw block, the node does not know the block hash. The flat traces then carry blockHash: null (#169).
What does the struct logger return?
The struct logger is the default tracer when tracer is absent. It returns {gas, failed, returnValue, structLogs}. Each step has pc, op, gas, gasCost and depth, and stack, memory, storage, returnData, refund or error when they apply. Options: enableMemory, disableStack, disableStorage, enableReturnData and limit.
Example request (not a recorded call):
{"jsonrpc":"2.0","id":4,"method":"debug_traceCall",
"params":[{"from":"<address>","to":"<address>","data":"0x<calldata>"},"latest",
{"disableStorage":true,"enableReturnData":true}]}
The struct logger writes error on a step that runs out of gas or hits a stack limit (PR #799). Two gaps stay open in #154. From net2040's Amsterdam rows, gas above 2^24 is a reservoir, so the GAS opcode, CALL costs and the result gas differ from geth. And the gasCost of a step that runs out of gas is the gas left, where geth gives the attempted cost.
Which tracers are not served?
JavaScript tracers are not served. A request for one answers tracer not found: <name>. Any other unknown name gets the same answer. ADR-008 states that the JS tracers are out (ADR-008).
xOneRS also serves 4byteTracer, noopTracer, muxTracer (a tracer name to its config), opcodeSummaryTracer and consoleTracer. The last two are xOne tracers, not geth names.
The Parity-style trace_block, trace_filter, trace_get and trace_transaction are served. The rest of that namespace is open in #181. debug_intermediateRoots and debug_traceBadBlock are open in #220.
Does tracing need historical state?
Yes. A trace re-executes the block on the state of its parent. The node checks that this state is retained. If it is not, the call fails with the typed unsupported history error (code -32000). A full node answers inside its state window only.
The archive guide says the tracers are not served from the archive history yet. So tracing below the window is open work. See the archive mode post for what an archive node serves today.
How is tracer parity with geth-XDC checked?
The rpc-parity harness replays calls on their recorded prestate and compares the answers with the geth-XDC archive. The counts below are from the merged PRs. All were equal, with 0 differing.
| What | Count | Source |
|---|---|---|
debug_traceCall, struct logger |
96 net2040 calls | PR #799 |
debug_traceCall, struct logger with overrides |
112 calls | PR #860 |
debug_traceCall, callTracer and prestateTracer |
96 calls each | PR #860 |
debug_traceCall, flatCallTracer (plain, convertParityErrors, includePrecompiles) |
96 calls each, 288 results | PR #880 |
PR #860 states 400 debug_traceCall results equal. The first run found divergences, and the PR fixes them. One example: a refused override error was wrapped in extra text.
Net2040 has no user transactions, so these are fixed call templates. Fifty real transactions per tracer are not done yet (#169). The harness is in the conformance replay gate post.
How do other clients describe tracing?
The table gives the one tracing claim we have, as stated, with the xOne fact next to it.
| Client | Claim, as stated | xOne on main |
|---|---|---|
| reth | 2.0 adds debug_intermediateRoots and debug_traceBadBlock. Source: reth v2.0.0 release, no date listed |
Not served yet (#220). |
Frequently asked questions
Which tracers does xOneRS serve?
xOneRS serves callTracer, prestateTracer, flatCallTracer, 4byteTracer, noopTracer, muxTracer, opcodeSummaryTracer and consoleTracer. The struct logger is the default when tracer is absent.
Does xOne serve JavaScript tracers?
No. A JavaScript tracer name answers tracer not found. ADR-008 puts the JS tracers out of scope.
Why does my trace answer unsupported history?
A trace needs the state of the parent block. If the node does not retain it, the call answers the typed unsupported history error.
Is the debug namespace on by default?
No. Name debug in --http.api or --ws.api. Each trace call costs 100 units and has a 30 s deadline.
Is xOne tracer output equal to geth-XDC?
On the recorded net2040 calls, yes: every compared debug_traceCall result was equal. Real user transactions are not covered yet.
Sources
- xOneRS: debug.rs, docs/rpc/methods.md, ADR-008, docs/ops/archive.md, RPC vectors
- Pull requests: #799, #860, #880
- Issues: #154, #169, #181, #220
- reth: v2.0.0 release
This article describes the source and evidence at its review date. Check the linked repository for current implementation and qualification status.
Explore the engineering evidenceEdit this page on GitHub opens the Markdown source (content/blog/tracing-transactions-xone/index.md). GitHub may ask you to sign in. Report a correction opens a prefilled GitHub issue for this page.