Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt at fixing Federator memory leak #238

Merged
merged 2 commits into from
Aug 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions federator/integrationTest/transfer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var Web3 = require('web3');
var log4js = require('log4js');
const Web3 = require('web3');
const log4js = require('log4js');
//configurations
const config = require('../config/config.js');
const abiBridge = require('../../abis/Bridge_v2.json');
Expand Down
27 changes: 12 additions & 15 deletions federator/src/contracts/AllowTokensFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@ const IAllowTokensV1 = require('./IAllowTokensV1');
const IAllowTokensV0 = require('./IAllowTokensV0');
const CustomError = require('../lib/CustomError');
const utils = require('../lib/utils');
const ContractFactory = require('./ContractFactory');

module.exports = class AllowTokensFactory {
module.exports = class AllowTokensFactory extends ContractFactory {
constructor(config, logger, Web3) {
this.config = config;
this.logger = logger;
this.mainWeb3 = new Web3(config.mainchain.host);
this.sideWeb3 = new Web3(config.sidechain.host);
super(config, logger, Web3);
this.mainChainBridgeContract = new this.mainWeb3.eth.Contract(abiBridge, this.config.mainchain.bridge);
this.sideChainBridgeContract = new this.sideWeb3.eth.Contract(abiBridge, this.config.sidechain.bridge);
}

async getVersion(allowTokensContract) {
try {
return await utils.retry3Times(allowTokensContract.methods.version().call);
} catch(err) {
} catch (err) {
return 'v0';
}
}

async createInstance(web3, address) {
let allowTokensContract = new web3.eth.Contract(abiAllowTokensNew, address);
let allowTokensContract = this.getContractByAbi(abiAllowTokensNew, address, web3);
const version = await this.getVersion(allowTokensContract);
const chainId = await utils.retry3Times(web3.eth.net.getId);
if (version === 'v1') {
return new IAllowTokensV1(allowTokensContract, chainId);
} else if (version === 'v0') {
allowTokensContract = new web3.eth.Contract(abiAllowTokensOld, address);
allowTokensContract = this.getContractByAbi(abiAllowTokensOld, address, web3);
return new IAllowTokensV0(allowTokensContract, chainId);
} else {
throw Error('Unknown AllowTokens contract version');
Expand All @@ -38,27 +38,24 @@ module.exports = class AllowTokensFactory {

async getMainAllowTokensContract() {
try {
const bridgeContract = new this.mainWeb3.eth.Contract(abiBridge, this.config.mainchain.bridge);
const allowTokensAddress = await utils.retry3Times(bridgeContract.methods.allowTokens().call);
const allowTokensAddress = await utils.retry3Times(this.mainChainBridgeContract.methods.allowTokens().call);
return await this.createInstance(
this.mainWeb3,
allowTokensAddress
);
} catch(err) {
} catch (err) {
throw new CustomError(`Exception creating Main AllowTokens Contract`, err);
}
}

async getSideAllowTokensContract() {
try {
const bridgeContract = new this.sideWeb3.eth.Contract(abiBridge, this.config.sidechain.bridge);
const allowTokensAddress = await utils.retry3Times(bridgeContract.methods.allowTokens().call);

const allowTokensAddress = await utils.retry3Times(this.sideChainBridgeContract.methods.allowTokens().call);
return await this.createInstance(
this.sideWeb3,
allowTokensAddress
);
} catch(err) {
} catch (err) {
throw new CustomError(`Exception creating Side AllowTokens Contract`, err);
}
}
Expand Down
18 changes: 8 additions & 10 deletions federator/src/contracts/BridgeFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,24 @@ const abiBridgeNew = require('../../../abis/Bridge.json');
const BridgeInterface = require('./IBridge.js');
const CustomError = require('../lib/CustomError');
const utils = require('../lib/utils');
const ContractFactory = require('./ContractFactory');

module.exports = class BridgeFactory {
module.exports = class BridgeFactory extends ContractFactory {

constructor(config, logger, Web3) {
this.config = config;
this.logger = logger;
this.mainWeb3 = new Web3(config.mainchain.host);
this.sideWeb3 = new Web3(config.sidechain.host);
super(config, logger, Web3);
}

async getVersion(bridgeContract) {
return utils.retry3Times(bridgeContract.methods.version().call)
}

async createInstance(web3, address) {
let bridgeContract = new web3.eth.Contract(abiBridgeOld, address);
let bridgeContract = this.getContractByAbi(abiBridgeOld, address, web3);
const version = await this.getVersion(bridgeContract);
if (version === 'v3') {
bridgeContract = new web3.eth.Contract(abiBridgeNew, address);
} else if (!['v2','v1'].includes(version)) {
bridgeContract = this.getContractByAbi(abiBridgeNew, address, web3);
} else if (!['v2', 'v1'].includes(version)) {
throw Error('Unknown Bridge contract version');
}
return new BridgeInterface(bridgeContract);
Expand All @@ -34,7 +32,7 @@ module.exports = class BridgeFactory {
this.mainWeb3,
this.config.mainchain.bridge
);
} catch(err) {
} catch (err) {
throw new CustomError(`Exception creating Main Bridge Contract`, err);
}
}
Expand All @@ -45,7 +43,7 @@ module.exports = class BridgeFactory {
this.sideWeb3,
this.config.sidechain.bridge
);
} catch(err) {
} catch (err) {
throw new CustomError(`Exception creating Side Bridge Contract`, err);
}
}
Expand Down
19 changes: 19 additions & 0 deletions federator/src/contracts/ContractFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = class ContractFactory {
constructor(config, logger, Web3) {
this.config = config;
this.logger = logger;
this.mainWeb3 = new Web3(config.mainchain.host);
this.sideWeb3 = new Web3(config.sidechain.host);
this.contractsByAbi = new Map();
}

// There should only be one address per abi - the address is only needed to create a new web3.eth.Contract object.
getContractByAbi(abi, address, web3) {
let contractForAbi = this.contractsByAbi.get(abi)
if (!contractForAbi) {
contractForAbi = new web3.eth.Contract(abi, address);
this.contractsByAbi.set(abi, contractForAbi);
}
return contractForAbi;
}
}
21 changes: 9 additions & 12 deletions federator/src/contracts/FederationFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,24 @@ const FederationInterfaceV1 = require('./IFederationV1.js');
const FederationInterfaceV2 = require('./IFederationV2.js');
const CustomError = require('../lib/CustomError');
const utils = require('../lib/utils');
const ContractFactory = require('./ContractFactory');

module.exports = class FederationFactory {
module.exports = class FederationFactory extends ContractFactory {

constructor(config, logger, Web3) {
this.config = config;
this.logger = logger;
this.mainWeb3 = new Web3(config.mainchain.host);
this.sideWeb3 = new Web3(config.sidechain.host);
super(config, logger, Web3)
this.mainChainBridgeContract = new this.mainWeb3.eth.Contract(abiBridge, this.config.mainchain.bridge);
this.sideChainBridgeContract = new this.sideWeb3.eth.Contract(abiBridge, this.config.sidechain.bridge);
}

async createInstance(web3, address) {
let federationContract = new web3.eth.Contract(abiFederationNew, address);
let federationContract = this.getContractByAbi(abiFederationNew, address, web3);
const version = await this.getVersion(federationContract);

if (version === 'v2') {
federationContract = new web3.eth.Contract(abiFederationNew, address);
return new FederationInterfaceV2(this.config, federationContract);
} else if (version === 'v1') {
federationContract = new web3.eth.Contract(abiFederationOld, address);
federationContract = this.getContractByAbi(abiFederationOld, address, web3);
return new FederationInterfaceV1(this.config, federationContract);
} else {
throw Error('Unknown Federation contract version');
Expand All @@ -40,8 +39,7 @@ module.exports = class FederationFactory {

async getMainFederationContract() {
try {
const bridgeContract = new this.mainWeb3.eth.Contract(abiBridge, this.config.mainchain.bridge);
const federationAddress = await utils.retry3Times(bridgeContract.methods.getFederation().call);
const federationAddress = await utils.retry3Times(this.mainChainBridgeContract.methods.getFederation().call);
return await this.createInstance(
this.mainWeb3,
federationAddress
Expand All @@ -53,8 +51,7 @@ module.exports = class FederationFactory {

async getSideFederationContract() {
try {
const bridgeContract = new this.sideWeb3.eth.Contract(abiBridge, this.config.sidechain.bridge);
const federationAddress = await utils.retry3Times(bridgeContract.methods.getFederation().call);
const federationAddress = await utils.retry3Times(this.sideChainBridgeContract.methods.getFederation().call);
return await this.createInstance(
this.sideWeb3,
federationAddress
Expand Down
8 changes: 4 additions & 4 deletions federator/src/lib/Federator.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ module.exports = class Federator {
const numberOfPages = Math.ceil((toBlock - fromBlock) / recordsPerPage);
this.logger.debug(`Total pages ${numberOfPages}, blocks per page ${recordsPerPage}`);

var fromPageBlock = fromBlock;
for(var currentPage = 1; currentPage <= numberOfPages; currentPage++) {
var toPagedBlock = fromPageBlock + recordsPerPage-1;
if(currentPage == numberOfPages) {
let fromPageBlock = fromBlock;
for (let currentPage = 1; currentPage <= numberOfPages; currentPage++) {
let toPagedBlock = fromPageBlock + recordsPerPage - 1;
if (currentPage === numberOfPages) {
toPagedBlock = toBlock
}
this.logger.debug(`Page ${currentPage} getting events from block ${fromPageBlock} to ${toPagedBlock}`);
Expand Down
8 changes: 4 additions & 4 deletions federator/src/lib/Heartbeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ module.exports = class Heartbeat {
const numberOfPages = Math.ceil((toBlock - fromBlock) / recordsPerPage);
this.logger.debug(`Total pages ${numberOfPages}, blocks per page ${recordsPerPage}`);

var fromPageBlock = fromBlock;
for(var currentPage = 1; currentPage <= numberOfPages; currentPage++) {
var toPagedBlock = fromPageBlock + recordsPerPage-1;
if(currentPage == numberOfPages) {
let fromPageBlock = fromBlock;
for(let currentPage = 1; currentPage <= numberOfPages; currentPage++) {
let toPagedBlock = fromPageBlock + recordsPerPage - 1;
if(currentPage === numberOfPages) {
toPagedBlock = toBlock
}

Expand Down
22 changes: 10 additions & 12 deletions federator/src/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ const Web3 = require('web3');
for (let i = 0; i < retriesMax; i++) {
try {
if (!config.isCb) {
const val = await fn.apply(null, args);
return val;
return await fn.apply(null, args);
} else {
const val = await getPromise(fn, clone(args));
return val;
return await getPromise(fn, clone(args));
}
} catch (error) {
if(retriesMax === i+1 || (error.hasOwnProperty('retryable') && !error.retryable)) throw error;
Expand All @@ -44,11 +42,11 @@ async function retry3Times(func, params = null) {
}

async function waitBlocks(client, numberOfBlocks) {
var startBlock = await client.eth.getBlockNumber();
var currentBlock = startBlock;
const startBlock = await client.eth.getBlockNumber();
let currentBlock = startBlock;
while(numberOfBlocks > currentBlock - startBlock) {
var newBlock = await client.eth.getBlockNumber();
if(newBlock != currentBlock){
const newBlock = await client.eth.getBlockNumber();
if(newBlock !== currentBlock){
currentBlock = newBlock;
} else {
await sleep(20000);
Expand Down Expand Up @@ -170,13 +168,13 @@ async function asyncMine(anotherWeb3Instance = null) {
return resolve(result);
});
});
};
}

async function evm_mine(iterations, web3Instance = null) {
for(var i = 0; i < iterations; i++ ) {
for(let i = 0; i < iterations; i++ ) {
await asyncMine(web3Instance);
};
};
}
}


function increaseTimestamp(web3, increase) {
Expand Down
2 changes: 1 addition & 1 deletion federator/test/TransactionSender.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const logger = {
warn: jest.fn(),
error: jest.fn(),
};
var web3Mock = jest.fn();
const web3Mock = jest.fn();

describe('TransactionSender module tests', () => {
beforeEach(async function () {
Expand Down
6 changes: 3 additions & 3 deletions federator/test/web3Mock/eth.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const contractMapping = require('./contractMapping');
const defaults = require('./defaults');
var Web3PromiEvent = require('web3-core-promievent');
const Web3PromiEvent = require('web3-core-promievent');

let eth = {};

Expand All @@ -10,8 +10,8 @@ eth.getTransactionCount = () => defaults.data.ethTransactionCount;
eth.getGasPrice = () => defaults.data.gasPrice;

let promiseSend = function(){
var promiEvent = Web3PromiEvent();
const promiEvent = Web3PromiEvent();

setTimeout(function() {
promiEvent.eventEmitter.emit('transactionHash', defaults.data.receipt.transactionHash);
promiEvent.resolve(defaults.data.receipt);
Expand Down