diff --git a/lib/contracts/contract_deployer.js b/lib/contracts/contract_deployer.js index 3385d642a..b97bb4750 100644 --- a/lib/contracts/contract_deployer.js +++ b/lib/contracts/contract_deployer.js @@ -152,16 +152,16 @@ class ContractDeployer { accounts = _accounts; // applying deployer account configuration, if any - if (typeof contract.fromIndex == 'number') { + if (typeof contract.fromIndex === 'number') { deploymentAccount = accounts[contract.fromIndex]; if (deploymentAccount === undefined) { return next(__("error deploying") + " " + contract.className + ": " + __("no account found at index") + " " + contract.fromIndex + __(" check the config")); } } - if (typeof contract.from == 'string' && typeof contract.fromIndex != 'undefined') { + if (typeof contract.from === 'string' && typeof contract.fromIndex !== 'undefined') { self.logger.warn(__('Both "from" and "fromIndex" are defined for contract') + ' "' + contract.className + '". ' + __('Using "from" as deployer account.')); } - if (typeof contract.from == 'string') { + if (typeof contract.from === 'string') { deploymentAccount = contract.from; } diff --git a/lib/contracts/contracts.js b/lib/contracts/contracts.js index f53d5fd53..cff1b19e8 100644 --- a/lib/contracts/contracts.js +++ b/lib/contracts/contracts.js @@ -261,8 +261,45 @@ class ContractsManager { }); } callback(); + }, + function setDependencyCount(callback) { + let className; + + function getDependencyCount(contractName, cycleDetector) { + if (!self.contracts[contractName]) { + return 0; + } + if (self.contracts[contractName].dependencyCount || self.contracts[contractName].dependencyCount === 0) { + // Already have that count + return self.contracts[contractName].dependencyCount; + } + if (!self.contractDependencies[contractName] || !self.contractDependencies[contractName].length) { + self.contracts[contractName].dependencyCount = 0; + return 0; + } + let total = self.contractDependencies[contractName].length; + self.contractDependencies[contractName].some(dependencyName => { + if (cycleDetector.indexOf(dependencyName) > -1) { + // We are in a cycle because of the dependency, set both to Infinity + self.contracts[dependencyName].dependencyCount = Infinity; + total = Infinity; + return true; + } + cycleDetector.push(dependencyName); + total += getDependencyCount(dependencyName, cycleDetector); + }); + self.contracts[contractName].dependencyCount = total; + return total; + } + + let cycleDetector; + for (className in self.contracts) { + cycleDetector = []; + getDependencyCount(className, cycleDetector); + } + callback(); } - ], function (err, _result) { + ], function (err) { if (err) { self.compileError = true; self.events.emit("status", __("Compile/Build error")); diff --git a/lib/contracts/deploy_manager.js b/lib/contracts/deploy_manager.js index 7f63a4d43..b53c4b0d1 100644 --- a/lib/contracts/deploy_manager.js +++ b/lib/contracts/deploy_manager.js @@ -1,4 +1,5 @@ let async = require('async'); +const _ = require('underscore'); class DeployManager { constructor(options) { @@ -31,12 +32,15 @@ class DeployManager { self.logger.info(__("deploying contracts")); self.events.emit("deploy:beforeAll"); - async.eachOfSeries(contracts, - function (contract, key, callback) { - contract._gasLimit = self.gasLimit; - self.events.request('deploy:contract', contract, (err) => { - callback(err); - }); + const contractsPerDependencyCount = _.groupBy(contracts, 'dependencyCount'); + async.eachSeries(contractsPerDependencyCount, + function (parallelGroups, callback) { + async.each(parallelGroups, (contract, eachCb) => { + contract._gasLimit = self.gasLimit; + self.events.request('deploy:contract', contract, (err) => { + eachCb(err); + }); + }, callback); }, function (err, _results) { if (err) { diff --git a/lib/tests/test.js b/lib/tests/test.js index 2cd5d7fac..5053f4739 100644 --- a/lib/tests/test.js +++ b/lib/tests/test.js @@ -123,6 +123,10 @@ class Test { this.engine.contractsManager.build(() => { self.builtContracts = cloneDeep(self.engine.contractsManager.contracts); + let className; + for (className in self.builtContracts) { + self.builtContracts[className].dependencyCount = null; + } self.compiledContracts = cloneDeep(self.engine.contractsManager.compiledContracts); callback(); }); @@ -211,6 +215,7 @@ class Test { function resetContracts(next) { self.engine.contractsManager.contracts = cloneDeep(self.builtContracts); self.engine.contractsManager.compiledContracts = cloneDeep(self.compiledContracts); + self.engine.contractsManager.contractDependencies = {}; next(); }, function deploy(next) {