61 lines
2.4 KiB
TypeScript
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
|
|
}
|
|
}
|