From f1eea79cd9c8681329735ddfea0128620853d144 Mon Sep 17 00:00:00 2001 From: KarishmaBothara Date: Thu, 19 May 2022 14:17:15 +1200 Subject: [PATCH] Update the relayer to work with new image + old image (#87) Restart pod when event proof is not found --- .github/workflows/image-builder.yml | 1 + README.md | 2 +- scripts/subscribeEventProof.js | 181 +++++++++++----------------- 3 files changed, 72 insertions(+), 112 deletions(-) diff --git a/.github/workflows/image-builder.yml b/.github/workflows/image-builder.yml index 7139469..abc6eea 100644 --- a/.github/workflows/image-builder.yml +++ b/.github/workflows/image-builder.yml @@ -6,6 +6,7 @@ on: push: branches: - "main" + - "azalea" paths: - "**.js" - "**.json" diff --git a/README.md b/README.md index c21427d..10c86b9 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ const ROPSTEN_V1 = { const ROPSTEN_V2 = { bridge: "0x452b8dd7b00D51e48cEF6254a48B7426d44658B8", peg: "0x4C411B3Bf36D6DE908C6f4256a72B85E3f2B00bF", - wcennz: "0xcdA767469D434c14D320e1A78D5b612B72B52bf0", + wcennz: "0x673F0244bd0AEbd9918ef089f75C503Df9bfBb38", } ``` diff --git a/scripts/subscribeEventProof.js b/scripts/subscribeEventProof.js index c7ea683..5ce3fac 100644 --- a/scripts/subscribeEventProof.js +++ b/scripts/subscribeEventProof.js @@ -4,11 +4,11 @@ require("dotenv").config(); const logger = require('./logger'); const { curly } = require("node-libcurl"); const mongoose = require('mongoose'); -const { EventProcessed, LastBlockScan } = require('../src/mongo/models'); +const { EventProcessed } = require('../src/mongo/models'); const ethers = require('ethers'); const bridgeAbi = require("../abi/CENNZnetBridge.json").abi; -const timeoutMs = 20000; +const timeoutMs = 40000; const BUFFER = 1000; // Ignore if validator public key is 0x000.. const IGNORE_KEY = '0x000000000000000000000000000000000000000000000000000000000000000000'; @@ -60,62 +60,62 @@ async function sendSlackNotification(message) { // Submit the event proof on Ethereum Bridge contract async function getEventPoofAndSubmit(api, eventId, bridge, txExecutor, newValidatorSetId, blockHash, provider) { const eventExistsOnEth = await bridge.eventIds(eventId.toString()); + if (eventExistsOnEth) return; // return if event proof already exist on Ethereum const eventProof = await withTimeout(api.derive.ethBridge.eventProof(eventId), timeoutMs); - if (eventProof && !eventExistsOnEth) { - const newValidators = await extractNewValidators(api, blockHash); - logger.info(`IMP Sending setValidators tx with the account: ${txExecutor.address}`); - logger.info(`IMP Parameters :::`); - logger.info(`IMP newValidators:${newValidators}`); - logger.info(`IMP newValidatorSetId: ${newValidatorSetId}`); - logger.info(`IMP event proof::${JSON.stringify(eventProof)}`); - const currentValidators = await extractCurrentValidators(api, blockHash); - logger.info(`IMP currentValidators:${currentValidators}`); - const proof = { - eventId: eventProof.eventId, - validatorSetId: eventProof.validatorSetId, - r: eventProof.r, - s: eventProof.s, - v: eventProof.v, - validators: currentValidators - }; - try { - const gasPrice = await provider.getGasPrice(); - logger.info('gas price::', gasPrice.toString()); - // Take 5 percent of current gas price - const percentGasPrice = gasPrice.mul(5).div(100); - logger.info('percentGasPrice:',percentGasPrice.toString()); - const increasedGasPrice = gasPrice.add(percentGasPrice); - logger.info('Gas price nw;:', gasPrice.toString()); - - const gasEstimated = await bridge.estimateGas.setValidators(newValidators, newValidatorSetId, proof, {gasLimit: 5000000, gasPrice: increasedGasPrice}); - const tx = await bridge.setValidators(newValidators, newValidatorSetId, proof, {gasLimit: gasEstimated.add(BUFFER), gasPrice: increasedGasPrice}); - await tx.wait(); // wait till tx is mined - logger.info(JSON.stringify(tx)); - await updateLastEventProcessed(eventId, blockHash.toString()); - const balance = await provider.getBalance(txExecutor.address); - logger.info(`IMP Balance is: ${balance}`); - - logger.info(`IMP Gas price: ${gasPrice.toString()}`); - const gasRequired = gasEstimated.mul(gasPrice); - logger.info(`IMP Gas required: ${gasRequired.toString()}`); - if (balance.lt(gasRequired.mul(2))) { - const message = ` 🚨 To keep the validator relayer running, topup the eth account ${txExecutor.address} on CENNZnets ${process.env.NETWORK} chain`; - await sendSlackNotification(message); - } - } catch (e) { - logger.warn('Something went wrong:'); - logger.error(`IMP Error: ${e.stack}`); - // send slack notification when proof submission fails - const message = ` 🚨 Issue while submitting validator set on ethereum bridge - proof: ${JSON.stringify(proof)} - newValidators: ${newValidators} - newValidatorSetId: ${newValidatorSetId} - on CENNZnets ${process.env.NETWORK} chain`; - await sendSlackNotification(message); - } - } else if (!eventProof){ + if (!eventProof) { logger.info(`IMP Could not retrieve event proof for event id ${eventId} from derived query api.derive.ethBridge.eventProof at ${timeoutMs} timeout`); + process.exit(1); + } + const newValidators = await extractNewValidators(api, blockHash); + logger.info(`IMP Sending setValidators tx with the account: ${txExecutor.address}`); + logger.info(`IMP Parameters :::`); + logger.info(`IMP newValidators:${newValidators}`); + logger.info(`IMP newValidatorSetId: ${newValidatorSetId}`); + logger.info(`IMP event proof::${JSON.stringify(eventProof)}`); + const currentValidators = await extractCurrentValidators(api, blockHash); + logger.info(`IMP currentValidators:${currentValidators}`); + const proof = { + eventId: eventProof.eventId, + validatorSetId: eventProof.validatorSetId, + r: eventProof.r, + s: eventProof.s, + v: eventProof.v, + validators: currentValidators + }; + try { + const gasPrice = await provider.getGasPrice(); + logger.info('gas price::', gasPrice.toString()); + // Take 5 percent of current gas price + const percentGasPrice = gasPrice.mul(5).div(100); + logger.info('percentGasPrice:',percentGasPrice.toString()); + const increasedGasPrice = gasPrice.add(percentGasPrice); + logger.info('Gas price nw;:', gasPrice.toString()); + + const gasEstimated = await bridge.estimateGas.setValidators(newValidators, newValidatorSetId, proof, {gasLimit: 5000000, gasPrice: increasedGasPrice}); + + logger.info(JSON.stringify(await bridge.setValidators(newValidators, newValidatorSetId, proof, {gasLimit: gasEstimated.add(BUFFER), gasPrice: increasedGasPrice}))); + await updateLastEventProcessed(eventId, blockHash.toString()); + const balance = await provider.getBalance(txExecutor.address); + logger.info(`IMP Balance is: ${balance}`); + + logger.info(`IMP Gas price: ${gasPrice.toString()}`); + const gasRequired = gasEstimated.mul(gasPrice); + logger.info(`IMP Gas required: ${gasRequired.toString()}`); + if (balance.lt(gasRequired.mul(2))) { + const message = ` 🚨 To keep the validator relayer running, topup the eth account ${txExecutor.address} on CENNZnets ${process.env.NETWORK} chain`; + await sendSlackNotification(message); + } + } catch (e) { + logger.warn('Something went wrong:'); + logger.error(`IMP Error: ${e.stack}`); + // send slack notification when proof submission fails + const message = ` 🚨 Issue while submitting validator set on ethereum bridge + proof: ${JSON.stringify(proof)} + newValidators: ${newValidators} + newValidatorSetId: ${newValidatorSetId} + on CENNZnets ${process.env.NETWORK} chain`; + await sendSlackNotification(message); } } @@ -142,15 +142,6 @@ async function main (networkName, bridgeContractAddress) { process.env.INFURA_API_KEY ); - const setProcessedBlock = process.env.BOOTSTRAP; - // for the first start set processed block - if (setProcessedBlock === 'true') { - const currentFinalizedHeadHash = await api.rpc.chain.getFinalizedHead(); - const block = await api.rpc.chain.getBlock(currentFinalizedHeadHash); - const blockNo = block.block.header.number.toString(); - await updateBlockScanned({ processedBlock: blockNo }); - } - let wallet = new ethers.Wallet(process.env.ETH_ACCOUNT_KEY, infuraProvider); const bridge = new ethers.Contract(bridgeContractAddress, bridgeAbi, wallet); @@ -175,7 +166,6 @@ async function main (networkName, bridgeContractAddress) { for (let i = scanFromEvent; i <= parseInt(lastEventProofIdFromCennznet);i++ ) { console.log('At Event id:',i); const eventProof = await withTimeout(api.derive.ethBridge.eventProof(i), 10000); - if (eventProof && eventProof.tag === 'sys:authority-change') { const checkEventExistsOnEth = await bridge.eventIds(i.toString()); if (!checkEventExistsOnEth) { @@ -192,45 +182,22 @@ async function main (networkName, bridgeContractAddress) { await api.rpc.chain .subscribeFinalizedHeads(async (head) => { - const finalizedBlockAt = head.number.toString(); - logger.info(` finalizedBlockAt::${finalizedBlockAt}`); - const update = { finalizedBlock: finalizedBlockAt }; - await updateBlockScanned(update); - }); - - while (true) { - const blockScanned = await LastBlockScan.findOne({}); - if (blockScanned) { - const {processedBlock, finalizedBlock} = blockScanned; - const processBlockNumber = parseInt(processedBlock); - const finalizedBlockNumber = parseInt(finalizedBlock); - if (processBlockNumber < finalizedBlockNumber) { - // processes block + 1 will be new block to process - for (let blockNumber = processBlockNumber+1; blockNumber < finalizedBlock; blockNumber++) { - logger.info(`At blocknumber: ${blockNumber}`); - - const blockHash = await api.rpc.chain.getBlockHash(blockNumber); - const events = await api.query.system.events.at(blockHash); - events.map(async ({event}) => { - const { section, method, data } = event; - if (section === 'ethBridge' && method === 'AuthoritySetChange') { - const dataFetched = data.toJSON(); - const eventIdFound = dataFetched[0]; - const newValidatorSetId = parseInt(dataFetched[1]); - logger.info(`IMP Event found at block ${blockNumber} hash ${blockHash} event id ${eventIdFound}`); - await getEventPoofAndSubmit(api, eventIdFound, bridge, wallet, newValidatorSetId.toString(), blockHash, infuraProvider); - } - }); - await updateBlockScanned({ processedBlock: blockNumber.toString() }); + const blockNumber = head.number.toNumber(); + logger.info(`At blocknumber: ${blockNumber}`); + + const blockHash = head.hash.toString(); + const events = await api.query.system.events.at(blockHash); + events.map(async ({event}) => { + const { section, method, data } = event; + if (section === 'ethBridge' && method === 'AuthoritySetChange') { + const dataFetched = data.toHuman(); + const eventIdFound = dataFetched[0]; + const newValidatorSetId = parseInt(dataFetched[1]); + logger.info(`IMP Event found at block ${blockNumber} hash ${blockHash} event id ${eventIdFound}`); + await getEventPoofAndSubmit(api, eventIdFound, bridge, wallet, newValidatorSetId.toString(), blockHash, infuraProvider); } - } - } - await sleep(500); - } -} - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); + }) + }); } async function withTimeout(promise, timeoutMs) { @@ -247,11 +214,3 @@ async function withTimeout(promise, timeoutMs) { const networkName = process.env.NETWORK; const bridgeContractAddress = process.env.BRIDGE_CONTRACT; main(networkName, bridgeContractAddress).catch((err) => console.log(err)); - - -async function updateBlockScanned(update) { - const filter = {}; - const options = { upsert: true, new: true, setDefaultsOnInsert: true }; // create new if record does not exist, else update - await LastBlockScan.updateOne(filter, update, options); - logger.info(`Updated the block in db..${JSON.stringify(update)}`); -}