From 77729ccf191401545a55ed0f4fdf504e1bf4e68c Mon Sep 17 00:00:00 2001 From: Gerardo Nardelli Date: Tue, 7 May 2019 16:47:08 -0300 Subject: [PATCH] Add safe getPastEvents with variable block ranges --- alerts.js | 6 ++--- getShortEventStats.js | 53 +++++++++++++++++++++++++++++++---------- utils/contract.js | 50 ++++++++++++++++++++++++++++++++++++++ utils/events.js | 50 ++++++++++++++++++++++++++++---------- utils/validatorUtils.js | 11 +++++++-- validators.js | 10 ++++++-- 6 files changed, 148 insertions(+), 32 deletions(-) create mode 100644 utils/contract.js diff --git a/alerts.js b/alerts.js index 4c00d92..013a317 100644 --- a/alerts.js +++ b/alerts.js @@ -2,6 +2,7 @@ require('dotenv').config() const Web3 = require('web3') const logger = require('./logger')('alerts') const eventsInfo = require('./utils/events') +const { getBlockNumber } = require('./utils/contract') const { HOME_RPC_URL, FOREIGN_RPC_URL } = process.env @@ -24,10 +25,7 @@ async function main() { const xAffirmations = homeWithdrawals.filter(findDifferences(foreignWithdrawals)) logger.debug('building misbehavior blocks') - const getBlockNumber = web3 => web3.eth.getBlockNumber() - const [foreignBlockNumber, homeBlockNumber] = (await Promise.all( - [web3Foreign, web3Home].map(getBlockNumber) - )).map(Web3.utils.toBN) + const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign) const baseRange = [false, false, false, false, false] const xSignaturesMisbehavior = buildRangesObject( diff --git a/getShortEventStats.js b/getShortEventStats.js index 6d613b4..fac0edf 100644 --- a/getShortEventStats.js +++ b/getShortEventStats.js @@ -1,11 +1,12 @@ require('dotenv').config() const Web3 = require('web3') +const { toBN } = require('web3').utils const logger = require('./logger')('getShortEventStats.js') const { getBridgeABIs, BRIDGE_MODES, ERC_TYPES } = require('./utils/bridgeMode') const { HOME_RPC_URL, FOREIGN_RPC_URL, HOME_BRIDGE_ADDRESS, FOREIGN_BRIDGE_ADDRESS } = process.env -const HOME_DEPLOYMENT_BLOCK = Number(process.env.HOME_DEPLOYMENT_BLOCK) || 0 -const FOREIGN_DEPLOYMENT_BLOCK = Number(process.env.FOREIGN_DEPLOYMENT_BLOCK) || 0 +const HOME_DEPLOYMENT_BLOCK = toBN(Number(process.env.HOME_DEPLOYMENT_BLOCK) || 0) +const FOREIGN_DEPLOYMENT_BLOCK = toBN(Number(process.env.FOREIGN_DEPLOYMENT_BLOCK) || 0) const homeProvider = new Web3.providers.HttpProvider(HOME_RPC_URL) const web3Home = new Web3(homeProvider) @@ -15,6 +16,7 @@ const web3Foreign = new Web3(foreignProvider) const ERC20_ABI = require('./abis/ERC20.abi') const { getTokenType } = require('./utils/ercUtils') +const { getPastEvents, getBlockNumber } = require('./utils/contract') async function main(bridgeMode) { try { @@ -25,27 +27,54 @@ async function main(bridgeMode) { const erc20Address = await foreignBridge.methods[erc20MethodName]().call() const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address) const tokenType = await getTokenType(foreignBridge, FOREIGN_BRIDGE_ADDRESS) + + logger.debug('getting last block numbers') + const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign) logger.debug("calling homeBridge.getPastEvents('UserRequestForSignature')") - const homeDeposits = await homeBridge.getPastEvents('UserRequestForSignature', { - fromBlock: HOME_DEPLOYMENT_BLOCK + const homeDeposits = await getPastEvents({ + contract: homeBridge, + event: 'UserRequestForSignature', + fromBlock: HOME_DEPLOYMENT_BLOCK, + toBlock: homeBlockNumber, + options: {} }) + logger.debug("calling foreignBridge.getPastEvents('RelayedMessage')") - const foreignDeposits = await foreignBridge.getPastEvents('RelayedMessage', { - fromBlock: FOREIGN_DEPLOYMENT_BLOCK + const foreignDeposits = await getPastEvents({ + contract: foreignBridge, + event: 'RelayedMessage', + fromBlock: FOREIGN_DEPLOYMENT_BLOCK, + toBlock: foreignBlockNumber, + options: {} }) + logger.debug("calling homeBridge.getPastEvents('AffirmationCompleted')") - const homeWithdrawals = await homeBridge.getPastEvents('AffirmationCompleted', { - fromBlock: HOME_DEPLOYMENT_BLOCK + const homeWithdrawals = await getPastEvents({ + contract: homeBridge, + event: 'AffirmationCompleted', + fromBlock: HOME_DEPLOYMENT_BLOCK, + toBlock: homeBlockNumber, + options: {} }) + logger.debug("calling foreignBridge.getPastEvents('UserRequestForAffirmation')") const foreignWithdrawals = tokenType === ERC_TYPES.ERC20 - ? await erc20Contract.getPastEvents('Transfer', { + ? await getPastEvents({ + contract: erc20Contract, + event: 'Transfer', fromBlock: FOREIGN_DEPLOYMENT_BLOCK, - filter: { to: FOREIGN_BRIDGE_ADDRESS } + toBlock: foreignBlockNumber, + options: { + filter: { to: FOREIGN_BRIDGE_ADDRESS } + } }) - : await foreignBridge.getPastEvents('UserRequestForAffirmation', { - fromBlock: FOREIGN_DEPLOYMENT_BLOCK + : await getPastEvents({ + contract: foreignBridge, + event: 'UserRequestForAffirmation', + fromBlock: FOREIGN_DEPLOYMENT_BLOCK, + toBlock: foreignBlockNumber, + options: {} }) logger.debug('Done') return { diff --git a/utils/contract.js b/utils/contract.js new file mode 100644 index 0000000..c682f17 --- /dev/null +++ b/utils/contract.js @@ -0,0 +1,50 @@ +const { toBN } = require('web3').utils + +const ONE = toBN(1) +const TWO = toBN(2) + +async function getPastEvents({ contract, event, fromBlock, toBlock, options }) { + let events + try { + events = await contract.getPastEvents(event, { + ...options, + fromBlock, + toBlock + }) + } catch (e) { + if (e.message.includes('query returned more than 1000 results')) { + const middle = fromBlock.add(toBlock).divRound(TWO) + const middlePlusOne = middle.add(ONE) + + const firstHalfEvents = await getPastEvents({ + contract, + event, + fromBlock, + toBlock: middle, + options + }) + const secondHalfEvents = await getPastEvents({ + contract, + event, + fromBlock: middlePlusOne, + toBlock, + options + }) + events = [...firstHalfEvents, ...secondHalfEvents] + } else { + throw new Error(e) + } + } + return events +} + +const getBlockNumberCall = web3 => web3.eth.getBlockNumber() + +async function getBlockNumber(web3Home, web3Foreign) { + return (await Promise.all([web3Home, web3Foreign].map(getBlockNumberCall))).map(toBN) +} + +module.exports = { + getPastEvents, + getBlockNumber +} diff --git a/utils/events.js b/utils/events.js index e60dca2..238ea8a 100644 --- a/utils/events.js +++ b/utils/events.js @@ -1,12 +1,13 @@ require('dotenv').config() const Web3 = require('web3') +const { toBN } = require('web3').utils const logger = require('../logger')('eventsUtils') const { BRIDGE_MODES, decodeBridgeMode, getBridgeABIs, ERC_TYPES } = require('./bridgeMode') const { getTokenType } = require('./ercUtils') const { HOME_RPC_URL, FOREIGN_RPC_URL, HOME_BRIDGE_ADDRESS, FOREIGN_BRIDGE_ADDRESS } = process.env -const HOME_DEPLOYMENT_BLOCK = Number(process.env.HOME_DEPLOYMENT_BLOCK) || 0 -const FOREIGN_DEPLOYMENT_BLOCK = Number(process.env.FOREIGN_DEPLOYMENT_BLOCK) || 0 +const HOME_DEPLOYMENT_BLOCK = toBN(Number(process.env.HOME_DEPLOYMENT_BLOCK) || 0) +const FOREIGN_DEPLOYMENT_BLOCK = toBN(Number(process.env.FOREIGN_DEPLOYMENT_BLOCK) || 0) const homeProvider = new Web3.providers.HttpProvider(HOME_RPC_URL) const web3Home = new Web3(homeProvider) @@ -16,6 +17,7 @@ const web3Foreign = new Web3(foreignProvider) const HOME_ERC_TO_ERC_ABI = require('../abis/HomeBridgeErcToErc.abi') const ERC20_ABI = require('../abis/ERC20.abi') +const { getPastEvents, getBlockNumber } = require('./contract') async function main() { try { @@ -31,29 +33,53 @@ async function main() { const erc20Address = await foreignBridge.methods[erc20MethodName]().call() const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address) + logger.debug('getting last block numbers') + const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign) + logger.debug("calling homeBridge.getPastEvents('UserRequestForSignature')") - const homeDeposits = await homeBridge.getPastEvents('UserRequestForSignature', { - fromBlock: HOME_DEPLOYMENT_BLOCK + const homeDeposits = await getPastEvents({ + contract: homeBridge, + event: 'UserRequestForSignature', + fromBlock: HOME_DEPLOYMENT_BLOCK, + toBlock: homeBlockNumber, + options: {} }) logger.debug("calling foreignBridge.getPastEvents('RelayedMessage')") - const foreignDeposits = await foreignBridge.getPastEvents('RelayedMessage', { - fromBlock: FOREIGN_DEPLOYMENT_BLOCK + const foreignDeposits = await getPastEvents({ + contract: foreignBridge, + event: 'RelayedMessage', + fromBlock: FOREIGN_DEPLOYMENT_BLOCK, + toBlock: foreignBlockNumber, + options: {} }) logger.debug("calling homeBridge.getPastEvents('AffirmationCompleted')") - const homeWithdrawals = await homeBridge.getPastEvents('AffirmationCompleted', { - fromBlock: HOME_DEPLOYMENT_BLOCK + const homeWithdrawals = await getPastEvents({ + contract: homeBridge, + event: 'AffirmationCompleted', + fromBlock: HOME_DEPLOYMENT_BLOCK, + toBlock: homeBlockNumber, + options: {} }) logger.debug("calling foreignBridge.getPastEvents('UserRequestForAffirmation')") const foreignWithdrawals = isExternalErc20 - ? await erc20Contract.getPastEvents('Transfer', { + ? await getPastEvents({ + contract: erc20Contract, + event: 'Transfer', fromBlock: FOREIGN_DEPLOYMENT_BLOCK, - filter: { to: FOREIGN_BRIDGE_ADDRESS } + toBlock: foreignBlockNumber, + options: { + filter: { to: FOREIGN_BRIDGE_ADDRESS } + } }) - : await foreignBridge.getPastEvents('UserRequestForAffirmation', { - fromBlock: FOREIGN_DEPLOYMENT_BLOCK + : await getPastEvents({ + contract: foreignBridge, + event: 'UserRequestForAffirmation', + fromBlock: FOREIGN_DEPLOYMENT_BLOCK, + toBlock: foreignBlockNumber, + options: {} }) logger.debug('Done') return { diff --git a/utils/validatorUtils.js b/utils/validatorUtils.js index 29998fb..facb36e 100644 --- a/utils/validatorUtils.js +++ b/utils/validatorUtils.js @@ -2,6 +2,7 @@ const bridgeValidatorsAbi = require('../abis/BridgeValidators.abi') const logger = require('../logger')('validatorsUtils') +const { getPastEvents } = require('./contract') const parseValidatorEvent = event => { if ( @@ -51,7 +52,7 @@ const validatorList = async contract => { } } -const getValidatorList = async (address, eth, fromBlock) => { +const getValidatorList = async (address, eth, fromBlock, toBlock) => { logger.debug('getting validatorList') const validatorsContract = new eth.Contract(bridgeValidatorsAbi, address) const validators = await validatorList(validatorsContract) @@ -62,7 +63,13 @@ const getValidatorList = async (address, eth, fromBlock) => { logger.debug('getting validatorsEvents') const contract = new eth.Contract([], address) - const validatorsEvents = await contract.getPastEvents('allEvents', { fromBlock }) + const validatorsEvents = await getPastEvents({ + contract, + event: 'allEvents', + fromBlock, + toBlock, + options: {} + }) return processValidatorsEvents(validatorsEvents) } diff --git a/validators.js b/validators.js index de7fad0..2e6229c 100644 --- a/validators.js +++ b/validators.js @@ -4,6 +4,7 @@ const fetch = require('node-fetch') const logger = require('./logger')('validators') const { getBridgeABIs } = require('./utils/bridgeMode') const { getValidatorList } = require('./utils/validatorUtils') +const { getBlockNumber } = require('./utils/contract') const { HOME_RPC_URL, @@ -56,6 +57,9 @@ async function main(bridgeMode) { homeValidatorsAddress ) + logger.debug('getting last block numbers') + const [homeBlockNumber, foreignBlockNumber] = await getBlockNumber(web3Home, web3Foreign) + logger.debug('calling foreignBridge.methods.validatorContract().call()') const foreignValidatorsAddress = await foreignBridge.methods.validatorContract().call() const foreignBridgeValidators = new web3Foreign.eth.Contract( @@ -67,14 +71,16 @@ async function main(bridgeMode) { const foreignValidators = await getValidatorList( foreignValidatorsAddress, web3Foreign.eth, - FOREIGN_DEPLOYMENT_BLOCK + FOREIGN_DEPLOYMENT_BLOCK, + foreignBlockNumber ) logger.debug('calling homeBridgeValidators getValidatorList()') const homeValidators = await getValidatorList( homeValidatorsAddress, web3Home.eth, - HOME_DEPLOYMENT_BLOCK + HOME_DEPLOYMENT_BLOCK, + homeBlockNumber ) const homeBalances = {}