mirror of
https://github.com/logos-messaging/js-rln.git
synced 2026-01-04 22:53:12 +00:00
feat: add custom queryFilter (#57)
* add custom fetcher * improve fetch in chunks * remove comment * fetch in portions of 5 * allow to configure fetch params * add error log
This commit is contained in:
parent
88a28a11e3
commit
7e0966aef7
@ -13,6 +13,12 @@ type ContractOptions = {
|
||||
provider: ethers.Signer | ethers.providers.Provider;
|
||||
};
|
||||
|
||||
type FetchMembersOptions = {
|
||||
fromBlock?: number;
|
||||
fetchRange?: number;
|
||||
fetchChunks?: number;
|
||||
};
|
||||
|
||||
export class RLNContract {
|
||||
private _contract: ethers.Contract;
|
||||
private membersFilter: ethers.EventFilter;
|
||||
@ -46,12 +52,12 @@ export class RLNContract {
|
||||
|
||||
public async fetchMembers(
|
||||
rlnInstance: RLNInstance,
|
||||
fromBlock?: number
|
||||
options: FetchMembersOptions = {}
|
||||
): Promise<void> {
|
||||
const registeredMemberEvents = await this.contract.queryFilter(
|
||||
this.membersFilter,
|
||||
fromBlock
|
||||
);
|
||||
const registeredMemberEvents = await queryFilter(this.contract, {
|
||||
...options,
|
||||
membersFilter: this.membersFilter,
|
||||
});
|
||||
|
||||
for (const event of registeredMemberEvents) {
|
||||
this.addMemberFromEvent(rlnInstance, event);
|
||||
@ -109,3 +115,90 @@ export class RLNContract {
|
||||
return txRegisterReceipt?.events?.[0];
|
||||
}
|
||||
}
|
||||
|
||||
type CustomQueryOptions = FetchMembersOptions & {
|
||||
membersFilter: ethers.EventFilter;
|
||||
};
|
||||
|
||||
// these value should be tested on other networks
|
||||
const FETCH_CHUNK = 5;
|
||||
const BLOCK_RANGE = 3000;
|
||||
|
||||
async function queryFilter(
|
||||
contract: ethers.Contract,
|
||||
options: CustomQueryOptions
|
||||
): Promise<ethers.Event[]> {
|
||||
const {
|
||||
fromBlock,
|
||||
membersFilter,
|
||||
fetchRange = BLOCK_RANGE,
|
||||
fetchChunks = FETCH_CHUNK,
|
||||
} = options;
|
||||
|
||||
if (!fromBlock) {
|
||||
return contract.queryFilter(membersFilter);
|
||||
}
|
||||
|
||||
if (!contract.signer.provider) {
|
||||
throw Error("No provider found on the contract's signer.");
|
||||
}
|
||||
|
||||
const toBlock = await contract.signer.provider.getBlockNumber();
|
||||
|
||||
if (toBlock - fromBlock < fetchRange) {
|
||||
return contract.queryFilter(membersFilter);
|
||||
}
|
||||
|
||||
const events: ethers.Event[][] = [];
|
||||
const chunks = splitToChunks(fromBlock, toBlock, fetchRange);
|
||||
|
||||
for (const portion of takeN<[number, number]>(chunks, fetchChunks)) {
|
||||
const promises = portion.map(([left, right]) =>
|
||||
ignoreErrors(contract.queryFilter(membersFilter, left, right), [])
|
||||
);
|
||||
const fetchedEvents = await Promise.all(promises);
|
||||
events.push(fetchedEvents.flatMap((v) => v));
|
||||
}
|
||||
|
||||
return events.flatMap((v) => v);
|
||||
}
|
||||
|
||||
function splitToChunks(
|
||||
from: number,
|
||||
to: number,
|
||||
step: number
|
||||
): Array<[number, number]> {
|
||||
const chunks = [];
|
||||
|
||||
let left = from;
|
||||
while (left < to) {
|
||||
const right = left + step < to ? left + step : to;
|
||||
|
||||
chunks.push([left, right] as [number, number]);
|
||||
|
||||
left = right;
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function* takeN<T>(array: T[], size: number): Iterable<T[]> {
|
||||
let start = 0;
|
||||
let skip = size;
|
||||
|
||||
while (skip < array.length) {
|
||||
const portion = array.slice(start, skip);
|
||||
|
||||
yield portion;
|
||||
|
||||
start = skip;
|
||||
skip += size;
|
||||
}
|
||||
}
|
||||
|
||||
function ignoreErrors<T>(promise: Promise<T>, defaultValue: T): Promise<T> {
|
||||
return promise.catch((err) => {
|
||||
console.error(`Ignoring an error during query: ${err?.message}`);
|
||||
return defaultValue;
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user