Docs

eth_newBlockFilter - Robinhood RPC Method

Create a filter for new block notifications on Robinhood Chain. Essential for block monitoring, chain progression tracking, and reorg detection for tokenized assets, DeFi applications, historical state analysis, and EVM smart contracts.

Creates a filter on Robinhood Chain that notifies when new blocks arrive. Once created, poll the filter with eth_getFilterChanges to receive an array of block hashes for each new block added to the chain since your last poll.

Why Robinhood? Build on an Ethereum-compatible Layer 2 built with Arbitrum Nitro for tokenized real-world assets with Arbitrum Nitro compatibility, ETH gas, sub-second soft confirmations, archive history, and WebSocket access.

When to Use This Method

eth_newBlockFilter is essential for Robinhood Chain developers, financial application teams, and EVM builders:

  • Block Monitoring - Detect new blocks on Robinhood as they are mined or finalized, without repeatedly calling eth_blockNumber
  • Chain Progression Tracking - Build dashboards or alerting systems that track block production rate and timing
  • Reorg Detection - Identify chain reorganizations by monitoring for blocks that are replaced or missing
  • Event-Driven Architectures - Trigger downstream processing (indexing, notifications, settlement) whenever a new block appears

Best Practices

  • Use WebSocket subscriptions (eth_subscribe) for real-time block notifications in production environments
  • Poll with eth_getFilterChanges at 1-5 second intervals to receive new block hashes
  • Combine with eth_getBlockByNumber or eth_getBlockByHash to retrieve full block details

Robinhood backend affinity

Filter IDs are backend-local. The archive endpoint is served by multiple backends, so create, poll, and uninstall a filter over one persistent WebSocket connection. Separate HTTP requests can reach another backend and return filter not found. Use eth_getLogs for stateless historical log queries.

Code Examples

Common Use Cases

1. Block Production Rate Monitor

Track block times and detect slowdowns on Robinhood:

JavaScript
async function monitorBlockRate(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  let lastBlockTime = null;
  const blockTimes = [];

  setInterval(async () => {
    const blockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of blockHashes) {
      const block = await provider.getBlock(hash);
      const blockTime = block.timestamp;

      if (lastBlockTime) {
        const interval = blockTime - lastBlockTime;
        blockTimes.push(interval);

        // Keep last 100 block times
        if (blockTimes.length > 100) blockTimes.shift();

        const avgBlockTime = blockTimes.reduce((a, b) => a + b, 0) / blockTimes.length;
        console.log(`Block #${block.number} | interval: ${interval}s | avg: ${avgBlockTime.toFixed(1)}s`);

        if (interval > avgBlockTime * 3) {
          console.warn(`Slow block detected - ${interval}s vs ${avgBlockTime.toFixed(1)}s average`);
        }
      }
      lastBlockTime = blockTime;
    }
  }, 2000);
}

2. Reorg-Aware Block Tracker

Detect chain reorganizations by tracking block hashes:

JavaScript
async function trackBlocksWithReorgDetection(provider) {
  const filterId = await provider.send('eth_newBlockFilter', []);
  const blockHistory = new Map(); // blockNumber -> blockHash

  setInterval(async () => {
    const newBlockHashes = await provider.send('eth_getFilterChanges', [filterId]);

    for (const hash of newBlockHashes) {
      const block = await provider.getBlock(hash);
      const existingHash = blockHistory.get(block.number);

      if (existingHash && existingHash !== hash) {
        console.warn(`Reorg detected at block #${block.number}!`);
        console.warn(`  Old hash: ${existingHash}`);
        console.warn(`  New hash: ${hash}`);
        // Trigger reorg handling logic
      }

      blockHistory.set(block.number, hash);

      // Prune old entries
      if (blockHistory.size > 1000) {
        const minBlock = block.number - 500;
        for (const [num] of blockHistory) {
          if (num < minBlock) blockHistory.delete(num);
        }
      }
    }
  }, 2000);
}

3. Block-Triggered Task Scheduler

Execute tasks whenever a new block is produced:

JavaScript
async function onNewBlock(provider, callback) {
  const filterId = await provider.send('eth_newBlockFilter', []);

  const poll = async () => {
    try {
      const hashes = await provider.send('eth_getFilterChanges', [filterId]);
      for (const hash of hashes) {
        await callback(hash);
      }
    } catch (error) {
      if (error.message.includes('filter not found')) {
        return provider.send('eth_newBlockFilter', []).then(newId => {
          console.log('Block filter recreated');
          return newId;
        });
      }
      throw error;
    }
    return filterId;
  };

  let currentFilterId = filterId;
  setInterval(async () => {
    currentFilterId = await poll() || currentFilterId;
  }, 2000);
}

// Usage
onNewBlock(provider, async (blockHash) => {
  console.log(`Processing block: ${blockHash}`);
  // Run indexer, check conditions, send notifications, etc.
});

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32603Internal errorNode may not support filters - verify node capabilities
-32000Filter not foundFilter expired (~5 min inactivity) - recreate with eth_newBlockFilter
-32005Rate limit exceededReduce polling frequency or implement client-side rate limiting
-32601Method not foundNode does not support filter methods - use eth_blockNumber polling instead
JavaScript
async function createBlockFilterWithFallback(provider) {
  try {
    const filterId = await provider.send('eth_newBlockFilter', []);
    return { type: 'filter', id: filterId };
  } catch (error) {
    console.warn('Block filter not supported - falling back to polling');
    return { type: 'polling', lastBlock: await provider.getBlockNumber() };
  }
}