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

Commit

Permalink
feat: get logs from a fork network directly
Browse files Browse the repository at this point in the history
  • Loading branch information
Andres Adjimann authored and MicaiahReid committed Jan 5, 2023
1 parent 3b2b474 commit 0db3e11
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 30 deletions.
81 changes: 51 additions & 30 deletions src/chains/ethereum/ethereum/src/data-managers/blocklog-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,38 +39,59 @@ export default class BlockLogManager extends Manager<BlockLogs> {

const logs = await this.get(blockNumber);
return logs ? [...logs.filter(addresses, topics)] : [];
} else {
const { addresses, topics, fromBlock, toBlockNumber } = parseFilter(
filter,
blockchain
);

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

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)));
}
}
}
const { addresses, topics, fromBlock, toBlock } = parseFilter(
filter,
blockchain
);
const from = Quantity.min(fromBlock, toBlock);
const fork = this.#blockchain.fallback;
if (!fork) {
return await this.getLocal(from.toNumber(), toBlock.toNumber(), filter);
}
const ret: Ethereum.Logs = [];
if (fork.isValidForkBlockNumber(from)) {
ret.push(...await this.getFromFork(from, Quantity.min(toBlock, fork.blockNumber), filter));
}
if (!fork.isValidForkBlockNumber(toBlock)) {
ret.push(...await this.getLocal(fork.blockNumber.toNumber() + 1, toBlock.toNumber(), filter));
}
return ret;
}

// now filter and compute all the blocks' blockLogs (in block order)
return Promise.all(pendingLogsPromises).then(blockLogsRange => {
const filteredBlockLogs: Ethereum.Logs = [];
blockLogsRange.forEach(blockLogs => {
// TODO(perf): this loops over all addresses for every block.
// Maybe make it loop only once?
// Issue: https://github.com/trufflesuite/ganache/issues/3482
if (blockLogs)
filteredBlockLogs.push(...blockLogs.filter(addresses, topics));
});
return filteredBlockLogs;
getLocal(from: number, toBlockNumber: number, filter: FilterArgs): Promise<Ethereum.Logs> {
const { addresses, topics } = parseFilter(filter, this.#blockchain);
const pendingLogsPromises: Promise<BlockLogs>[] = [];
for (let i = from; i <= toBlockNumber; i++) {
pendingLogsPromises.push(this.get(Quantity.toBuffer(i)));
}
return Promise.all(pendingLogsPromises).then(blockLogsRange => {
const filteredBlockLogs: Ethereum.Logs = [];
blockLogsRange.forEach(blockLogs => {
// TODO(perf): this loops over all addresses for every block.
// Maybe make it loop only once?
// Issue: https://github.com/trufflesuite/ganache/issues/3482
if (blockLogs)
filteredBlockLogs.push(...blockLogs.filter(addresses, topics));
});
return filteredBlockLogs;
});
}

async getFromFork(from: Quantity, to: Quantity, filter: FilterArgs): Promise<Ethereum.Logs> {
const { topics } = parseFilter(filter, this.#blockchain);
const f = this.#blockchain.fallback;
if (!f || !f.isValidForkBlockNumber(from)) {
return [];
}
return await f.request<Ethereum.Logs | null>(
"eth_getLogs",
[{
fromBlock: from,
toBlock: f.selectValidForkBlockNumber(to),
address: filter.address ? (Array.isArray(filter.address) ? filter.address : [filter.address]) : [],
topics
}]
);
}
}
8 changes: 8 additions & 0 deletions src/packages/utils/src/things/json-rpc/json-rpc-quantity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export class Quantity extends BaseJsonRpcType {
return new Quantity(value, nullable);
}

public static min(a: Quantity, b: Quantity) {
return a.toBigInt() < b.toBigInt() ? a : b;
}

public static max(a: Quantity, b: Quantity) {
return a.toBigInt() < b.toBigInt() ? b : a;
}

constructor(value: JsonRpcInputArg, nullable?: boolean) {
super(value);
if (value === "0x") {
Expand Down

0 comments on commit 0db3e11

Please sign in to comment.