site-activity-chain/src/utils/block.util.ts

61 lines
2.4 KiB
TypeScript

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
}
}