From 89bc7f37dade1fbd6f840b0f92f504834a2ce484 Mon Sep 17 00:00:00 2001 From: Alex Rea Date: Mon, 20 Feb 2023 14:37:28 +0000 Subject: [PATCH] Make fetching logs from fork efficient --- .../src/data-managers/blocklog-manager.ts | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/chains/ethereum/ethereum/src/data-managers/blocklog-manager.ts b/src/chains/ethereum/ethereum/src/data-managers/blocklog-manager.ts index dd32185f85..f13491e607 100644 --- a/src/chains/ethereum/ethereum/src/data-managers/blocklog-manager.ts +++ b/src/chains/ethereum/ethereum/src/data-managers/blocklog-manager.ts @@ -5,6 +5,7 @@ import Blockchain from "../blockchain"; import { parseFilter, parseFilterDetails } from "../helpers/filter-parsing"; import { Ethereum } from "../api-types"; import { GanacheLevelUp } from "../database"; +type Topic = string | string[]; export default class BlockLogManager extends Manager { #blockchain: Blockchain; @@ -28,6 +29,19 @@ export default class BlockLogManager extends Manager { return log; } + async getRange(fromBlockNumber: string | Buffer, toBlockNumber: string | Buffer, topics: Topic[], address: String | String[]) { + const blockchain = this.#blockchain; + if (!blockchain.fallback){ + throw new Error("Not a forked instance"); + } + const res = await this.#blockchain.fallback.request( + "eth_getLogs", + [{ address, topics, fromBlock: Quantity.from(fromBlockNumber), toBlock: Quantity.from(toBlockNumber) }] + ); + return BlockLogs.fromJSON(res); + + } + async getLogs(filter: FilterArgs): Promise { const blockchain = this.#blockchain; if ("blockHash" in filter) { @@ -44,19 +58,34 @@ export default class BlockLogManager extends Manager { filter, blockchain ); - - const pendingLogsPromises: Promise[] = [ - this.get(fromBlock.toBuffer()) - ]; + const pendingLogsPromises: Promise[] = []; const fromBlockNumber = fromBlock.toNumber(); // if we have a range of blocks to search, do that here: if (fromBlockNumber !== toBlockNumber) { - // fetch all the blockLogs in-between `fromBlock` and `toBlock` (excluding - // from, because we already started fetching that one) - for (let i = fromBlockNumber + 1, l = toBlockNumber + 1; i < l; i++) { - pendingLogsPromises.push(this.get(Quantity.toBuffer(i))); + if ( + !blockchain.fallback || // We're not a forked chain + blockchain.fallback.blockNumber < fromBlock // Or we are, but only querying post-fork + ) { + // fetch all the blockLogs in-between `fromBlock` and `toBlock` + for (let i = fromBlockNumber, l = toBlockNumber + 1; i < l; i++) { + pendingLogsPromises.push(this.get(Quantity.toBuffer(i))); + } + } else { + // Fetch all the logs from fromBlockNumber to forkBlock in one request + let addressesAsStrings: String[]|String; + if (Array.isArray(addresses)){ + addressesAsStrings = addresses.map(x => `0x${x.toString('hex')}`) + } + pendingLogsPromises.push(this.getRange(Quantity.from(fromBlockNumber).toString(), Quantity.from(toBlockNumber).toString(), topics, addressesAsStrings )); + // fetch all the blockLogs in-between `forkBlock` + 1 and `toBlock` locally in the + // way that we normally do + for (let i = blockchain.fallback.blockNumber.toNumber() + 1, l = toBlockNumber + 1; i < l; i++) { + pendingLogsPromises.push(this.get(Quantity.toBuffer(i))); + } } + } else { + pendingLogsPromises.push(this.get(Quantity.toBuffer(fromBlockNumber))); } // now filter and compute all the blocks' blockLogs (in block order)