Cross-Contract Call Tracing
Source: docs/design/cross-contract-call-tracing.md
Status: Draft Issue: chain-3gy7a Date: 2026-02-03
Overview
Section titled “Overview”Cross-contract call tracing captures the full call tree for a single VM execution. Each call frame records gas usage, inputs/outputs, storage operations, events, and nested calls so debugging and profiling can happen with full context.
Trace Data Model
Section titled “Trace Data Model”Tracing is represented by a TraceFrame tree in crates/vm-runtime and mirrored
into src/core/execution/types.rs for node-level use. Each frame includes:
- Call metadata: call type, caller, callee, value, gas limit, gas used.
- Payloads: input calldata and output bytes.
- Side effects: storage ops (read/write/delete) with before/after values and gas.
- Events: emitted logs with contract + topics + data.
- Children: nested call frames.
- Error metadata and a wall-clock duration in nanoseconds.
Related types:
TraceStorageOpandTraceStorageOpTypeTraceLogEntryTraceErrorTracingConfig(max depth)
Capture Flow
Section titled “Capture Flow”TxContext::enable_tracing(TracingConfig { max_depth })turns tracing on.- Syscall handlers call
enter_call_frameon call entry andexit_call_frameon return. - Storage reads/writes and log emissions are pushed into the current frame via
trace_storage_opandtrace_event. take_root_trace()returns the rootTraceFrametree for formatting or post-processing.
Depth is capped by TracingConfig.max_depth (default: 64). Frames beyond the
limit are suppressed rather than partially recorded.
Output Formats
Section titled “Output Formats”crates/vm-runtime/src/trace_format.rs renders the trace tree into:
- JSON (
to_json,to_json_compact,to_json_with_metadata) - Chrome trace format (
to_chrome_trace/to_chrome_trace_pretty) - Human-readable tree output (
to_tree/to_tree_with_config)
src/core/execution/trace_format.rs mirrors similar formatters for core
TraceFrame types at the node layer.
Post-Processing Utilities
Section titled “Post-Processing Utilities”These helpers live in crates/vm-runtime and can be wired into higher-level
interfaces as needed:
trace_compress: deduplicates repeated subtrees to keep large traces small.trace_filter: selective tracing by contract, depth range, gas threshold, value transfer, selector, or failure-only.trace_diff: structured comparison between two traces for regressions.trace_summary: aggregates net storage deltas, events, touched contracts, and gas/time stats.
RPC Surface
Section titled “RPC Surface”The RPC IDL defines hierarchical trace endpoints:
chain_traceTransaction: returns a detailed frame tree with storage ops and events (TraceFrameDetailed). Acceptsmax_depth.chain_traceCall: returns a simpler frame tree (TraceFrame) for view calls.
See src/rpc/node_rpc_v1.idl for the request/response fields.
Trace Persistence (Flat Traces)
Section titled “Trace Persistence (Flat Traces)”src/debug/trace.rs stores flat execution traces (ExecutionTrace) built from
VmTxTrace (storage writes, logs, transfers, return data). Storage is enabled
with environment variables:
ASHEN_DEBUG_TRACE_DIRASHEN_DEBUG_TRACE_MAX_BLOCKSASHEN_DEBUG_TRACE_MAX_BYTES
This path is for deterministic replay and audit trails, not the hierarchical call tree.
Where to Look
Section titled “Where to Look”- Runtime tracing core:
crates/vm-runtime/src/context.rs - Formatters:
crates/vm-runtime/src/trace_format.rs - Compression/diff/filter/summary:
crates/vm-runtime/src/trace_*.rs - Core type bridge:
src/core/execution/types.rs - RPC definitions:
src/rpc/node_rpc_v1.idl - Trace storage:
src/debug/trace.rs