From 03f81c47d7919967c22f48352cfa5e80a8bb62bc Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Sat, 24 Sep 2016 21:10:47 -0400 Subject: [PATCH] implement contract tracking --- demo/chains.json | 20 +++++++++++++++++ lib/config.js | 19 ++++++++++++++++ lib/deploy.js | 42 ++++++++++++++++++++++++++++------- lib/deploy_tracker.js | 51 +++++++++++++++++++++++++++++++++++++++++++ lib/index.js | 8 ++++++- package.json | 2 +- 6 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 demo/chains.json create mode 100644 lib/deploy_tracker.js diff --git a/demo/chains.json b/demo/chains.json new file mode 100644 index 00000000..51b90f75 --- /dev/null +++ b/demo/chains.json @@ -0,0 +1,20 @@ +{ + "0xb6cfeab83614da04c03db0fb8a6787a45d0be8d576fcc6f8f457a5a816d22ab3": { + "name": "development", + "networkId": "", + "contracts": { + "288f087742d513019f59539bbf4f07b352e14327e0e7b8ed4bc7c33e34fbc192": { + "address": "0xab47369d82950224a1698d4a856cfa175ba9cf84", + "name": "SimpleStorage" + }, + "5a52b16abb7dfccfc675550d0daba1683a3cf7e80fb5f0e199301f7dd57237fb": { + "address": "0xbd2b5c34a2a85d3ae5e903e0015a07868c0d97c3", + "name": "SimpleStorage" + }, + "708fa6b699f419627ab3c4c2d9c82f8f1a6fab03c122d0a9ee55d2d0d0ad1e4b": { + "address": "0x7a72b8be758afe7d3e421e7d32c81c605fec333d", + "name": "token" + } + } + } +} \ No newline at end of file diff --git a/lib/config.js b/lib/config.js index 6988c9e4..87b5381a 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,11 +1,14 @@ var fs = require('fs'); var grunt = require('grunt'); +// TODO: add wrapper for fs so it can also work in the browser +// can work with both read and save var Config = function(env) { this.env = env; this.blockchainConfig = {}; this.contractsConfig = {}; this.pipelineConfig = {}; + this.chainTracker = {}; this.assetFiles = {}; this.contractsFiles = []; this.configDir = 'config/'; @@ -17,12 +20,14 @@ Config.prototype.loadConfigFiles = function(options) { this.loadPipelineConfigFile(); this.loadBlockchainConfigFile(); this.loadContractsConfigFile(); + this.loadChainTrackerFile(); }; Config.prototype.reloadConfig = function() { this.loadPipelineConfigFile(); this.loadBlockchainConfigFile(); this.loadContractsConfigFile(); + this.loadChainTrackerFile(); }; Config.prototype.loadBlockchainConfigFile = function() { @@ -51,6 +56,20 @@ Config.prototype.loadPipelineConfigFile = function() { this.configDir = this.embarkConfig.config; }; +Config.prototype.loadChainTrackerFile = function() { + //var self = this; + var chainTracker; + try { + chainTracker = JSON.parse(fs.readFileSync("./chains.json")); + } + catch(err) { + //self.logger.info('chains.json file not found, creating it...'); + chainTracker = {}; + fs.writeFileSync('./chains.json', '{}'); + } + this.chainTracker = chainTracker; +}; + Config.prototype.loadFiles = function(files) { var originalFiles = grunt.file.expand({nonull: true}, files); var readFiles = []; diff --git a/lib/deploy.js b/lib/deploy.js index 675f3fc1..31a3120a 100644 --- a/lib/deploy.js +++ b/lib/deploy.js @@ -1,17 +1,45 @@ var async = require('async'); var Compiler = require('./compiler.js'); +var DeployTracker = require('./deploy_tracker.js'); + +var Deploy = function(options) { + this.web3 = options.web3; + this.contractsManager = options.contractsManager; + this.logger = options.logger; + this.env = options.env; + + this.deployTracker = new DeployTracker({ + logger: options.logger, chainConfig: options.chainConfig, web3: options.web3, env: this.env + }); +}; + +Deploy.prototype.checkAndDeployContract = function(contract, params, callback) { + var self = this; + var trackedChain = self.deployTracker.getContract(contract.className, contract.code, contract.args); + + // TODO: need to also check getCode + if (trackedChain) { + self.logger.info(contract.className + " already deployed " + trackedChain.address); + contract.deployedAddress = trackedChain.address; + self.logger.contractsState(self.contractsManager.contractsState()); + callback(); + } else { + this.deployContract(contract, params, function(err, address) { + self.logger.info("not deployed"); + self.deployTracker.trackContract(contract.className, contract.code, contract.args, address); + self.deployTracker.save(); + self.logger.contractsState(self.contractsManager.contractsState()); + callback(); + }); + } -var Deploy = function(web3, contractsManager, logger) { - this.web3 = web3; - this.contractsManager = contractsManager; - this.logger = logger; }; Deploy.prototype.deployContract = function(contract, params, callback) { var self = this; var contractObject = this.web3.eth.contract(contract.abiDefinition); - var contractParams = params || contract.args; + var contractParams = (params || contract.args).slice(); contractParams.push({ from: this.web3.eth.coinbase, @@ -27,12 +55,10 @@ Deploy.prototype.deployContract = function(contract, params, callback) { if (err) { self.logger.error("error deploying contract: " + contract.className); self.logger.error(err.toString()); - self.logger.contractsState(self.contractsManager.contractsState()); callback(new Error(err)); } else if (transaction.address !== undefined) { self.logger.info(contract.className + " deployed at " + transaction.address); contract.deployedAddress = transaction.address; - self.logger.contractsState(self.contractsManager.contractsState()); callback(null, transaction.address); } }); @@ -47,7 +73,7 @@ Deploy.prototype.deployAll = function(done) { async.eachOfSeries(this.contractsManager.listContracts(), function(contract, key, callback) { self.logger.trace(arguments); - self.deployContract(contract, null, callback); + self.checkAndDeployContract(contract, null, callback); }, function(err, results) { self.logger.info("finished"); diff --git a/lib/deploy_tracker.js b/lib/deploy_tracker.js new file mode 100644 index 00000000..292034f2 --- /dev/null +++ b/lib/deploy_tracker.js @@ -0,0 +1,51 @@ +var fs = require('fs'); +var prettyJson = require("json-honey"); + +var DeployTracker = function(options) { + this.logger = options.logger; + this.env = options.env; + this.chainConfig = options.chainConfig; + this.web3 = options.web3; + + var block = this.web3.eth.getBlock(0); + var chainId = block.hash; + + if (this.chainConfig[chainId] === undefined) { + this.chainConfig[chainId] = {contracts: {}}; + } + + this.currentChain = this.chainConfig[chainId]; + + this.currentChain.name = this.env; + // TODO: add networkId + this.currentChain.networkId = ""; +}; + +DeployTracker.prototype.loadConfig = function(config) { + this.chainConfig = config; + return this; +}; + +DeployTracker.prototype.trackContract = function(contractName, code, args, address) { + //this.logger.debug("--- trackContract ---"); + //this.logger.debug(this.currentChain.contracts); + //this.logger.debug(code + contractName + args.join(',')); + //this.logger.debug(this.web3.sha3(code + contractName + args.join(','))); + this.currentChain.contracts[this.web3.sha3(code + contractName + args.join(','))] = { + name: contractName, + address: address + }; +}; + +DeployTracker.prototype.getContract = function(contractName, code, args) { + return this.currentChain.contracts[this.web3.sha3(code + contractName + args.join(','))]; +}; + +// TODO: abstract this +// chainConfig can be an abstract PersistentObject +DeployTracker.prototype.save = function() { + fs.writeFileSync("./chains.json", prettyJson(this.chainConfig)); +}; + +module.exports = DeployTracker; + diff --git a/lib/index.js b/lib/index.js index fdc149e0..29318ea8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -210,7 +210,13 @@ var Embark = { exit(); } - var deploy = new Deploy(web3, contractsManager, Embark.logger); + var deploy = new Deploy({ + web3: web3, + contractsManager: contractsManager, + logger: Embark.logger, + chainConfig: self.config.chainTracker, + env: self.config.env + }); deploy.deployAll(function() { callback(null, contractsManager); }); diff --git a/package.json b/package.json index ae25b31d..6745436d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "commander": "^2.8.1", "finalhandler": "^0.5.0", "grunt": "^0.4.5", - "js-sha3": "^0.3.1", + "json-honey": "^0.4.1", "meteor-build-client": "^0.1.6", "mkdirp": "^0.5.1", "read-yaml": "^1.0.0",