Docs
Docs
Home
Getting Started
Agent Tooling
CLI
Supported Chains
Acala
Aptos
Arbitrum
Arc
Asset Hub
Astar
Avalanche
Base
Berachain
Bifrost
Binance Smart Chain
Bittensor
Blast
Boba Network
Bridge Hub
Celo
Centrifuge
Chiliz
Cronos
Enjin
Ethereum
Etherlink
Flow EVM Gateway
Gnosis
Hydration
Hyperliquid
Immutable
Ink
IoTeX
Kusama
Linea
LISK
Manta Atlantic
Manta Pacific
Mantle
MegaETH
Monad
Movement
Neuroweb
opBNB
Optimism
Plasma
Polkadot
Polygon
Pulsechain
Robinhood
Ronin
Scroll
Sonic
Starknet
Taiko
Tempo
Sui
TRON
Unichain
Viction
World Chain
XDC Network
XX Network
Zetachain
zkSync Era
Zora
Supported ChainsPlasmaJSON-RPC APIDebug Methods

debug_traceBlockByNumber - Plasma RPC Method

Trace all transactions in a block by number on Plasma. Analyze gas consumption, debug state transitions, and inspect historical block execution.

Plasma RPC endpoint: endpoint URLs, plans and pricing.

Traces all transactions in a block on Plasma identified by its block number or tag. This is the most convenient block-tracing method - pass a block number or "latest" to get full execution traces of every transaction in that block.

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.

Archive Node Required

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_traceBlockByNumber is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

  • Historical Block Analysis - Trace transactions in any past block by number, enabling time-series analysis of Plasma execution patterns
  • Gas Consumption Patterns - Profile gas usage across all transactions in a block to understand network congestion and gas cost trends for stablecoin transfers, payment apps, and wallets that need 1 second confirmation
  • Debugging State Transitions - Inspect how every transaction in a block changed the global state, useful for verifying protocol upgrades and hard fork behavior
  • Automated Block Scanning - Iterate through block ranges by number to build analytics pipelines, detect anomalies, and index execution traces

Best Practices

  • Requires archive node access; not available on standard full nodes
  • Use the callTracer for faster execution when full opcode detail is not needed
  • A full trace of a dense block can be hundreds of megabytes in size
  • Paginate results and process traces in batches for large blocks
JSON-RPC request
{
  "jsonrpc": "2.0",
  "method": "debug_traceBlockByNumber",
  "params": [
    "latest",
    {
      "tracer": "callTracer"
    }
  ],
  "id": 1
}

Code Examples

Bash
# Trace latest block 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_traceBlockByNumber",
    "params": ["latest", {"tracer": "callTracer"}],
    "id": 1
  }'

# Trace specific block 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_traceBlockByNumber",
    "params": ["0xF4240", {"tracer": "prestateTracer"}],
    "id": 1
  }'

# Trace with default opcode tracer (minimal output)
curl -X POST https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "debug_traceBlockByNumber",
    "params": ["latest", {"disableStorage": true, "disableStack": true}],
    "id": 1
  }'

Common Use Cases

1. Historical Gas Consumption Analysis

Profile gas usage across a range of blocks on Plasma:

JavaScript
async function analyzeGasOverRange(provider, startBlock, endBlock) {
  const blockStats = [];

  for (let block = startBlock; block <= endBlock; block++) {
    const blockHex = '0x' + block.toString(16);
    const traces = await provider.send('debug_traceBlockByNumber', [
      blockHex,
      { tracer: 'callTracer' }
    ]);

    let totalGas = 0;
    let maxGas = 0;
    let revertCount = 0;

    for (const trace of traces) {
      const gasUsed = parseInt(trace.result.gasUsed, 16);
      totalGas += gasUsed;
      maxGas = Math.max(maxGas, gasUsed);
      if (trace.result.error) revertCount++;
    }

    blockStats.push({
      block,
      txCount: traces.length,
      totalGas,
      avgGas: traces.length > 0 ? Math.round(totalGas / traces.length) : 0,
      maxGas,
      revertCount
    });

    console.log(
      `Block ${block}: ${traces.length} txs, ${totalGas} total gas, ${revertCount} reverts`
    );
  }

  return blockStats;
}

2. Automated Block Scanner for Contract Interactions

Scan blocks for interactions with a specific contract on Plasma:

Python
import requests

def scan_blocks_for_contract(start_block, end_block, target_contract):
    target = target_contract.lower()
    interactions = []

    for block_num in range(start_block, end_block + 1):
        block_hex = hex(block_num)
        response = requests.post('https://api-plasma-mainnet.n.dwellir.com/YOUR_API_KEY', json={
            'jsonrpc': '2.0',
            'method': 'debug_traceBlockByNumber',
            'params': [block_hex, {'tracer': 'callTracer'}],
            'id': 1
        })
        traces = response.json()['result']

        for trace in traces:
            calls = flatten_calls(trace['result'])
            for call in calls:
                if call.get('to', '').lower() == target:
                    interactions.append({
                        'block': block_num,
                        'tx_hash': trace['txHash'],
                        'call_type': call['type'],
                        'from': call['from'],
                        'input': call['input'][:10],  # function selector
                        'gas_used': int(call.get('gasUsed', '0x0'), 16)
                    })

    print(f'Found {len(interactions)} interactions with {target_contract}')
    for i in interactions:
        print(f'  Block {i["block"]}: {i["tx_hash"]} [{i["call_type"]}] selector={i["input"]}')

    return interactions

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

3. Debugging State Transitions After Protocol Upgrades

Compare block execution before and after a hard fork or protocol upgrade:

JavaScript
async function compareBlockExecution(provider, forkBlock) {
  const preFork = '0x' + (forkBlock - 1).toString(16);
  const postFork = '0x' + forkBlock.toString(16);

  const [preTraces, postTraces] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { tracer: 'callTracer' }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { tracer: 'callTracer' }
    ])
  ]);

  console.log(`Pre-fork block ${forkBlock - 1}: ${preTraces.length} txs`);
  console.log(`Post-fork block ${forkBlock}: ${postTraces.length} txs`);

  // Analyze opcode-level differences for the first transaction in each
  const [preOpcodes, postOpcodes] = await Promise.all([
    provider.send('debug_traceBlockByNumber', [
      preFork,
      { disableStorage: true, enableReturnData: true }
    ]),
    provider.send('debug_traceBlockByNumber', [
      postFork,
      { disableStorage: true, enableReturnData: true }
    ])
  ]);

  // Check for new opcodes introduced after the fork
  const preOps = new Set();
  const postOps = new Set();

  for (const trace of preOpcodes) {
    for (const log of trace.result.structLogs || []) {
      preOps.add(log.op);
    }
  }

  for (const trace of postOpcodes) {
    for (const log of trace.result.structLogs || []) {
      postOps.add(log.op);
    }
  }

  const newOps = [...postOps].filter(op => !preOps.has(op));
  if (newOps.length > 0) {
    console.log('New opcodes observed after fork:', newOps);
  }
}

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32000Block not foundVerify the block number exists on Plasma - it may be in the future
-32000Missing trie nodeNode is not an archive node or state has been pruned - use an archive endpoint
-32601Method not foundDebug namespace is not enabled on the node
-32603Internal errorBlock may be too large to trace - increase timeout or use disableStorage
-32005Rate limit exceededReduce request frequency or upgrade your plan
-32602Invalid paramsCheck that the block number is a valid hex string or tag
JavaScript
async function safeTraceBlockByNumber(provider, blockNumber, options = {}) {
  const defaultOptions = {
    tracer: 'callTracer',
    timeout: '60s',
    ...options
  };

  try {
    return await provider.send('debug_traceBlockByNumber', [blockNumber, defaultOptions]);
  } catch (error) {
    if (error.code === -32601) {
      throw new Error('debug_traceBlockByNumber not available - ensure archive node with debug API');
    }
    if (error.code === -32000 && error.message?.includes('not found')) {
      throw new Error(`Block ${blockNumber} not found on Plasma`);
    }
    if (error.message?.includes('timeout')) {
      console.warn('Trace timed out - retrying with top-level calls only');
      return await provider.send('debug_traceBlockByNumber', [
        blockNumber,
        { tracer: 'callTracer', tracerConfig: { onlyTopCall: true } }
      ]);
    }
    throw error;
  }
}

Related Methods

  • debug_traceBlock - Trace all transactions using RLP-encoded block data
  • debug_traceBlockByHash - Trace all transactions in a block by hash
  • debug_traceTransaction - Trace a single transaction by hash
  • debug_traceCall - Trace a call without creating a transaction
  • eth_getBlockByNumber - Get block details by number (without traces)

debug_traceBlockByHash

Trace all transactions in a block by hash on Plasma. Investigate specific blocks, analyze execution order, and debug reverts with detailed traces.

debug_traceCall

Simulate a call on Plasma with debug_traceCall and get opcode, callTracer or prestateTracer output at any block, without sending a transaction.

On this page

When to Use This MethodBest PracticesCode ExamplesCommon Use Cases1. Historical Gas Consumption Analysis2. Automated Block Scanner for Contract Interactions3. Debugging State Transitions After Protocol UpgradesError HandlingRelated Methods