⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

Tracing

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.

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

debug_traceBlockByNumber

Trace all transactions in a block.

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

trace_transaction

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

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

Tracer Types

1. Call Tracer

Captures all calls made during transaction execution.

{
"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.

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

Output includes:

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

3. 4byte Tracer

Identifies function signatures in the transaction.

{
"tracer": "4byteTracer"
}

Output:

  • Map of 4-byte signatures to call counts

4. Custom JavaScript Tracer

Create custom tracers for specific analysis.

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

Practical Examples

Debugging Failed Transactions

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

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

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
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
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

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

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

Timeout

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

Solution: Simplify tracer or reduce block range.

Invalid Tracer

{
"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

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

Ethers.js

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

Cast (Foundry)

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

Need help with tracing? Contact our support team.