# debug_traceBlockByHash - Plasma RPC Method

Traces all transactions in a block on Plasma 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 Plasma?** Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

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 Plasma - ensure your plan includes debug namespace support.

## When to Use This Method

`debug_traceBlockByHash` is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

- **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 Plasma
- **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 stablecoin transfers, payment apps, and wallets that need 1 second confirmation
- **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": [
    "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
    {
      "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-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'

# Trace with prestate tracer
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByHash",
    "params": [
      "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07",
      {"tracer": "prestateTracer"}
    ],
    "id": 1
  }'
```

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

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

// 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-plasma-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 = '0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07'

# 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-plasma-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 := "0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07"

    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-plasma-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 Plasma:

```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 Plasma:

```python
import requests

def analyze_token_transfers(block_hash):
    response = requests.post('https://api-plasma-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('0xf8e25a8aece71a7a87e8aaefd242832cb0ce838ebbad206c48ca9e9f6b1a7a07')
```

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