Docs

eth_newBlockFilter - IoTeX RPC Method

Create a filter for new block notifications on IoTeX. Essential for block monitoring, chain progression tracking, and reorg detection for decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data.

Creates a filter on IoTeX 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 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.

When to Use This Method

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

  • Block Monitoring — Detect new blocks on IoTeX 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

Code Examples

Common Use Cases

1. Block Production Rate Monitor

Track block times and detect slowdowns on IoTeX:

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() };
  }
}