Skip to main content

debug_traceBlockByHash

Returns execution traces for all transactions in a block specified by its hash. This is particularly useful when you have a block hash rather than a block number, commonly used in event-driven architectures and block explorers.

Premium Method

This method is available on premium plans with debug API access. Contact our team for access.

When to Use This Method​

debug_traceBlockByHash is essential for:

  • Block Explorer Integration - Analyze blocks when you only have the hash
  • Event-Driven Analysis - Process blocks as they're mined using their hash
  • Transaction Ordering Analysis - Understand MEV and transaction sequencing
  • Gas Optimization - Analyze gas consumption patterns across entire blocks
  • Smart Contract Debugging - Trace all interactions within a specific block

Parameters​

1. blockHash (required)​

  • Type: DATA, 32 bytes
  • Description: The hash of the block to trace
  • Example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

2. tracer (optional)​

  • Type: Object
  • Description: Tracer configuration object
  • Fields:
    • tracer: The type of tracer to use (callTracer, prestateTracer, or custom JavaScript)
    • tracerConfig: Additional configuration for the tracer

Common Tracer Types​

callTracer​

Returns a nested list of call frames:

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

prestateTracer​

Returns the state before transaction execution:

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

Returns​

Array of trace objects, one for each transaction in the block:

FieldTypeDescription
resultObjectThe trace result for each transaction
txHashStringHash of the traced transaction
fromAddressSender address
toAddressRecipient address
gasQuantityGas provided
gasUsedQuantityGas actually consumed
inputDataTransaction input data
outputDataTransaction output data
callsArrayInternal call traces (with callTracer)
errorStringError message if execution failed
revertReasonStringSolidity revert reason if available

Implementation Examples​

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

Response Example​

Successful Response​

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"from": "0x742d35cc6634c0532925a3b844bc9e7595f0beb5",
"to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"gas": "0x30d40",
"gasUsed": "0x1a8f0",
"input": "0xa9059cbb000000000000000000000000...",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"type": "CALL",
"value": "0x0",
"calls": [
{
"from": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"to": "0x4200000000000000000000000000000000000006",
"gas": "0x2a8d8",
"gasUsed": "0x5208",
"input": "0x",
"output": "0x",
"type": "CALL",
"value": "0x1bc16d674ec80000"
}
]
},
{
"from": "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5",
"to": "0x4200000000000000000000000000000000000016",
"gas": "0x186a0",
"gasUsed": "0x12345",
"input": "0x095ea7b3...",
"output": "0x",
"type": "CALL",
"value": "0x0"
}
]
}

Common Use Cases​

1. MEV Analysis​

Analyze transaction ordering and MEV extraction:

async function analyzeMEV(blockHash) {
const traces = await traceBlockByHash(blockHash);

// Look for sandwich attacks
const dexCalls = traces.filter(trace =>
isUniswapRouter(trace.to) || isSushiSwapRouter(trace.to)
);

// Identify potential sandwich patterns
for (let i = 1; i < dexCalls.length - 1; i++) {
const prev = dexCalls[i - 1];
const curr = dexCalls[i];
const next = dexCalls[i + 1];

if (prev.from === next.from && prev.from !== curr.from) {
console.log('Potential sandwich attack detected');
console.log(`Attacker: ${prev.from}`);
console.log(`Victim: ${curr.from}`);
}
}
}

2. Gas Usage Patterns​

Identify gas-intensive contracts:

def analyze_gas_patterns(block_hash):
traces = trace_block_by_hash(block_hash)

# Aggregate gas by contract
gas_by_contract = {}

for trace in traces:
to_address = trace.get('to', 'creation')
gas_used = int(trace.get('gasUsed', '0x0'), 16)

if to_address not in gas_by_contract:
gas_by_contract[to_address] = {
'total_gas': 0,
'tx_count': 0,
'failed_count': 0
}

gas_by_contract[to_address]['total_gas'] += gas_used
gas_by_contract[to_address]['tx_count'] += 1

if trace.get('error'):
gas_by_contract[to_address]['failed_count'] += 1

# Sort by gas consumption
sorted_contracts = sorted(
gas_by_contract.items(),
key=lambda x: x[1]['total_gas'],
reverse=True
)

print("Top Gas Consumers:")
for contract, stats in sorted_contracts[:10]:
avg_gas = stats['total_gas'] // stats['tx_count']
failure_rate = stats['failed_count'] / stats['tx_count'] * 100
print(f"{contract}:")
print(f" Total Gas: {stats['total_gas']:,}")
print(f" Transactions: {stats['tx_count']}")
print(f" Average Gas: {avg_gas:,}")
print(f" Failure Rate: {failure_rate:.1f}%")

3. Block Event Reconstruction​

Reconstruct all events emitted in a block:

async function reconstructBlockEvents(blockHash) {
const traces = await traceBlockByHash(blockHash, 'callTracer');
const events = [];

for (const trace of traces) {
// Process main transaction
if (trace.output && trace.output !== '0x') {
events.push({
type: 'direct',
from: trace.from,
to: trace.to,
data: trace.output
});
}

// Process internal calls
if (trace.calls) {
for (const call of trace.calls) {
if (call.type === 'LOG') {
events.push({
type: 'event',
address: call.from,
topics: call.topics,
data: call.data
});
}
}
}
}

return events;
}

Error Handling​

Common errors and solutions:

Error CodeDescriptionSolution
-32000Block not foundVerify the block hash exists
-32601Method not foundEnsure debug API access is enabled
-32602Invalid paramsCheck block hash format (0x + 64 hex chars)
-32603Internal errorBlock may be too large; try with smaller blocks
-32005TimeoutReduce block range or optimize tracer config

Error Handling Example​

async function safeTraceBlock(blockHash, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const traces = await traceBlockByHash(blockHash);
return traces;
} catch (error) {
if (error.code === -32000) {
// Block not found - it might not be mined yet
console.log(`Block ${blockHash} not found, waiting...`);
await new Promise(resolve => setTimeout(resolve, 2000));
} else if (error.code === -32603 && attempt < maxRetries - 1) {
// Internal error - might be temporary
console.log(`Attempt ${attempt + 1} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
} else {
throw error;
}
}
}

throw new Error(`Failed to trace block after ${maxRetries} attempts`);
}

Best Practices​

  1. Cache Results: Block traces are immutable once finalized
  2. Use Appropriate Tracers: callTracer for call analysis, prestateTracer for state changes
  3. Handle Large Blocks: Some blocks may have hundreds of transactions
  4. Monitor Performance: Tracing is computationally intensive
  5. Implement Retries: Network issues may cause temporary failures

Need help? Contact our support team for assistance with debug methods.