# debug_traceBlock - Hyperliquid RPC Method

Traces all transactions in a block on Hyperliquid by accepting a serialized block payload. Returns detailed execution traces for every transaction in the block, including opcode-level steps, gas consumption, and internal calls.

> **Why Hyperliquid?** Build on the trading-focused EVM and HyperCore ecosystem built for onchain perpetuals and market data with HyperCore market structure, sub-second finality, and direct access to trading-focused data services.

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

## When to Use This Method

`debug_traceBlock` is valuable for derivatives traders, DeFi protocols, and teams building high-frequency trading applications:

- **Block-Level Debugging** - Trace every transaction in a block simultaneously when you have the serialized block payload, useful for offline analysis or replaying captured block data
- **Gas Profiling Across Transactions** - Measure gas consumption per opcode across all transactions in a block to identify expensive patterns on Hyperliquid
- **MEV Analysis** - Analyze transaction ordering, sandwich attacks, and arbitrage patterns by tracing full block execution for perpetual futures trading, onchain order books, and institutional-grade derivatives
- **Protocol Research** - Replay historical blocks from RLP data to study state transitions and EVM behavior

## Best Practices

- Requires archive node access; not available on standard full nodes
- Block traces can be very resource-intensive on densely packed blocks
- Consider tracing individual transactions instead for targeted analysis
- Prefer debug\_traceBlockByNumber or debug\_traceBlockByHash for simpler workflows

## Request Parameters

- `blockPayload` (`DATA, required`): Serialized block payload as a hex string
- `tracerConfig` (`Object, optional`): Tracer configuration object (see options below)

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlock",
  "params": [
    "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
    {
      "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
- `gas` (`QUANTITY, required`): Gas provided
- `returnValue` (`DATA, required`): Return value of the call
- `structLogs` (`Array, required`): Array of opcode execution steps
- `structLogs[].pc` (`QUANTITY, required`): Program counter
- `structLogs[].op` (`string, required`): Opcode name
- `structLogs[].gas` (`QUANTITY, required`): Remaining gas
- `structLogs[].gasCost` (`QUANTITY, required`): Gas cost of this opcode
- `structLogs[].depth` (`QUANTITY, required`): Call depth
- `type` (`string, required`): Call type (CALL, DELEGATECALL, STATICCALL, CREATE)
- `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
- `calls` (`Array, required`): Sub-calls made during execution

## 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": "DELEGATECALL",
            "from": "0x1234567890abcdef1234567890abcdef12345678",
            "to": "0xfedcba0987654321fedcba0987654321fedcba09",
            "gas": "0x1a5b4",
            "gasUsed": "0x9c40",
            "input": "0xa9059cbb...",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
          }
        ]
      }
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

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

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlock",
    "params": [
      "0xf90217a0...SERIALIZED_BLOCK_PAYLOAD",
      {"tracer": "callTracer"}
    ],
    "id": 1
  }'
```

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

const provider = new JsonRpcProvider('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY');

// First, obtain the serialized block payload from your tracing workflow
// Then trace all transactions in the block
const blockRlp = '0xf90217a0...'; // Serialized block payload

// Trace with call tracer
const traces = await provider.send('debug_traceBlock', [
  blockRlp,
  { tracer: 'callTracer' }
]);

for (const trace of traces) {
  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)}`);
}

// Trace with default opcode tracer (verbose output)
const opcodeTraces = await provider.send('debug_traceBlock', [
  blockRlp,
  { disableStorage: true, disableStack: false }
]);

for (const trace of opcodeTraces) {
  console.log(`Tx: ${trace.txHash}, Opcodes: ${trace.result.structLogs.length}`);
}
```

```python
import requests
import json

def trace_block_by_rlp(rlp_data, tracer='callTracer'):
    response = requests.post(
        'https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlock',
            'params': [rlp_data, {'tracer': tracer}],
            'id': 1
        }
    )
    return response.json()['result']

# Trace all transactions in a block
block_rlp = '0xf90217a0...'  # Serialized block payload
traces = trace_block_by_rlp(block_rlp)

for trace in traces:
    tx_hash = trace.get('txHash', 'unknown')
    result = trace['result']
    gas_used = int(result['gasUsed'], 16)
    print(f'Tx {tx_hash}: {result["type"]} | Gas: {gas_used}')

    # Print sub-calls
    for call in result.get('calls', []):
        print(f'  -> {call["type"]} to {call["to"]}')

# Using web3.py
from web3 import Web3

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

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

```go
package main

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

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"`
    Calls   []CallTrace `json:"calls"`
}

func main() {
    blockRlp := "0xf90217a0..." // Serialized block payload

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

    body, _ := json.Marshal(payload)
    resp, err := http.Post("https://api-hyperliquid-mainnet-evm.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)

    for _, trace := range response.Result {
        fmt.Printf("Tx: %s | Type: %s | Gas: %s\n",
            trace.TxHash, trace.Result.Type, trace.Result.GasUsed)
    }
}
```

## Common Use Cases

### 1. Block-Level Gas Profiling

Analyze gas consumption across all transactions in a block on Hyperliquid:

```javascript
async function profileBlockGas(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  let totalGas = 0;
  const txGas = [];

  for (const trace of traces) {
    const gasUsed = parseInt(trace.result.gasUsed, 16);
    totalGas += gasUsed;
    txGas.push({
      txHash: trace.txHash,
      gasUsed,
      type: trace.result.type,
      hasSubCalls: (trace.result.calls || []).length > 0
    });
  }

  // Sort by gas usage
  txGas.sort((a, b) => b.gasUsed - a.gasUsed);

  console.log(`Block total gas: ${totalGas}`);
  console.log('Top gas consumers:');
  for (const tx of txGas.slice(0, 5)) {
    const pct = ((tx.gasUsed / totalGas) * 100).toFixed(1);
    console.log(`  ${tx.txHash}: ${tx.gasUsed} gas (${pct}%)`);
  }

  return { totalGas, txGas };
}
```

### 2. MEV Detection and Analysis

Detect sandwich attacks and arbitrage in Hyperliquid blocks:

```javascript
async function detectMEVPatterns(provider, blockRlp) {
  const traces = await provider.send('debug_traceBlock', [
    blockRlp,
    { tracer: 'callTracer' }
  ]);

  const dexInteractions = [];

  for (let i = 0; i < traces.length; i++) {
    const trace = traces[i];
    const calls = flattenCalls(trace.result);

    for (const call of calls) {
      // Detect swap-like function selectors (e.g., Uniswap swapExactTokensForTokens)
      if (call.input && call.input.startsWith('0x38ed1739')) {
        dexInteractions.push({
          index: i,
          txHash: trace.txHash,
          to: call.to,
          type: 'swap'
        });
      }
    }
  }

  // Check for sandwich patterns (swap-X-swap by same sender)
  for (let i = 0; i < dexInteractions.length - 2; i++) {
    const first = dexInteractions[i];
    const last = dexInteractions[i + 2];
    if (first.txHash !== last.txHash &&
        traces[first.index].result.from === traces[last.index].result.from) {
      console.log(`Potential sandwich: tx ${first.index} and ${last.index}`);
    }
  }

  return dexInteractions;
}

function flattenCalls(trace) {
  const calls = [trace];
  for (const sub of trace.calls || []) {
    calls.push(...flattenCalls(sub));
  }
  return calls;
}
```

### 3. Comparing Block Execution Across Clients

Verify consistent execution by tracing the same block RLP on different clients:

```python
import requests

def trace_on_endpoint(endpoint, block_rlp):
    response = requests.post(endpoint, json={
        'jsonrpc': '2.0',
        'method': 'debug_traceBlock',
        'params': [block_rlp, {'tracer': 'callTracer'}],
        'id': 1
    })
    return response.json()['result']

# Compare traces from two different endpoints
block_rlp = '0xf90217a0...'
traces_a = trace_on_endpoint('https://api-hyperliquid-mainnet-evm.n.dwellir.com/YOUR_API_KEY', block_rlp)
traces_b = trace_on_endpoint('https://other-endpoint.example.com', block_rlp)

# Verify same number of traces
assert len(traces_a) == len(traces_b), 'Transaction count mismatch'

# Compare gas usage per transaction
for i, (a, b) in enumerate(zip(traces_a, traces_b)):
    gas_a = int(a['result']['gasUsed'], 16)
    gas_b = int(b['result']['gasUsed'], 16)
    if gas_a != gas_b:
        print(f'Gas mismatch at tx {i}: {gas_a} vs {gas_b}')
    else:
        print(f'Tx {i}: {gas_a} gas (consistent)')
```

## Related Methods

- [`debug_traceBlockByHash`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByHash) - Trace all transactions in a block by hash (more commonly used)
- [`debug_traceBlockByNumber`](https://www.dwellir.com/docs/hyperliquid/debug_traceBlockByNumber) - Trace all transactions in a block by number
- [`debug_traceTransaction`](https://www.dwellir.com/docs/hyperliquid/debug_traceTransaction) - Trace a single transaction by hash
- [`debug_traceCall`](https://www.dwellir.com/docs/hyperliquid/debug_traceCall) - Trace a call without creating a transaction
