diff --git a/constants/variables.js b/constants/variables.js index 35ab9b1..c4789f1 100644 --- a/constants/variables.js +++ b/constants/variables.js @@ -60,6 +60,22 @@ export const cachedEventsLength = { } } +export const corsConfig = (rpcUrl) => ({ + headers: [ + { + name: 'Access-Control-Allow-Origin', + value: rpcUrl + }, + { + name: 'Access-Control-Allow-Methods', + value: 'POST, GET, OPTIONS' + } + ], + withCredentials: false, + // buffer for tor connections + timeout: 30000 +}) + export const PROVIDERS = { walletConnect: { name: 'WalletConnect', diff --git a/services/events.js b/services/events.js index ff262c3..5bf6d71 100644 --- a/services/events.js +++ b/services/events.js @@ -4,7 +4,7 @@ import graph from '@/services/graph' import { download } from '@/store/snark' import networkConfig from '@/networkConfig' import InstanceABI from '@/abis/Instance.abi.json' -import { CONTRACT_INSTANCES, eventsType } from '@/constants' +import { CONTRACT_INSTANCES, eventsType, corsConfig } from '@/constants' import { sleep, flattenNArray, formatEvents, capitalizeFirstLetter } from '@/utils' const supportedCaches = ['1', '56', '100', '137'] @@ -441,23 +441,9 @@ class EventsFactory { instances = new Map() constructor(rpcUrl) { - this.provider = new Web3( - new Web3.providers.HttpProvider(rpcUrl, { - headers: [ - { - name: 'Access-Control-Allow-Origin', - value: rpcUrl - }, - { - name: 'Access-Control-Allow-Methods', - value: 'POST, GET, OPTIONS' - } - ], - withCredentials: false, - // buffer for tor connections - timeout: 30000 - }) - ).eth + const httpProvider = new Web3.providers.HttpProvider(rpcUrl, corsConfig(rpcUrl)) + + this.provider = new Web3(httpProvider).eth } getBlockNumber = () => { diff --git a/services/registry/index.js b/services/registry/index.js index cacaba4..29184e1 100644 --- a/services/registry/index.js +++ b/services/registry/index.js @@ -1,10 +1,11 @@ +import Web3 from 'web3' import namehash from 'eth-ens-namehash' import { BigNumber as BN } from 'bignumber.js' -import { toChecksumAddress } from 'web3-utils' +import { toChecksumAddress, isAddress } from 'web3-utils' -import { graph } from '@/services' import networkConfig from '@/networkConfig' -import { REGISTRY_DEPLOYED_BLOCK } from '@/constants' +import { REGISTRY_DEPLOYED_BLOCK, corsConfig } from '@/constants' +import { sleep, flattenNArray } from '@/utils' import AggregatorABI from '@/abis/Aggregator.abi.json' import RelayerRegistryABI from '@/abis/RelayerRegistry.abi.json' @@ -24,28 +25,52 @@ class RelayerRegister { this.relayerRegistry = new this.provider.Contract(RelayerRegistryABI, registryContract) } - fetchEvents = async (fromBlock, toBlock) => { + fetchEvents = ({ fromBlock, toBlock }) => { if (fromBlock <= toBlock) { - try { - const registeredEventsPart = await this.relayerRegistry.getPastEvents('RelayerRegistered', { - fromBlock, - toBlock - }) + return new Promise((resolve, reject) => { + try { + const registeredEventsPart = this.relayerRegistry.getPastEvents('RelayerRegistered', { + fromBlock, + toBlock + }) - return registeredEventsPart - } catch (error) { - const midBlock = (fromBlock + toBlock) >> 1 + resolve(registeredEventsPart) + } catch (error) { + sleep(200) - if (midBlock - fromBlock < 2) { - throw new Error(`error fetching events: ${error.message}`) + const midBlock = (fromBlock + toBlock) >> 1 + + if (midBlock - fromBlock < 2) { + reject(new Error(`error fetching events: ${error.message}`)) + } + + const arr1 = this.fetchEvents({ fromBlock, toBlock: midBlock }) + const arr2 = this.fetchEvents({ fromBlock: midBlock + 1, toBlock }) + resolve([...arr1, ...arr2]) } - - const arr1 = await this.fetchEvents(fromBlock, midBlock) - const arr2 = await this.fetchEvents(midBlock + 1, toBlock) - return [...arr1, ...arr2] - } + }) + } else { + return [] } - return [] + } + + batchFetchEvents = async ({ fromBlock, toBlock }) => { + const blockRange = 10000 + const blockDifference = toBlock - fromBlock + const chunkCount = Math.ceil(blockDifference / blockRange) + const blockDenom = Math.ceil(blockDifference / chunkCount) + + const promises = new Array(chunkCount).fill('').map((_, i) => + this.fetchEvents({ + fromBlock: i * blockDenom + fromBlock, + toBlock: (i + 1) * blockDenom + fromBlock + }) + ) + + const batchEvents = flattenNArray(await Promise.all(promises)) + const events = batchEvents.map((e) => ({ ...e.returnValues })) + + return events } saveEvents = async ({ events, lastSyncBlock, storeName }) => { @@ -96,51 +121,73 @@ class RelayerRegister { } } + getENSAddress = async (ensName) => { + const { url } = Object.values(networkConfig.netId1.rpcUrls)[0] + const httpProvider = new Web3.providers.HttpProvider(url, corsConfig(url)) + const provider = new Web3(httpProvider) + + const ensAddress = await provider.eth.ens.getAddress(ensName) + + return ensAddress + } + fetchRelayers = async () => { + const blockRange = 10000 // eslint-disable-next-line prefer-const - let { blockFrom, blockTo, cachedEvents } = await this.getCachedData() + let { blockTo, cachedEvents } = await this.getCachedData() let allRelayers = cachedEvents - if (blockFrom !== blockTo) { - const registeredRelayersEvents = await graph.getAllRegisters(blockFrom) + const currentBlockNumber = await this.provider.getBlockNumber() + const fromBlock = cachedEvents.length === 0 ? REGISTRY_DEPLOYED_BLOCK[1] : blockTo + const blockDifference = currentBlockNumber - fromBlock - let relayers = { - lastSyncBlock: registeredRelayersEvents.lastSyncBlock, - events: registeredRelayersEvents.events.map((el) => ({ - ensName: el.ensName, - relayerAddress: toChecksumAddress(el.address) - })) + try { + let toBlock + let registerRelayerEvents + let lastBlock + + if (cachedEvents.length > 0 || blockDifference === 0) { + return cachedEvents + } else if (blockDifference >= blockRange) { + toBlock = currentBlockNumber + registerRelayerEvents = await this.batchFetchEvents({ fromBlock, toBlock }) + lastBlock = toBlock + } else { + toBlock = fromBlock + blockRange + registerRelayerEvents = await this.fetchEvents({ fromBlock, toBlock }) + lastBlock = toBlock } - const isGraphLate = relayers.lastSyncBlock && blockTo > Number(relayers.lastSyncBlock) + const lastIndex = registerRelayerEvents.length - 1 + const lastSyncBlock = registerRelayerEvents[lastIndex]?.blockNumber || lastBlock + const relayerEvents = cachedEvents.concat(registerRelayerEvents || []) - if (isGraphLate) { - blockFrom = relayers.lastSyncBlock - } + const events = [] - if (!relayers.events.length || isGraphLate) { - const multicallEvents = await this.fetchEvents(blockFrom, blockTo) - const eventsRelayers = multicallEvents.map(({ returnValues }) => ({ - ensName: returnValues.ensName, - relayerAddress: returnValues.relayerAddress - })) - - relayers = { - lastSyncBlock: blockTo, - events: relayers.events.concat(eventsRelayers) + for (let x = 0; x < relayerEvents.length; x++) { + const { ensName, relayerAddress } = relayerEvents[x] + let ensAddress + if (!isAddress(relayerAddress)) { + ensAddress = await this.getENSAddress(ensName) + ensAddress = toChecksumAddress(ensAddress) + } else { + ensAddress = relayerAddress } + + events.push({ ensName, relayerAddress: ensAddress }) } - await this.saveEvents({ storeName: 'register_events', ...relayers }) - allRelayers = allRelayers.concat(relayers.events) - } + await this.saveEvents({ storeName: 'register_events', lastSyncBlock, events }) + allRelayers = allRelayers.concat(events) + } catch (e) { + return cachedEvents + } return allRelayers } filterRelayer = (acc, curr, ensSubdomainKey, relayer) => { const subdomainIndex = subdomains.indexOf(ensSubdomainKey) - const mainnetSubdomain = curr.records[0] const hostname = curr.records[subdomainIndex] const isHostWithProtocol = hostname.includes('http') @@ -191,7 +238,6 @@ class RelayerRegister { getRelayers = async (ensSubdomainKey) => { const relayers = await this.fetchRelayers() - const validRelayers = await this.getValidRelayers(relayers, ensSubdomainKey) return validRelayers