import { batchEthBlocks } from "chain/chain.api"; import logger from "logger/logger"; import { RedisClient } from "redis/RedisClient"; const MAX_BATCH_AMOUNT = 500 const REQUEST_INTERVAL = 0.5 * 1000 export async function divQueryPassBlocks({chainId, rpc, fromBlock, amount} : {chainId: number, rpc: string, fromBlock: number, amount: number}) { const middleBlock = fromBlock + Math.floor(amount / 2) const firstBlocks = await getPastBlocks({chainId, rpc, fromBlock, amount: middleBlock - fromBlock}) const secondBlocks = await getPastBlocks({chainId, rpc, fromBlock: middleBlock, amount: amount - (middleBlock - fromBlock)}) return [...firstBlocks, ...secondBlocks] } export async function getPastBlocks({chainId, rpc, fromBlock, amount} : {chainId: number, rpc: string, fromBlock: number, amount: number}) { let blocks = [] logger.log(`getPastBlocks: ${chainId} from: ${fromBlock} amount: ${amount}`) let blockNumber = fromBlock const redisKey = `blocknum_${chainId}` try { let res = await batchEthBlocks(rpc, blockNumber, amount) if (res.error) { throw new Error(res.error.message) } for (let i = 0; i < res.length; i++) { const block = res[i].result; if (block) { blocks.push(block) } } await new RedisClient().set(redisKey, blockNumber + amount + '') await new Promise(resolve => setTimeout(resolve, REQUEST_INTERVAL)) } catch (e) { logger.log(e.message || e) if (e.message && /Too Many Requests/.test(e.message) && amount > 1) { blocks = await divQueryPassBlocks({chainId, rpc, fromBlock, amount}) } else if (e.message && /Public RPC Rate Limit Hit, limit will reset in \d+ seconds/.test(e.message)) { const match = e.message.match(/Public RPC Rate Limit Hit, limit will reset in (\d+) seconds/) const seconds = parseInt(match[1]) await new Promise(resolve => setTimeout(resolve, seconds * 1000)) blocks = await getPastBlocks({chainId, rpc, fromBlock, amount}) }else { throw e } } return blocks } export function* getPastBlocksIter({chainId, rpc, fromBlock, amount} : {chainId: number, rpc: string, fromBlock: number, amount: number}) { logger.debug(`*getPastBlocksIter: ${chainId} from: ${fromBlock} amount: ${amount}`) let remain = amount while (remain > 0) { yield getPastBlocks({chainId, rpc, fromBlock, amount: Math.min(MAX_BATCH_AMOUNT, remain)}) fromBlock += MAX_BATCH_AMOUNT remain -= MAX_BATCH_AMOUNT } }