diff --git a/README.md b/README.md index 4930ed01..53b4caf7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +This Readme applies to Embark 1.0.0 Beta which is currently under development. For the old version please check the old [readme](https://github.com/iurimatias/embark-framework/blob/0.9.3/README.md) + What is embark ====== @@ -11,18 +13,18 @@ With Embark you can: * Do Test Driven Development with Contracts using Javascript. * Easily deploy to & use decentralized systems such as IPFS. * Keep track of deployed contracts, deploy only when truly needed. +* Manage different chains (e.g testnet, private net, livenet) * Quickly create advanced DApps using multiple contracts. See the [Wiki](https://github.com/iurimatias/embark-framework/wiki) for more details. Installation ====== -Requirements: geth (1.0.0), solc (0.1.0) or serpent (develop), node (0.12.2) and npm - -For specs: pyethereum, ethertdd.py +Requirements: geth (1.1.3 or higher), node (0.12.2) and npm +Optional: serpent (develop) if using contracts with Serpent ```Bash -$ npm install -g embark-framework grunt-cli +$ npm -g install embark-framework ``` See [Complete Installation Instructions](https://github.com/iurimatias/embark-framework/wiki/Installation). @@ -35,11 +37,19 @@ You can easily create a sample working DApp with the following: $ embark demo $ cd embark_demo ``` -To run the ethereum node for development purposes simply run: + +To run a ethereum rpc simulator simply run: + +```Bash +$ embark simulator +``` + +Or Alternatively, you can run a REAL ethereum node for development purposes: ```Bash $ embark blockchain ``` + By default embark blockchain will mine a minimum amount of ether and will only mine when new transactions come in. This is quite usefull to keep a low CPU. The option can be configured at config/blockchain.yml Then, in another command line: @@ -199,42 +209,41 @@ You can also define contract interfaces (Stubs) and actions to do on deployment Tests ====== -You can run specs with ```embark spec```, it will run any files ending *_spec.js under ```spec/```. +You can run specs with ```embark spec```, it will run any test files under ```test/```. Embark includes a testing lib to fastly run & test your contracts in a EVM. ```Javascript -# spec/contracts/simple_storage_spec.js -Embark = require('embark-framework'); -Embark.init(); -Embark.blockchainConfig.loadConfigFile('config/blockchain.yml'); -Embark.contractsConfig.loadConfigFile('config/contracts.yml'); +# test/simple_storage_spec.js +var assert = require('assert'); +var Embark = require('embark-framework'); +var EmbarkSpec = Embark.initTests(); -var files = ['app/contracts/simpleStorage.sol']; -Embark.contractsConfig.init(files, 'development'); - -var EmbarkSpec = Embark.tests(files); - -describe("SimpleStorage", function() { - beforeAll(function() { - // equivalent to initializing SimpleStorage with param 150 - SimpleStorage = EmbarkSpec.request("SimpleStorage", [150]); +describe("SimpleStorage", function(done) { + before(function(done) { + EmbarkSpec.deployAll(done); }); - it("should set constructor value", function() { - expect(SimpleStorage.storedData()).toEqual('150'); + it("should set constructor value", function(done) { + SimpleStorage.storedData(function(err, result) { + assert.equal(result.toNumber(), 100); + done(); + }); }); - it("set storage value", function() { - SimpleStorage.set(100); - expect(SimpleStorage.get()).toEqual('100'); + it("set storage value", function(done) { + SimpleStorage.set(150, function() { + SimpleStorage.get(function(err, result) { + assert.equal(result.toNumber(), 150); + done(); + }); + }); }); }) ``` -Embark uses [Jasmine](https://jasmine.github.io/2.3/introduction.html) by default, but you can use any testing framework you want. - +Embark uses [Mocha](http://mochajs.org/) by default, but you can use any testing framework you want. Working with different chains ====== @@ -258,6 +267,7 @@ The environment is a specific blockchain configuration that can be managed at co chains: chains_staging.json network_id: 0 console: true + geth_extra_opts: --vmdebug account: init: false address: 0x123 diff --git a/bin/embark b/bin/embark index 8a3b7ae7..5cf6f390 100755 --- a/bin/embark +++ b/bin/embark @@ -6,6 +6,7 @@ var wrench = require('wrench'); var grunt = require('grunt'); require('shelljs/global'); var readYaml = require('read-yaml'); +var EtherSim = require('ethersim'); var Embark = require('..'); var run = function(cmd) { @@ -14,7 +15,7 @@ var run = function(cmd) { } } -var deploy = function(env, embarkConfig) { +var deploy = function(env, embarkConfig, cb) { var contractFiles = grunt.file.expand(embarkConfig.contracts); var destFile = embarkConfig.output; @@ -24,12 +25,14 @@ var deploy = function(env, embarkConfig) { var chainFile = Embark.blockchainConfig.blockchainConfig[env].chains || embarkConfig.chains || './chains.json'; - abi = Embark.deployContracts(env, contractFiles, destFile, chainFile); - grunt.file.write(destFile, abi); + abi = Embark.deployContracts(env, contractFiles, destFile, chainFile, true, true, function(abi) { + grunt.file.write(destFile, abi); + cb(); + }); } program - .version('0.9.2') + .version('1.0.2'); program.command('new [name]').description('New application').action(function(name) { if (name === undefined) { @@ -53,7 +56,7 @@ program.command('deploy [env]').description('deploy contracts').action(function( run("grunt deploy_contracts:" + env); } else { - deploy(env, embarkConfig); + deploy(env, embarkConfig, function() { exit(); }); } }); @@ -105,15 +108,16 @@ program.command('run [env]').description('run dapp').action(function(env_) { } }); -program.command('spec').description('run specs').action(function() { +program.command('spec').description('run tests').action(function() { var embarkConfig = readYaml.sync("./embark.yml"); if (embarkConfig.type === "grunt") { - run('jasmine'); + run('mocha test/ --no-timeouts'); } else { console.log("command not available in meteor or manual mode yet"); console.log("note: you can use embark tests with any framework"); + console.log("try running mocha test/"); } }); @@ -155,7 +159,7 @@ program.command('demo').description('create a working dapp with a SimpleStorage wrench.copyDirSyncRecursive(boilerPath, targetDir); wrench.copyDirSyncRecursive(demoPath + "/app", targetDir + "/app", {forceDelete: true}); wrench.copyDirSyncRecursive(demoPath + "/config", targetDir + "/config", {forceDelete: true}); - wrench.copyDirSyncRecursive(demoPath + "/spec", targetDir + "/spec", {forceDelete: true}); + wrench.copyDirSyncRecursive(demoPath + "/test", targetDir + "/test", {forceDelete: true}); cd(targetDir); run('npm install'); @@ -170,10 +174,14 @@ program.command('meteor_demo').description('create a working meteor dapp with a console.log('\n\ninit complete'); }); +program.command('simulator').description('run a fast ethereum rpc simulator').action(function() { + EtherSim.startServer(); +}); + program.parse(process.argv) if (!process.argv.slice(2).length) { program.outputHelp(); } -exit(); +//exit(); diff --git a/boilerplate/Gruntfile.coffee b/boilerplate/Gruntfile.coffee index 150ff372..279c1816 100644 --- a/boilerplate/Gruntfile.coffee +++ b/boilerplate/Gruntfile.coffee @@ -1,5 +1,6 @@ module.exports = (grunt) -> + grunt.option 'stack', true grunt.loadNpmTasks "grunt-embark" grunt.loadTasks "tasks" @@ -111,4 +112,3 @@ module.exports = (grunt) -> grunt.registerTask "deploy", ["coffee", "deploy_contracts", "concat", "copy", "server", "watch"] grunt.registerTask "build", ["clean", "deploy_contracts", "coffee", "concat", "uglify", "copy"] - diff --git a/boilerplate/config/blockchain.yml b/boilerplate/config/blockchain.yml index 49fb0add..af516800 100644 --- a/boilerplate/config/blockchain.yml +++ b/boilerplate/config/blockchain.yml @@ -14,6 +14,7 @@ development: account: init: true password: config/password + num: 1 staging: rpc_host: localhost rpc_port: 8101 @@ -22,6 +23,9 @@ staging: network_id: 0 max_peers: 4 console: true + bootnodes: + boot: false + enodes: [] #insert enode urls here. account: init: false address: @@ -33,6 +37,9 @@ production: network_id: 1 max_peers: 4 console: true + bootnodes: + boot: false + enodes: [] account: init: false address: diff --git a/boilerplate/package.json b/boilerplate/package.json index 458c8ec2..addeb674 100644 --- a/boilerplate/package.json +++ b/boilerplate/package.json @@ -10,8 +10,8 @@ "license": "ISC", "homepage": "", "devDependencies": { - "embark-framework": "^0.9.2", - "grunt-embark": "^0.4.3", + "embark-framework": "^1.0.2", + "grunt-embark": "^0.5.1", "grunt-contrib-clean": "^0.6.0", "grunt-contrib-coffee": "^0.13.0", "grunt-contrib-concat": "^0.5.1", @@ -21,6 +21,7 @@ "grunt": "^0.4.5", "grunt-cli": "^0.1.13", "matchdep": "^0.3.0", + "mocha": "^2.2.5", "express": "^4.12.3", "read-yaml": "^1.0.0", "compression": "^1.4.3" diff --git a/boilerplate/spec/support/jasmine.json b/boilerplate/spec/support/jasmine.json deleted file mode 100644 index a5f29329..00000000 --- a/boilerplate/spec/support/jasmine.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "spec_dir": "spec", - "spec_files": [ - "**/*[sS]pec.js" - ], - "helpers": [ - "helpers/**/*.js" - ] -} diff --git a/demo/spec/contracts/simple_storage_spec.js b/demo/spec/contracts/simple_storage_spec.js deleted file mode 100644 index 359d9d15..00000000 --- a/demo/spec/contracts/simple_storage_spec.js +++ /dev/null @@ -1,25 +0,0 @@ -var Embark = require('embark-framework'); -Embark.init(); -Embark.blockchainConfig.loadConfigFile('config/blockchain.yml'); -Embark.contractsConfig.loadConfigFile('config/contracts.yml'); - -var files = ["app/contracts/simple_storage.sol"]; - -Embark.contractsConfig.init(files, 'development'); -var EmbarkSpec = Embark.tests(files); - -describe("SimpleStorage", function() { - beforeAll(function() { - SimpleStorage = EmbarkSpec.request("SimpleStorage", [150]); - }); - - it("should set constructor value", function() { - expect(SimpleStorage.storedData()).toEqual('150'); - }); - - it("set storage value", function() { - SimpleStorage.set(100); - expect(SimpleStorage.get()).toEqual('100'); - }); - -}) diff --git a/demo/spec/support/jasmine.json b/demo/spec/support/jasmine.json deleted file mode 100644 index a5f29329..00000000 --- a/demo/spec/support/jasmine.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "spec_dir": "spec", - "spec_files": [ - "**/*[sS]pec.js" - ], - "helpers": [ - "helpers/**/*.js" - ] -} diff --git a/demo/test/simple_storage_spec.js b/demo/test/simple_storage_spec.js new file mode 100644 index 00000000..916c4c5e --- /dev/null +++ b/demo/test/simple_storage_spec.js @@ -0,0 +1,26 @@ +var assert = require('assert'); +var Embark = require('embark-framework'); +var EmbarkSpec = Embark.initTests(); + +describe("SimpleStorage", function(done) { + before(function(done) { + EmbarkSpec.deployAll(done); + }); + + it("should set constructor value", function(done) { + SimpleStorage.storedData(function(err, result) { + assert.equal(result.toNumber(), 100); + done(); + }); + }); + + it("set storage value", function(done) { + SimpleStorage.set(150, function() { + SimpleStorage.get(function(err, result) { + assert.equal(result.toNumber(), 150); + done(); + }); + }); + }); + +}) diff --git a/lib/blockchain.js b/lib/blockchain.js index 9ab37a5c..9ab5deaf 100644 --- a/lib/blockchain.js +++ b/lib/blockchain.js @@ -16,6 +16,10 @@ Blockchain.prototype.generate_basic_command = function() { cmd += "--logfile=\"" + config.datadir + ".log\" "; } + if (config.geth_extra_opts) { + cmd += config.geth_extra_opts + " "; + } + cmd += "--port " + config.port + " "; cmd += "--rpc "; cmd += "--rpcport " + config.rpcPort + " "; @@ -27,7 +31,9 @@ Blockchain.prototype.generate_basic_command = function() { cmd += "--minerthreads \"" + config.minerthreads + "\" "; } - cmd += "--mine "; + if(config.mine) + cmd += "--mine "; + if (config.genesisBlock !== void 0) { cmd += "--genesis=\"" + config.genesisBlock + "\" "; } @@ -69,6 +75,13 @@ Blockchain.prototype.run_command = function(address, use_tmp) { cmd += "--unlock " + address + " "; } + if (config.bootNodes !== undefined && config.bootNodes.boot == true){ + cmd += "--bootnodes "; + for (var i = 0; i < config.bootNodes.enodes.length; i++){ + cmd += config.bootNodes.enodes[i] + " "; + } + } + if (config.console_toggle) { cmd += "console"; } @@ -87,6 +100,10 @@ Blockchain.prototype.run_command = function(address, use_tmp) { Blockchain.prototype.get_address = function() { var config = this.config; + + if(config.account.address) + return config.account.address; + var address = null; if (config.account.init) { diff --git a/lib/chain_manager.js b/lib/chain_manager.js index edc48bbd..1e909a7c 100644 --- a/lib/chain_manager.js +++ b/lib/chain_manager.js @@ -1,12 +1,10 @@ var fs = require('fs'); -var web3 = require('web3'); var sha3_256 = require('js-sha3').sha3_256; ChainManager = function() { this.chainManagerConfig = {}; this.currentChain = {}; this.file = ""; - this.web3 = null; } ChainManager.prototype.loadConfigFile = function(filename) { @@ -25,17 +23,18 @@ ChainManager.prototype.loadConfig = function(config) { return this; }; -ChainManager.prototype.init = function(env, config) { - web3.setProvider(new web3.providers.HttpProvider("http://" + config.rpcHost + ":" + config.rpcPort)); - - var chainId = web3.eth.getBlock(0).hash; +ChainManager.prototype.init = function(env, config, web3) { + var block = web3.eth.getBlock(0); + if(!block){ + throw new Error("Cannot get the genesis block, is embark blockchain running ?"); + } + var chainId = block.hash; if (this.chainManagerConfig[chainId] === undefined) { this.chainManagerConfig[chainId] = {contracts: {}}; } this.currentChain = this.chainManagerConfig[chainId]; - this.web3 = web3; } ChainManager.prototype.addContract = function(contractName, code, args, address) { diff --git a/lib/compiler.js b/lib/compiler.js index 31b45e72..253bbc13 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -1,6 +1,8 @@ var shelljs = require('shelljs'); var shelljs_global = require('shelljs/global'); var web3 = require('web3'); +var fs = require('fs'); +var solc = require('solc'); Compiler = function(blockchainConfig) { this.blockchainConfig = blockchainConfig; @@ -8,55 +10,28 @@ Compiler = function(blockchainConfig) { Compiler.prototype.init = function(env) { var config = this.blockchainConfig.config(env); - - try { - web3.setProvider(new web3.providers.HttpProvider("http://" + config.rpcHost + ":" + config.rpcPort)); - primaryAddress = web3.eth.coinbase; - web3.eth.defaultAccount = primaryAddress; - } catch (e) { - throw new Error("can't connect to " + config.rpcHost + ":" + config.rpcPort + " check if an ethereum node is running"); - } - console.log("address is : " + primaryAddress); }; Compiler.prototype.compile_solidity = function(contractFile) { - var cmd, result, output, version, json, compiled_object; + var source = fs.readFileSync(contractFile).toString(); + var output = solc.compile(source, 1); - cmd = "solc --version"; + var json = output.contracts; - result = exec(cmd, {silent: true}); - output = result.output; - version = output.split('\n')[1].split(' ')[1].slice(0,5); - - if (version == '0.1.1') { - cmd = "solc --input-file " + contractFile + " --combined-json binary,json-abi"; - } - else { - cmd = "solc --input-file " + contractFile + " --combined-json bin,abi"; - } - - result = exec(cmd, {silent: true}); - output = result.output; - - if (result.code === 1) { - throw new Error(result.output); - } - - json = JSON.parse(output).contracts; compiled_object = {} for (var className in json) { var contract = json[className]; compiled_object[className] = {}; - compiled_object[className].code = contract.binary || contact.bin; + compiled_object[className].code = contract.bytecode; compiled_object[className].info = {}; - compiled_object[className].info.abiDefinition = JSON.parse(contract["abi"] || contract["json-abi"]); + compiled_object[className].info.abiDefinition = JSON.parse(contract.interface); } return compiled_object; -} +}; Compiler.prototype.compile_serpent = function(contractFile) { var cmd, result, output, json, compiled_object; diff --git a/lib/config/blockchain.js b/lib/config/blockchain.js index d0dcdd50..99f861c3 100644 --- a/lib/config/blockchain.js +++ b/lib/config/blockchain.js @@ -30,6 +30,7 @@ BlockchainConfig.prototype.config = function(env) { else { networkId = config.network_id; } + config = { rpcHost: config.rpc_host, @@ -41,14 +42,16 @@ BlockchainConfig.prototype.config = function(env) { genesisBlock: config.genesis_block, datadir: config.datadir, chains: config.chains, + bootNodes: config.bootnodes, deployTimeout: config.deploy_timeout || 20, networkId: networkId, - maxPeers: 4, + maxPeers: config.max_peers || 4, port: config.port || "30303", console_toggle: config.console || false, mine_when_needed: config.mine_when_needed || false, whisper: config.whisper || false, - account: config.account + account: config.account, + geth_extra_opts: config.geth_extra_opts } return config; diff --git a/lib/deploy.js b/lib/deploy.js index d75f7e31..0c6087e2 100644 --- a/lib/deploy.js +++ b/lib/deploy.js @@ -4,63 +4,78 @@ var grunt = require('grunt'); var readYaml = require('read-yaml'); var Config = require('./config/config.js'); -// Ugly, but sleep lib has issues on osx -sleep = function sleep(ms) { - var start = new Date().getTime(); - while (new Date().getTime() < start + ms); -} - -Deploy = function(env, contractFiles, blockchainConfig, contractsConfig, chainManager) { - //this.blockchainConfig = (new Config.Blockchain()).loadConfigFile('config/blockchain.yml').config(env); - this.blockchainConfig = blockchainConfig; - this.chainManager = chainManager; - this.chainManager.init(env, this.blockchainConfig); - - //this.contractsManager = (new Config.Contracts(contractFiles, blockchainConfig)).loadConfigFile('config/contracts.yml'); +Deploy = function(env, contractFiles, blockchainConfig, contractsConfig, chainManager, withProvider, withChain, _web3) { + if (_web3 !== undefined) { + web3 = _web3; + } this.contractsManager = contractsConfig; this.contractsConfig = this.contractsManager.config(env); this.deployedContracts = {}; + this.blockchainConfig = blockchainConfig; try { - web3.setProvider(new web3.providers.HttpProvider("http://" + this.blockchainConfig.rpcHost + ":" + this.blockchainConfig.rpcPort)); + if (withProvider) { + web3.setProvider(new web3.providers.HttpProvider("http://" + this.blockchainConfig.rpcHost + ":" + this.blockchainConfig.rpcPort)); + } primaryAddress = web3.eth.coinbase; web3.eth.defaultAccount = primaryAddress; } catch (e) { throw new Error("==== can't connect to " + this.blockchainConfig.rpcHost + ":" + this.blockchainConfig.rpcPort + " check if an ethereum node is running"); } + this.chainManager = chainManager; + this.chainManager.init(env, this.blockchainConfig, web3); + this.withChain = withChain; + console.log("primary account address is : " + primaryAddress); }; -Deploy.prototype.deploy_contract = function(contractObject, contractParams) { - var transactionHash = contractObject["new"].apply(contractObject, contractParams).transactionHash; - var receipt = null; - var time = 0; - while ((receipt = web3.eth.getTransactionReceipt(transactionHash)) === null || receipt.contractAddress === null) { - sleep(1000); - time += 1; - if (time >= this.blockchainConfig.deployTimeout) { - return false; +Deploy.prototype.deploy_contract = function(contractObject, contractParams, cb) { + var callback = function(e, contract) { + if(!e && contract.address !== undefined) { + cb(contract.address); } - } - return receipt; + else { + console.log("error deploying"); + exit(); + } + }; + + contractParams.push(callback); + + contractObject["new"].apply(contractObject, contractParams); } -Deploy.prototype.deploy_contracts = function(env) { +Deploy.prototype.deploy_contracts = function(env, cb) { this.contractsManager.compileContracts(env); - all_contracts = this.contractsManager.all_contracts; + var all_contracts = this.contractsManager.all_contracts; this.contractDB = this.contractsManager.contractDB; - contractDependencies = this.contractsManager.contractDependencies; - this.deployedContracts = {}; - for (k = 0; k < all_contracts.length; k++) { - className = all_contracts[k]; - contract = this.contractDB[className]; + this.deploy_contract_list(all_contracts.length, env, all_contracts, cb); +} + +Deploy.prototype.deploy_contract_list = function(index, env, all_contracts, cb) { + if(index === 0) { + cb(); + } + else { + var _this = this; + this.deploy_contract_list(index - 1, env, all_contracts, function() { + var className = all_contracts[index - 1]; + _this.deploy_a_contract(env, className, cb); + }); + } +} + +Deploy.prototype.deploy_a_contract = function(env, className, cb) { + var contractDependencies = this.contractsManager.contractDependencies; + var contract = this.contractDB[className]; if (contract.deploy === false) { console.log("skipping " + className); - continue; + cb(); + return; } var realArgs = []; @@ -76,8 +91,8 @@ Deploy.prototype.deploy_contracts = function(env) { if (contract.address !== undefined) { this.deployedContracts[className] = contract.address; - //console.log("contract " + className + " at " + contractAddress); console.log("contract " + className + " at " + contract.address); + cb(); } else { var chainContract = this.chainManager.getContract(className, contract.compiled.code, realArgs); @@ -86,6 +101,7 @@ Deploy.prototype.deploy_contracts = function(env) { console.log("contract " + className + " is unchanged and already deployed at " + chainContract.address); this.deployedContracts[className] = chainContract.address; this.execute_cmds(contract.onDeploy); + cb(); } else { @@ -101,31 +117,31 @@ Deploy.prototype.deploy_contracts = function(env) { console.log('trying to obtain ' + className + ' address...'); - while((receipt = this.deploy_contract(contractObject, contractParams)) === false) { - console.log("timeout... failed to deploy contract.. retrying..."); - } + var _this = this; + this.deploy_contract(contractObject, contractParams, function(contractAddress) { + if (web3.eth.getCode(contractAddress) === "0x") { + console.log("========="); + console.log("contract was deployed at " + contractAddress + " but doesn't seem to be working"); + console.log("try adjusting your gas values"); + console.log("========="); + } + else { + console.log("deployed " + className + " at " + contractAddress); + _this.chainManager.addContract(className, contract.compiled.code, realArgs, contractAddress); + if (_this.withChain) { + _this.chainManager.save(); + } + } - var contractAddress = receipt.contractAddress; + _this.deployedContracts[className] = contractAddress; - if (web3.eth.getCode(contractAddress) === "0x") { - console.log("========="); - console.log("contract was deployed at " + contractAddress + " but doesn't seem to be working"); - console.log("try adjusting your gas values"); - console.log("========="); - } - else { - console.log("deployed " + className + " at " + contractAddress); - this.chainManager.addContract(className, contract.compiled.code, realArgs, contractAddress); - this.chainManager.save(); - } + _this.execute_cmds(contract.onDeploy); - this.deployedContracts[className] = contractAddress; + cb(); + }); - this.execute_cmds(contract.onDeploy); } } - } - }; Deploy.prototype.execute_cmds = function(cmds) { @@ -147,12 +163,17 @@ Deploy.prototype.execute_cmds = function(cmds) { } } -Deploy.prototype.generate_abi_file = function() { - var result; - +Deploy.prototype.generate_provider_file = function() { + var result = ""; result = "web3.setProvider(new web3.providers.HttpProvider('http://" + this.blockchainConfig.rpcHost + ":" + this.blockchainConfig.rpcPort + "'));"; result += "web3.eth.defaultAccount = web3.eth.accounts[0];"; + return result; +} + +Deploy.prototype.generate_abi_file = function() { + var result = ""; + for(className in this.deployedContracts) { var deployedContract = this.deployedContracts[className]; var contract = this.contractDB[className]; diff --git a/lib/index.js b/lib/index.js index fcc82d3b..5f02c392 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,35 +1,34 @@ -var hashmerge = require('hashmerge'); var readYaml = require('read-yaml'); var shelljs = require('shelljs'); var shelljs_global = require('shelljs/global'); var web3 = require('web3'); var commander = require('commander'); var wrench = require('wrench'); -var python = require('python'); -var syncMe = require('sync-me'); -var methodmissing = require('methodmissing'); -var jasmine = require('jasmine'); +var grunt = require('grunt'); -var Tests = require('./test.js'); +//var Tests = require('./test.js'); var Blockchain = require('./blockchain.js'); var Deploy = require('./deploy.js'); var Release = require('./ipfs.js'); var Config = require('./config/config.js'); var Compiler = require('./compiler.js'); var ChainManager = require('./chain_manager.js'); +var Test = require('./test.js'); Embark = { - init: function() { + init: function(_web3) { this.blockchainConfig = (new Config.Blockchain()); this.compiler = (new Compiler(this.blockchainConfig)); this.contractsConfig = (new Config.Contracts(this.blockchainConfig, this.compiler)); + if (_web3 !== undefined) { + this.web3 = _web3; + } + else { + this.web3 = web3; + } this.chainManager = (new ChainManager()); }, - tests: function(contractFiles) { - return new Tests(this.contractsConfig, contractFiles); - }, - startBlockchain: function(env, use_tmp) { var chain = new Blockchain(this.blockchainConfig.config(env)); chain.startChain(use_tmp); @@ -45,13 +44,20 @@ Embark = { return chain.getStartChainCommand(use_tmp); }, - deployContracts: function(env, contractFiles, destFile, chainFile) { + deployContracts: function(env, contractFiles, destFile, chainFile, withProvider, withChain, cb) { this.contractsConfig.init(contractFiles, env); this.chainManager.loadConfigFile(chainFile) - var deploy = new Deploy(env, contractFiles, this.blockchainConfig.config(env), this.contractsConfig, this.chainManager); - deploy.deploy_contracts(env); - return deploy.generate_abi_file(destFile); + var deploy = new Deploy(env, contractFiles, this.blockchainConfig.config(env), this.contractsConfig, this.chainManager, withProvider, withChain, this.web3); + deploy.deploy_contracts(env, function() { + console.log("contracts deployed; generating abi file"); + var result = "" + if (withProvider) { + result += deploy.generate_provider_file(); + } + result += deploy.generate_abi_file(); + cb(result); + }); }, geth: function(env, args) { @@ -59,7 +65,19 @@ Embark = { chain.execGeth(args); }, - release: Release + release: Release, + + initTests: function() { + var embarkConfig = readYaml.sync("./embark.yml"); + var fileExpression = embarkConfig.contracts || ["app/contracts/**/*.sol", "app/contracts/**/*.se"]; + var contractFiles = grunt.file.expand(fileExpression); + var blockchainFile = embarkConfig.blockchainConfig || 'config/blockchain.yml'; + var contractFile = embarkConfig.contractsConfig || 'config/contracts.yml'; + + var tests = new Test(contractFiles, blockchainFile, contractFile, 'development'); + + return tests; + } } module.exports = Embark; diff --git a/lib/test.js b/lib/test.js index 6c957256..bb7e8362 100644 --- a/lib/test.js +++ b/lib/test.js @@ -1,73 +1,24 @@ -var python = require('python').shell; -var mm = require('methodmissing'); -var sync = require('sync-me'); +var ethersim = require('ethersim'); +var web3 = require('web3'); -py_exec = function(cmd) { - return sync(python, cmd)[1].trim(); -}; +Test = function(contractFiles, blockchainFile, contractFile, _env) { + this.env = _env || 'development'; + this.web3 = web3; + this.web3.setProvider(ethersim.web3Provider()); + this.contractFiles = contractFiles; -TestContractWrapper = (function() { - function TestContractWrapper(contract, className, args) { - this.contract = contract.compiled; - this.className = className; - this.args = args; - this.initializeContract(); - } + Embark.init(this.web3); + Embark.blockchainConfig.loadConfigFile(blockchainFile); + Embark.contractsConfig.loadConfigFile(contractFile); - TestContractWrapper.prototype.initializeContract = function() { - example_abi = JSON.stringify(this.contract.info.abiDefinition); - example_binary = this.contract.code.slice(2); + Embark.contractsConfig.init(this.contractFiles, this.env); +} - py_exec("example_abi = '" + example_abi + "'"); - py_exec("example_abi"); - py_exec("example_binary = '" + example_binary + "'.decode('hex')"); - py_exec("example_binary"); - - if (this.args === undefined) { - py_exec(this.className + "_contract = EvmContract(example_abi, example_binary, '" + this.className + "')"); - } - else { - py_exec(this.className + "_contract = EvmContract(example_abi, example_binary, '" + this.className + "', [" + this.args.join(",") + "])"); - } - - this.contractVariable = this.className + "_contract"; - }; - - TestContractWrapper.prototype.execCmd = function(method, args) { - var arg_list = []; - for (var key in args) { - var value = args[key]; - arg_list.push(value); - } - - data = py_exec(this.className + "_contract." + method + "(" + arg_list.join(",") + ")"); - return data; - }; - - return TestContractWrapper; - -})(); - -TestContract = function(contract, className, args) { - var wrapper = new TestContractWrapper(contract, className, args); - var Obj = mm(wrapper, function (key, args) { - return wrapper.execCmd(key, args); +Test.prototype.deployAll = function(cb) { + Embark.deployContracts('development', this.contractFiles, "/tmp/abi.js", "chains.json", false, false, function(abi) { + eval(abi); + cb(); }); - return Obj; } -test = function(contractsConfig, contractFiles) { - contractsConfig.init(contractFiles, 'development'); - - contractsConfig.compileContracts(); - this.contractDB = contractsConfig.contractDB; -} - -test.prototype.request = function(className, args) { - var contract = this.contractDB[className]; - py_exec("from ethertdd import EvmContract"); - return TestContract(contract, className, args); -} - -module.exports = test; - +module.exports = Test; diff --git a/package.json b/package.json index 0f15b435..adfbde25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "embark-framework", - "version": "0.9.2", + "version": "1.0.2", "description": "", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" @@ -15,19 +15,16 @@ "dependencies": { "commander": "^2.8.1", "grunt": "^0.4.5", - "hashmerge": "^1.0.2", - "jasmine": "^2.3.1", "js-sha3": "^0.3.1", "meteor-build-client": "^0.1.6", - "methodmissing": "^0.0.3", "mkdirp": "^0.5.1", - "python": "^0.0.4", "read-yaml": "^1.0.0", "shelljs": "^0.5.0", - "sync-me": "^0.1.1", + "solc": "^0.1.3-2", "toposort": "^0.2.10", "web3": "^0.8.1", - "wrench": "^1.5.8" + "wrench": "^1.5.8", + "ethersim": "^0.1.1" }, "author": "Iuri Matias ", "contributors": [],