Docs

Tracing

Use debug_traceTransaction, trace_transaction, and other tracing APIs to inspect smart contract execution, debug failed transactions, and analyze gas usage on Dwellir archive nodes.

Transaction tracing allows you to inspect the internal operations of smart contract executions, debug failed transactions, and analyze gas consumption patterns.

Overview

Tracing APIs provide detailed information about:

  • EVM execution steps
  • Internal transactions
  • State changes
  • Gas consumption
  • Opcode execution
  • Storage modifications

Available Tracing Methods

debug_traceTransaction

Trace a single transaction by hash.

Example data: The curl commands below use Ethereum block 0x166eaba and transaction 0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198 captured on 2025-10-06. Replace them with your own values when tracing different operations.

Bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceTransaction",
    "params": [
      "0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198",
      {
        "tracer": "callTracer",
        "tracerConfig": {
          "onlyTopCall": false
        }
      }
    ],
    "id": 1
  }'

debug_traceBlockByNumber

Trace all transactions in a block.

Bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["0x166eaba", {"tracer": "callTracer"}],
    "id": 1
  }'

trace_transaction

Get trace information for a transaction (Parity/OpenEthereum style).

Bash
curl -X POST https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "trace_transaction",
    "params": ["0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198"],
    "id": 1
  }'

Tracer Types

1. Call Tracer

Captures all calls made during transaction execution.

JavaScript
{
  "tracer": "callTracer",
  "tracerConfig": {
    "onlyTopCall": false,
    "withLog": true
  }
}

Output includes:

  • Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
  • From/to addresses
  • Input/output data
  • Gas used
  • Error messages

2. Prestate Tracer

Shows state before transaction execution.

JavaScript
{
  "tracer": "prestateTracer",
  "tracerConfig": {
    "diffMode": true
  }
}

Output includes:

  • Account balances
  • Contract code
  • Storage values
  • Nonce values

3. 4byte Tracer

Identifies function signatures in the transaction.

JavaScript
{
  "tracer": "4byteTracer"
}

Output:

  • Map of 4-byte signatures to call counts

4. Custom JavaScript Tracer

Create custom tracers for specific analysis.

JavaScript
{
  "tracer": "{data: [], step: function(log) { this.data.push(log.op.toString()); }, result: function() { return this.data; }}"
}

Practical Examples

Debugging Failed Transactions

JavaScript
async function debugFailedTransaction(txHash) {
  const trace = await provider.send('debug_traceTransaction', [
    txHash,
    { tracer: 'callTracer' }
  ]);
  
  // Find the exact failure point
  function findError(call) {
    if (call.error) {
      return {
        address: call.to,
        error: call.error,
        input: call.input
      };
    }
    if (call.calls) {
      for (const subcall of call.calls) {
        const error = findError(subcall);
        if (error) return error;
      }
    }
    return null;
  }
  
  return findError(trace);
}

Analyzing Gas Usage

JavaScript
async function analyzeGasUsage(txHash) {
  const trace = await provider.send('debug_traceTransaction', [
    txHash,
    { tracer: 'callTracer' }
  ]);
  
  function calculateGas(call, depth = 0) {
    const gasInfo = {
      address: call.to,
      gasUsed: parseInt(call.gasUsed, 16),
      depth: depth,
      calls: []
    };
    
    if (call.calls) {
      for (const subcall of call.calls) {
        gasInfo.calls.push(calculateGas(subcall, depth + 1));
      }
    }
    
    return gasInfo;
  }
  
  return calculateGas(trace);
}

Internal Transactions

JavaScript
async function getInternalTransactions(txHash) {
  const trace = await provider.send('trace_transaction', [txHash]);
  
  return trace
    .filter(t => t.type === 'call' && t.action.value !== '0x0')
    .map(t => ({
      from: t.action.from,
      to: t.action.to,
      value: t.action.value,
      success: t.result !== null
    }));
}

Performance Considerations

Archive Node Requirements

Tracing requires archive nodes for historical data:

  • Full state at every block
  • Complete transaction history
  • Higher infrastructure costs

Request Optimization

  1. Cache Trace Results
JavaScript
const traceCache = new Map();

async function getCachedTrace(txHash) {
  if (traceCache.has(txHash)) {
    return traceCache.get(txHash);
  }
  
  const trace = await provider.send('debug_traceTransaction', [
    txHash,
    { tracer: 'callTracer' }
  ]);
  
  traceCache.set(txHash, trace);
  return trace;
}
  1. Batch Trace Requests
JavaScript
async function batchTraceTransactions(txHashes) {
  const requests = txHashes.map((hash, index) => ({
    jsonrpc: '2.0',
    method: 'debug_traceTransaction',
    params: [hash, { tracer: 'callTracer' }],
    id: index
  }));
  
  return await provider.send(requests);
}
  1. Use Appropriate Tracers
  • callTracer for debugging
  • prestateTracer for state analysis
  • 4byteTracer for function identification
  • Custom tracers for specific needs

Error Handling

Common tracing errors and solutions:

Missing State

JSON
{
  "error": {
    "code": -32000,
    "message": "missing trie node"
  }
}

Solution: Use an archive node or request more recent data.

Timeout

JSON
{
  "error": {
    "code": -32000,
    "message": "execution timeout"
  }
}

Solution: Simplify tracer or reduce block range.

Invalid Tracer

JSON
{
  "error": {
    "code": -32602,
    "message": "invalid tracer"
  }
}

Solution: Check tracer syntax and supported tracers for the network.

Security Considerations

When using tracing:

  1. Validate Input: Sanitize transaction hashes and parameters
  2. Rate Limit: Implement client-side rate limiting
  3. Access Control: Restrict tracing access in production
  4. Data Privacy: Traced data may contain sensitive information

Tools and Libraries

Web3.js

JavaScript
const trace = await web3.currentProvider.send({
  method: 'debug_traceTransaction',
  params: [txHash, { tracer: 'callTracer' }]
});

Ethers.js

JavaScript
const trace = await provider.send('debug_traceTransaction', [
  txHash,
  { tracer: 'callTracer' }
]);

Cast (Foundry)

Bash
cast run --trace 0xhash --rpc-url https://api-ethereum-mainnet.n.dwellir.com/YOUR_API_KEY

Need help with tracing? Contact our support team.