diff --git a/lib/contracts.js b/lib/contracts.js index c8f5c245..66215cfc 100644 --- a/lib/contracts.js +++ b/lib/contracts.js @@ -1,5 +1,6 @@ var Compiler = require('./compiler.js'); var toposort = require('toposort'); +var async = require('async'); // TODO: create a contract object @@ -17,129 +18,155 @@ ContractsManager.prototype.compileContracts = function() { return compiler.compile_solidity(this.contractFiles); }; -ContractsManager.prototype.build = function() { - this.compiledContracts = this.compileContracts(); - var className; - var contract; - - // go through config file first - for(className in this.contractsConfig.contracts) { - contract = this.contractsConfig.contracts[className]; - - contract.className = className; - contract.args = contract.args || []; - - this.contracts[className] = contract; - } - - // compile contracts - for(className in this.compiledContracts) { - var compiledContract = this.compiledContracts[className]; - var contractConfig = this.contractsConfig.contracts[className]; - - contract = this.contracts[className] || {className: className, args: []}; - - contract.code = compiledContract.code; - contract.runtimeBytecode = compiledContract.runtimeBytecode; - contract.gasEstimates = compiledContract.gasEstimates; - contract.functionHashes = compiledContract.functionHashes; - contract.abiDefinition = compiledContract.abiDefinition; - contract.gas = (contractConfig && contractConfig.gas) || this.contractsConfig.gas; - - if (contract.deploy === undefined) { - contract.deploy = true; - } - - if (contract.gas === 'auto') { - var maxGas; - if (contract.deploy) { - maxGas = Math.max(contract.gasEstimates.creation[0], contract.gasEstimates.creation[1], 500000); - } else { - maxGas = 500000; +ContractsManager.prototype.build = function(done) { + var self = this; + async.waterfall([ + function compileContracts(callback) { + var compiler = new Compiler(); + try { + self.compiledContracts = compiler.compile_solidity(self.contractFiles); + callback(); + } catch(err) { + callback(new Error(err.message)); } - // TODO: put a check so it doesn't go over the block limit - var adjustedGas = Math.round(maxGas * 1.40); - contract.gas = adjustedGas; - } - contract.gasPrice = contract.gasPrice || this.contractsConfig.gasPrice; - contract.type = 'file'; - contract.className = className; + }, + function prepareContractsFromConfig(callback) { + var className, contract; + for(className in self.contractsConfig.contracts) { + contract = self.contractsConfig.contracts[className]; - this.contracts[className] = contract; - } + contract.className = className; + contract.args = contract.args || []; - // deal with special configs - for(className in this.contracts) { - contract = this.contracts[className]; - - // if deploy intention is not specified default is true - if (contract.deploy === undefined) { - contract.deploy = true; - } - - if (contract.instanceOf !== undefined) { - var parentContractName = contract.instanceOf; - var parentContract = this.contracts[parentContractName]; - - if (parentContract === className) { - this.logger.error(className + ": instanceOf is set to itself"); - continue; + self.contracts[className] = contract; } + callback(); + }, + function prepareContractsFromCompilation(callback) { + var className, compiledContract, contractConfig, contract; + var maxGas, adjustedGas; + for(className in self.compiledContracts) { + compiledContract = self.compiledContracts[className]; + contractConfig = self.contractsConfig.contracts[className]; - if (parentContract === undefined) { - this.logger.error(className + ": couldn't find instanceOf contract " + parentContractName); - continue; - } + contract = self.contracts[className] || {className: className, args: []}; - if (parentContract.args && parentContract.args.length > 0 && contract.args === []) { - contract.args = parentContract.args; - } + contract.code = compiledContract.code; + contract.runtimeBytecode = compiledContract.runtimeBytecode; + contract.gasEstimates = compiledContract.gasEstimates; + contract.functionHashes = compiledContract.functionHashes; + contract.abiDefinition = compiledContract.abiDefinition; + contract.gas = (contractConfig && contractConfig.gas) || self.contractsConfig.gas; - if (contract.code !== undefined) { - this.logger.error(className + " has code associated to it but it's configured as an instanceOf " + parentContractName); - } - - contract.code = parentContract.code; - contract.runtimeBytecode = parentContract.runtimeBytecode; - contract.gasEstimates = parentContract.gasEstimates; - contract.functionHashes = parentContract.functionHashes; - contract.abiDefinition = parentContract.abiDefinition; - - contract.gas = contract.gas || parentContract.gas; - contract.gasPrice = contract.gasPrice || parentContract.gasPrice; - } - } - - // remove contracts that don't have code - for(className in this.contracts) { - contract = this.contracts[className]; - - if (contract.code === undefined) { - this.logger.error(className + " has no code associated"); - delete this.contracts[className]; - } - } - - this.logger.trace(this.contracts); - - // determine dependencies - for(className in this.contracts) { - contract = this.contracts[className]; - - if (contract.args === []) continue; - - var ref = contract.args; - for (var j = 0; j < ref.length; j++) { - var arg = ref[j]; - if (arg[0] === "$") { - if (this.contractDependencies[className] === void 0) { - this.contractDependencies[className] = []; + if (contract.deploy === undefined) { + contract.deploy = true; } - this.contractDependencies[className].push(arg.substr(1)); - } - } - } + if (contract.gas === 'auto') { + if (contract.deploy) { + maxGas = Math.max(contract.gasEstimates.creation[0], contract.gasEstimates.creation[1], 500000); + } else { + maxGas = 500000; + } + // TODO: put a check so it doesn't go over the block limit + adjustedGas = Math.round(maxGas * 1.40); + contract.gas = adjustedGas; + } + contract.gasPrice = contract.gasPrice || self.contractsConfig.gasPrice; + contract.type = 'file'; + contract.className = className; + + self.contracts[className] = contract; + } + callback(); + }, + function dealWithSpecialConfigs(callback) { + var className, contract, parentContractName, parentContract; + + for(className in self.contracts) { + contract = self.contracts[className]; + + // if deploy intention is not specified default is true + if (contract.deploy === undefined) { + contract.deploy = true; + } + + if (contract.instanceOf !== undefined) { + parentContractName = contract.instanceOf; + parentContract = self.contracts[parentContractName]; + + if (parentContract === className) { + self.logger.error(className + ": instanceOf is set to itself"); + continue; + } + + if (parentContract === undefined) { + slef.logger.error(className + ": couldn't find instanceOf contract " + parentContractName); + continue; + } + + if (parentContract.args && parentContract.args.length > 0 && contract.args === []) { + contract.args = parentContract.args; + } + + if (contract.code !== undefined) { + self.logger.error(className + " has code associated to it but it's configured as an instanceOf " + parentContractName); + } + + contract.code = parentContract.code; + contract.runtimeBytecode = parentContract.runtimeBytecode; + contract.gasEstimates = parentContract.gasEstimates; + contract.functionHashes = parentContract.functionHashes; + contract.abiDefinition = parentContract.abiDefinition; + + contract.gas = contract.gas || parentContract.gas; + contract.gasPrice = contract.gasPrice || parentContract.gasPrice; + } + } + callback(); + }, + function removeContractsWithNoCode(callback) { + var className, contract; + for(className in self.contracts) { + contract = self.contracts[className]; + + if (contract.code === undefined) { + self.logger.error(className + " has no code associated"); + delete self.contracts[className]; + } + } + self.logger.trace(self.contracts); + callback(); + }, + function determineDependencies(callback) { + var className, contract; + for(className in self.contracts) { + contract = self.contracts[className]; + + if (contract.args === []) continue; + + var ref = contract.args; + for (var j = 0; j < ref.length; j++) { + var arg = ref[j]; + if (arg[0] === "$") { + if (self.contractDependencies[className] === void 0) { + self.contractDependencies[className] = []; + } + self.contractDependencies[className].push(arg.substr(1)); + } + } + } + callback(); + } + ], function(err, result) { + self.logger.trace("finished".underline); + if (err) { + //self.logger.debug(err.stack); + done(err); + } else { + done(null, self); + } + }); }; ContractsManager.prototype.getContract = function(className) { diff --git a/lib/index.js b/lib/index.js index 74c7150f..1358794d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -143,12 +143,7 @@ var Embark = { contractsConfig: self.config.contractsConfig, logger: Embark.logger }); - try { - contractsManager.build(); - callback(null, contractsManager); - } catch(err) { - callback(new Error(err.message)); - } + contractsManager.build(callback); }, function deployContracts(contractsManager, callback) {