Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
fix: make fetching logs from fork efficient
Browse files Browse the repository at this point in the history
  • Loading branch information
area committed Feb 20, 2023
1 parent e0bb8e3 commit 4a65345
Showing 1 changed file with 37 additions and 8 deletions.
45 changes: 37 additions & 8 deletions src/chains/ethereum/ethereum/src/data-managers/blocklog-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<BlockLogs> {
#blockchain: Blockchain;
Expand All @@ -28,6 +29,19 @@ export default class BlockLogManager extends Manager<BlockLogs> {
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<any[] | null>(
"eth_getLogs",
[{ address, topics, fromBlock: Quantity.from(fromBlockNumber), toBlock: Quantity.from(toBlockNumber) }]
);
return BlockLogs.fromJSON(res);

}

async getLogs(filter: FilterArgs): Promise<Ethereum.Logs> {
const blockchain = this.#blockchain;
if ("blockHash" in filter) {
Expand All @@ -44,19 +58,34 @@ export default class BlockLogManager extends Manager<BlockLogs> {
filter,
blockchain
);

const pendingLogsPromises: Promise<BlockLogs>[] = [
this.get(fromBlock.toBuffer())
];
const pendingLogsPromises: Promise<BlockLogs>[] = [];

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)
Expand Down

0 comments on commit 4a65345

Please sign in to comment.