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:
Field | Type | Description |
---|---|---|
result | Object | The trace result for each transaction |
txHash | String | Hash of the traced transaction |
from | Address | Sender address |
to | Address | Recipient address |
gas | Quantity | Gas provided |
gasUsed | Quantity | Gas actually consumed |
input | Data | Transaction input data |
output | Data | Transaction output data |
calls | Array | Internal call traces (with callTracer) |
error | String | Error message if execution failed |
revertReason | String | Solidity revert reason if available |
Implementation Examples​
- cURL
- JavaScript
- Python
- Go
curl -X POST https://api-base-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
}'
const traceBlockByHash = async (blockHash) => {
const response = await fetch('https://api-base-mainnet.n.dwellir.com/YOUR_API_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'debug_traceBlockByHash',
params: [
blockHash,
{
tracer: 'callTracer',
tracerConfig: {
onlyTopCall: false,
withLog: true
}
}
],
id: 1
})
});
const data = await response.json();
return data.result;
};
// Example usage
const blockHash = '0x97b49e43632ac7c22b22b0f6dba10b91dd3f525b2e5e7a6490b0b8f6b5d1f123';
const traces = await traceBlockByHash(blockHash);
// Process each transaction trace
traces.forEach((trace, index) => {
console.log(`Transaction ${index}:`);
console.log(` From: ${trace.from}`);
console.log(` To: ${trace.to}`);
console.log(` Gas Used: ${trace.gasUsed}`);
console.log(` Success: ${!trace.error}`);
if (trace.calls) {
console.log(` Internal Calls: ${trace.calls.length}`);
}
});
import requests
import json
def trace_block_by_hash(block_hash, tracer_type='callTracer'):
"""
Trace all transactions in a block by its hash
"""
url = 'https://api-base-mainnet.n.dwellir.com/YOUR_API_KEY'
payload = {
"jsonrpc": "2.0",
"method": "debug_traceBlockByHash",
"params": [
block_hash,
{
"tracer": tracer_type,
"tracerConfig": {
"onlyTopCall": False,
"withLog": True
}
}
],
"id": 1
}
response = requests.post(url, json=payload)
data = response.json()
if 'error' in data:
raise Exception(f"RPC Error: {data['error']['message']}")
return data['result']
# Example usage
block_hash = '0x97b49e43632ac7c22b22b0f6dba10b91dd3f525b2e5e7a6490b0b8f6b5d1f123'
traces = trace_block_by_hash(block_hash)
# Analyze gas usage across the block
total_gas = 0
failed_txs = 0
for i, trace in enumerate(traces):
gas_used = int(trace.get('gasUsed', '0x0'), 16)
total_gas += gas_used
if trace.get('error'):
failed_txs += 1
print(f"Transaction {i} failed: {trace['error']}")
# Check for high gas consumption
if gas_used > 1000000:
print(f"High gas transaction {i}: {gas_used:,} gas")
print(f"\nBlock Analysis:")
print(f"Total transactions: {len(traces)}")
print(f"Failed transactions: {failed_txs}")
print(f"Total gas consumed: {total_gas:,}")
print(f"Average gas per tx: {total_gas // len(traces):,}")
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type TraceConfig struct {
Tracer string `json:"tracer"`
TracerConfig map[string]interface{} `json:"tracerConfig"`
}
type TraceResult struct {
From string `json:"from"`
To string `json:"to"`
Gas string `json:"gas"`
GasUsed string `json:"gasUsed"`
Input string `json:"input"`
Output string `json:"output"`
Error string `json:"error,omitempty"`
Calls []Call `json:"calls,omitempty"`
}
type Call struct {
Type string `json:"type"`
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasUsed string `json:"gasUsed"`
Input string `json:"input"`
Output string `json:"output"`
}
func traceBlockByHash(blockHash string) ([]TraceResult, error) {
url := "https://api-base-mainnet.n.dwellir.com/YOUR_API_KEY"
config := TraceConfig{
Tracer: "callTracer",
TracerConfig: map[string]interface{}{
"onlyTopCall": false,
"withLog": true,
},
}
payload := map[string]interface{}{
"jsonrpc": "2.0",
"method": "debug_traceBlockByHash",
"params": []interface{}{blockHash, config},
"id": 1,
}
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, err
}
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result struct {
Result []TraceResult `json:"result"`
Error *struct {
Message string `json:"message"`
} `json:"error"`
}
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
if result.Error != nil {
return nil, fmt.Errorf("RPC error: %s", result.Error.Message)
}
return result.Result, nil
}
func main() {
blockHash := "0x97b49e43632ac7c22b22b0f6dba10b91dd3f525b2e5e7a6490b0b8f6b5d1f123"
traces, err := traceBlockByHash(blockHash)
if err != nil {
panic(err)
}
// Analyze the block
fmt.Printf("Block %s Analysis:\n", blockHash)
fmt.Printf("Total transactions: %d\n", len(traces))
for i, trace := range traces {
fmt.Printf("\nTransaction %d:\n", i)
fmt.Printf(" From: %s\n", trace.From)
fmt.Printf(" To: %s\n", trace.To)
fmt.Printf(" Gas Used: %s\n", trace.GasUsed)
if trace.Error != "" {
fmt.Printf(" Error: %s\n", trace.Error)
}
if len(trace.Calls) > 0 {
fmt.Printf(" Internal Calls: %d\n", len(trace.Calls))
}
}
}
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 Code | Description | Solution |
---|---|---|
-32000 | Block not found | Verify the block hash exists |
-32601 | Method not found | Ensure debug API access is enabled |
-32602 | Invalid params | Check block hash format (0x + 64 hex chars) |
-32603 | Internal error | Block may be too large; try with smaller blocks |
-32005 | Timeout | Reduce 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​
- Cache Results: Block traces are immutable once finalized
- Use Appropriate Tracers:
callTracer
for call analysis,prestateTracer
for state changes - Handle Large Blocks: Some blocks may have hundreds of transactions
- Monitor Performance: Tracing is computationally intensive
- Implement Retries: Network issues may cause temporary failures
Related Methods​
debug_traceBlock
- Trace by block numberdebug_traceBlockByNumber
- Alternative block tracingdebug_traceTransaction
- Trace individual transactionsdebug_traceCall
- Trace calls without creating transactions
Need help? Contact our support team for assistance with debug methods.