# debug_traceBlockByHash - IoTeX RPC Method

Traces all transactions in a block on IoTeX identified by its block hash. Returns detailed execution traces for every transaction, making it ideal for investigating specific blocks when you know the exact hash.

> **Why IoTeX?** Build on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem with W3bstream offchain compute, Quicksilver AI data verification, Vodafone partnership for 5M+ cell tower integration, and ioID device identity.

This method requires an archive node with debug APIs enabled. Standard full nodes prune the historical state needed for transaction tracing. Dwellir provides archive node access for IoTeX - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Investigating Specific Blocks** - When you have a block hash from an event, alert, or on-chain reference, trace every transaction in that exact block on IoTeX
- **Analyzing Transaction Execution Order** - Understand how transactions within a block interact, including cross-transaction state dependencies
- **Debugging Reverted Transactions** - Find the exact opcode where transactions failed across an entire block for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Fork and Reorg Analysis** - Use block hashes to trace transactions in specific forks, ensuring you analyze the correct chain branch

## Best Practices

- Use block hash for deterministic results during chain reorganizations
- Same performance considerations as debug\_traceBlockByNumber apply
- Requires archive node access; not available on standard full nodes

## Request Parameters

- `blockHash` (`DATA, required`): 32-byte hash of the block to trace
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByHash",
  "params": [
    "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}
```

## Response Fields

- `result` (`Array<Object>, required`): Array of trace objects, one per transaction
- `result[].result` (`Object, required`): Trace output (structure depends on tracer used)
- `result[].txHash` (`DATA, required`): Transaction hash for this trace
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2)
- `from` (`DATA, required`): Sender address
- `to` (`DATA, required`): Recipient address
- `value` (`QUANTITY, required`): Value transferred in wei
- `gas` (`QUANTITY, required`): Gas provided
- `gasUsed` (`QUANTITY, required`): Gas consumed
- `input` (`DATA, required`): Call data
- `output` (`DATA, required`): Return data
- `error` (`string, required`): Error message if the call reverted
- `revertReason` (`string, required`): Decoded revert reason (if available)
- `calls` (`Array, required`): Sub-calls made during execution
- `address` (`Object, required`): State of each account touched by the transaction
- `address.balance` (`QUANTITY, required`): Account balance before execution
- `address.nonce` (`QUANTITY, required`): Account nonce before execution
- `address.code` (`DATA, required`): Contract bytecode (if contract account)
- `address.storage` (`Object, required`): Storage slots read or written

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "txHash": "0xabc123...",
      "result": {
        "type": "CALL",
        "from": "0x1234567890abcdef1234567890abcdef12345678",
        "to": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "value": "0xde0b6b3a7640000",
        "gas": "0x76c0",
        "gasUsed": "0x5208",
        "input": "0x",
        "output": "0x"
      }
    },
    {
      "txHash": "0xdef456...",
      "result": {
        "type": "CALL",
        "from": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "value": "0x0",
        "gas": "0x1e848",
        "gasUsed": "0xb841",
        "input": "0xa9059cbb...",
        "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x1388",
            "input": "0x70a08231...",
            "output": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "block not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# Trace with call tracer
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": [
      "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
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": [
      "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const blockHash = '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2';

// Call tracer - shows internal calls tree
const callTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'callTracer' }
]);

console.log(`Block has ${callTraces.length} transactions`);

for (const trace of callTraces) {
  console.log(`Tx: ${trace.txHash}`);
  console.log(`  Type: ${trace.result.type}`);
  console.log(`  From: ${trace.result.from}`);
  console.log(`  To: ${trace.result.to}`);
  console.log(`  Gas used: ${parseInt(trace.result.gasUsed, 16)}`);
  if (trace.result.error) {
    console.log(`  ERROR: ${trace.result.error}`);
  }
}

// Prestate tracer - shows account state before execution
const prestateTraces = await provider.send('debug_traceBlockByHash', [
  blockHash,
  { tracer: 'prestateTracer' }
]);

for (const trace of prestateTraces) {
  const addresses = Object.keys(trace.result);
  console.log(`Tx ${trace.txHash} touched ${addresses.length} accounts`);
}
```

```python
import requests

def trace_block_by_hash(block_hash, tracer='callTracer'):
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByHash',
            'params': [block_hash, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

block_hash = '0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2'

# Call tracer
traces = trace_block_by_hash(block_hash)
print(f'Block contains {len(traces)} transactions')

for trace in traces:
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    status = 'REVERTED' if 'error' in result else 'OK'
    print(f'  {trace["txHash"]}: {gas_used} gas [{status}]')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))

traces = w3.provider.make_request('debug_traceBlockByHash', [
    block_hash,
    {'tracer': 'callTracer'}
])
print(f'Traced {len(traces["result"])} transactions')
```

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strconv"
)

type TraceResult struct {
    TxHash string    `json:"txHash"`
    Result CallTrace `json:"result"`
}

type CallTrace 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"`
    Error   string      `json:"error,omitempty"`
    Calls   []CallTrace `json:"calls,omitempty"`
}

func main() {
    blockHash := "0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2"

    payload := map[string]interface{}{
        "jsonrpc": "2.0",
        "method":  "debug_traceBlockByHash",
        "params": []interface{}{
            blockHash,
            map[string]string{"tracer": "callTracer"},
        },
        "id": 1,
    }

    body, _ := json.Marshal(payload)
    resp, err := http.Post(
        "https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    data, _ := io.ReadAll(resp.Body)

    var response struct {
        Result []TraceResult `json:"result"`
    }
    json.Unmarshal(data, &response)

    fmt.Printf("Block contains %d transactions\n", len(response.Result))
    for _, trace := range response.Result {
        gasUsed, _ := strconv.ParseInt(trace.Result.GasUsed[2:], 16, 64)
        status := "OK"
        if trace.Result.Error != "" {
            status = "REVERTED: " + trace.Result.Error
        }
        fmt.Printf("  %s: %d gas [%s]\n", trace.TxHash, gasUsed, status)
    }
}
```

## Common Use Cases

### 1. Find All Reverted Transactions in a Block

Identify and analyze failed transactions on IoTeX:

```javascript
async function findReverts(provider, blockHash) {
  const traces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'callTracer' }
  ]);

  const reverts = [];

  for (const trace of traces) {
    if (trace.result.error) {
      reverts.push({
        txHash: trace.txHash,
        error: trace.result.error,
        revertReason: trace.result.revertReason || 'N/A',
        from: trace.result.from,
        to: trace.result.to,
        gasUsed: parseInt(trace.result.gasUsed, 16)
      });
    }

    // Also check sub-calls for internal reverts
    const internalReverts = findInternalReverts(trace.result.calls || []);
    if (internalReverts.length > 0) {
      reverts.push({
        txHash: trace.txHash,
        internalReverts,
        topLevelSuccess: !trace.result.error
      });
    }
  }

  console.log(`Found ${reverts.length} reverted transactions out of ${traces.length}`);
  for (const r of reverts) {
    console.log(`  ${r.txHash}: ${r.error || 'internal revert'}`);
  }
  return reverts;
}

function findInternalReverts(calls) {
  const reverts = [];
  for (const call of calls) {
    if (call.error) {
      reverts.push({ type: call.type, to: call.to, error: call.error });
    }
    reverts.push(...findInternalReverts(call.calls || []));
  }
  return reverts;
}
```

### 2. Analyze Token Transfer Patterns in a Block

Extract all ERC-20 transfer events from block traces on IoTeX:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlockByHash',
        'params': [block_hash, {'tracer': 'callTracer'}],
        'id': 1
    })
    traces = response.json()['result']

    # ERC-20 transfer(address,uint256) selector
    TRANSFER_SELECTOR = '0xa9059cbb'
    # ERC-20 transferFrom(address,address,uint256) selector
    TRANSFER_FROM_SELECTOR = '0x23b872dd'

    transfers = []

    for trace in traces:
        calls = flatten_calls(trace['result'])
        for call in calls:
            input_data = call.get('input', '')
            if input_data.startswith(TRANSFER_SELECTOR) or \
               input_data.startswith(TRANSFER_FROM_SELECTOR):
                transfers.append({
                    'tx_hash': trace['txHash'],
                    'token_contract': call['to'],
                    'from': call['from'],
                    'type': call['type'],
                    'gas_used': int(call.get('gasUsed', '0x0'), 16)
                })

    print(f'Found {len(transfers)} token transfers in block')
    # Group by token contract
    by_token = {}
    for t in transfers:
        by_token.setdefault(t['token_contract'], []).append(t)

    for token, txs in by_token.items():
        print(f'  {token}: {len(txs)} transfers')

    return transfers

def flatten_calls(trace):
    calls = [trace]
    for sub in trace.get('calls', []):
        calls.extend(flatten_calls(sub))
    return calls

analyze_token_transfers('0xc5bd9f787bec85feee50f013caebb999107e5ba47da16ac194a5dbb06b5f4ff2')
```

### 3. Block Execution State Diff

Compare account states before and after block execution using the prestate tracer:

```javascript
async function getBlockStateDiff(provider, blockHash) {
  // Get prestate - accounts state before each transaction
  const prestateTraces = await provider.send('debug_traceBlockByHash', [
    blockHash,
    { tracer: 'prestateTracer', tracerConfig: { diffMode: true } }
  ]);

  const allAddresses = new Set();
  const balanceChanges = {};

  for (const trace of prestateTraces) {
    const pre = trace.result.pre || trace.result;
    const post = trace.result.post || {};

    for (const [addr, state] of Object.entries(pre)) {
      allAddresses.add(addr);
      if (!balanceChanges[addr]) {
        balanceChanges[addr] = {
          preBal: BigInt(state.balance || '0x0'),
          postBal: BigInt((post[addr]?.balance) || state.balance || '0x0')
        };
      }
    }
  }

  console.log(`Block touched ${allAddresses.size} unique addresses`);
  for (const [addr, change] of Object.entries(balanceChanges)) {
    const diff = change.postBal - change.preBal;
    if (diff !== 0n) {
      console.log(`  ${addr}: ${diff > 0n ? '+' : ''}${diff} wei`);
    }
  }

  return balanceChanges;
}
```

## Related Methods

- [`debug_traceBlock`](https://www.dwellir.com/docs/iotex/debug_traceBlock) - Trace all transactions using RLP-encoded block data
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/iotex/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/iotex/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/iotex/debug_traceCall) - Trace a call without creating a transaction
- [`eth_getBlockByHash`](https://www.dwellir.com/docs/iotex/eth_getBlockByHash) - Get block details by hash (without traces)
