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
0x166eabaand transaction0xad5b9400c749bd5d6ca2bb026bd23e83d6ff71d52a0fb379e85ae2020a0ed198captured on 2025-10-06. Replace them with your own values when tracing different operations.
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.
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).
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.
{
"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
- 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;
}- 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);
}- Use Appropriate Tracers
callTracerfor debuggingprestateTracerfor state analysis4byteTracerfor 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:
- Validate Input: Sanitize transaction hashes and parameters
- Rate Limit: Implement client-side rate limiting
- Access Control: Restrict tracing access in production
- 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.n.dwellir.com/YOUR_API_KEYNeed help with tracing? Contact our support team.
Archive Nodes
Learn what archive nodes are, when you need them, how they differ from full nodes, and how to choose the right endpoint on Dwellir.
Sticky Sessions
Pin your requests to a single backend node using the DWSESSION cookie. Useful for consistent state across sequential calls like eth_getFilterChanges, eth_subscribe, and trace workflows.