An indexer polls (or subscribes to) new blocks, extracts relevant transactions/events, and writes them into a database so an application can query rich, filtered data without hitting the node for every request.
js
async function pollBlocks(rpcCall, db, state) {
const latestHex = await rpcCall("eth_blockNumber");
const latest = parseInt(latestHex, 16);
for (let n = state.lastProcessed + 1; n <= latest; n++) {
const block = await rpcCall("eth_getBlockByNumber", [`0x${n.toString(16)}`, true]);
await db.saveBlock(block);
state.lastProcessed = n;
}
}
setInterval(() => pollBlocks(rpcCall, db, state).catch(console.error), 5000);Real indexers must also handle chain reorganizations (a previously-seen block being replaced) by re-checking recent block hashes and rolling back/re-applying affected data — naively assuming block numbers only ever increase leads to corrupted data after a reorg.