Skip to content

Commit

Permalink
Update the relayer to work with new image + old image (#87)
Browse files Browse the repository at this point in the history
Restart pod when event proof is not found
  • Loading branch information
KarishmaBothara committed May 8, 2023
1 parent 7dcce33 commit f1eea79
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 112 deletions.
1 change: 1 addition & 0 deletions .github/workflows/image-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
push:
branches:
- "main"
- "azalea"
paths:
- "**.js"
- "**.json"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const ROPSTEN_V1 = {
const ROPSTEN_V2 = {
bridge: "0x452b8dd7b00D51e48cEF6254a48B7426d44658B8",
peg: "0x4C411B3Bf36D6DE908C6f4256a72B85E3f2B00bF",
wcennz: "0xcdA767469D434c14D320e1A78D5b612B72B52bf0",
wcennz: "0x673F0244bd0AEbd9918ef089f75C503Df9bfBb38",
}
```

Expand Down
181 changes: 70 additions & 111 deletions scripts/subscribeEventProof.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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)}`);
}

0 comments on commit f1eea79

Please sign in to comment.