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.