From ac631f90dcd24f0df2dd3ab8c49588d5a87630a0 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 6 Jun 2018 15:22:15 -0400 Subject: [PATCH 1/9] fix missing error callback --- lib/contracts/deploy_manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/contracts/deploy_manager.js b/lib/contracts/deploy_manager.js index ff87adf4..7f69e9e6 100644 --- a/lib/contracts/deploy_manager.js +++ b/lib/contracts/deploy_manager.js @@ -29,8 +29,8 @@ class DeployManager { async.eachOfSeries(contracts, function (contract, key, callback) { contract._gasLimit = self.gasLimit; - self.events.request('deploy:contract', contract, () => { - callback(); + self.events.request('deploy:contract', contract, (err) => { + callback(err); }); }, function (err, _results) { From 30a82635690db968dcac8e10339c526104b39c9f Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 6 Jun 2018 15:33:48 -0400 Subject: [PATCH 2/9] enable using accounts and balances --- lib/tests/test.js | 39 +++++++++++++++---- .../test_app/test/another_storage_spec.js | 7 ++++ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/lib/tests/test.js b/lib/tests/test.js index 2e81f943..f98c6a32 100644 --- a/lib/tests/test.js +++ b/lib/tests/test.js @@ -6,6 +6,7 @@ const utils = require('../utils/utils'); const constants = require('../constants'); const Events = require('../core/events'); const cloneDeep = require('clone-deep'); +const AccountParser = require('../contracts/accountParser'); function getSimulator() { try { @@ -36,12 +37,7 @@ class Test { this.compiledContracts = {}; this.web3 = new Web3(); - if (this.simOptions.node) { - this.web3.setProvider(new this.web3.providers.HttpProvider(this.simOptions.node)); - } else { - this.sim = getSimulator(); - this.web3.setProvider(this.sim.provider(this.simOptions)); - } + this.initWeb3Provider(); this.engine = new Engine({ env: this.options.env || 'test', @@ -55,11 +51,32 @@ class Test { }); this.versions_default = this.engine.config.contractsConfig.versions; + const deploymentConfig = this.engine.config.contractsConfig.versions; // Reset contract config to nothing to make sure we deploy only what we want - this.engine.config.contractsConfig = {contracts: {}, versions: this.versions_default}; + this.engine.config.contractsConfig = {contracts: {}, versions: this.versions_default, deployment: deploymentConfig}; this.engine.startService("libraryManager"); this.engine.startService("codeRunner"); + this.initDeployServices(); + this.engine.startService("codeGenerator"); + } + + initWeb3Provider() { + if (this.simOptions.node) { + this.web3.setProvider(new this.web3.providers.HttpProvider(this.simOptions.node)); + } else { + if (this.simOptions.accounts) { + this.simOptions.accounts = this.simOptions.accounts.map((account, index) => { + return {balance: this.options.deployment.accounts[index].balance || 0xFFFFFFFFFFFFFFFFFF, + secretKey: account.privateKey}; + }); + } + this.sim = getSimulator(); + this.web3.setProvider(this.sim.provider(this.simOptions)); + } + } + + initDeployServices() { this.engine.startService("web3", { web3: this.web3 }); @@ -67,7 +84,6 @@ class Test { trackContracts: false, ipcRole: 'client' }); - this.engine.startService("codeGenerator"); } init(callback) { @@ -100,6 +116,13 @@ class Test { this.simOptions = this.options.simulatorOptions || {}; this.ready = false; + if (this.options.deployment && this.options.deployment.accounts) { + // Account setup + this.simOptions.accounts = AccountParser.parseAccountsConfig(this.options.deployment.accounts, this.web3); + this.initWeb3Provider(); + this.initDeployServices(); + } + // Reset contracts this.engine.contractsManager.contracts = cloneDeep(this.builtContracts); this.engine.contractsManager.compiledContracts = cloneDeep(this.compiledContracts); diff --git a/test_apps/test_app/test/another_storage_spec.js b/test_apps/test_app/test/another_storage_spec.js index 82ee75fb..cce1aaa6 100644 --- a/test_apps/test_app/test/another_storage_spec.js +++ b/test_apps/test_app/test/another_storage_spec.js @@ -4,6 +4,13 @@ const AnotherStorage = embark.require('Embark/contracts/AnotherStorage'); const SimpleStorage = embark.require('Embark/contracts/SimpleStorage'); config({ + deployment: { + "accounts": [ + { + "mnemonic": "example exile argue silk regular smile grass bomb merge arm assist farm" + } + ] + }, contracts: { "SimpleStorage": { args: [100] From 4ffb5c401fae64e24927fa2838a576fc20e9caf4 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 6 Jun 2018 16:43:08 -0400 Subject: [PATCH 3/9] enable setting balance in mutliple formats --- lib/tests/test.js | 52 ++++++++++++++++++- .../test_app/test/another_storage_spec.js | 15 +++++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/lib/tests/test.js b/lib/tests/test.js index f98c6a32..9dbc400e 100644 --- a/lib/tests/test.js +++ b/lib/tests/test.js @@ -61,14 +61,62 @@ class Test { this.engine.startService("codeGenerator"); } + // eslint-disable-next-line complexity + getMutliplicator(keyword) { + switch (keyword.toLowerCase()) { + case 'wei': return 1; + case 'ether': + case 'eth': return 1000000000000000000; + case 'finney': + case 'milli': + case 'milliether': return 1000000000000000; + case 'szabo': + case 'microether,': + case 'micro': return 1000000000000; + case 'gwei': + case 'nanoether': + case 'shannon': + case 'nano': return 1000000000; + case 'mwei': + case 'babbage': + case 'picoether': return 1000000; + case 'kwei': + case 'ada': + case 'femtoether': return 1000; + case 'kether': + case 'grand': + case 'einstein': return 1000000000000000000000; + case 'mether': return 1000000000000000000000000; + case 'gether': return 1000000000000000000000000000; + case 'tether': return 1000000000000000000000000000000; + default: console.warn('\n' + __(`Unrecognised keyword ${keyword} in balance. Will assume Wei`).yellow); + return 1; + } + } + + getBalance(balanceString) { + if (!balanceString) { + return 0xFFFFFFFFFFFFFFFFFF; + } + if (this.web3.utils.isHexStrict(balanceString)) { + return balanceString; + } + const match = balanceString.match(/([0-9]+) ?([a-zA-Z]*)/); + if (!match[2]) { + return this.web3.utils.toHex(parseInt(match[1], 10)); + } + + return this.web3.utils.toHex(parseInt(match[1], 10) * this.getMutliplicator(match[2])); + } + initWeb3Provider() { if (this.simOptions.node) { this.web3.setProvider(new this.web3.providers.HttpProvider(this.simOptions.node)); } else { if (this.simOptions.accounts) { this.simOptions.accounts = this.simOptions.accounts.map((account, index) => { - return {balance: this.options.deployment.accounts[index].balance || 0xFFFFFFFFFFFFFFFFFF, - secretKey: account.privateKey}; + const balance = this.getBalance(this.options.deployment.accounts[index].balance); + return {balance, secretKey: account.privateKey}; }); } this.sim = getSimulator(); diff --git a/test_apps/test_app/test/another_storage_spec.js b/test_apps/test_app/test/another_storage_spec.js index cce1aaa6..10ee0b35 100644 --- a/test_apps/test_app/test/another_storage_spec.js +++ b/test_apps/test_app/test/another_storage_spec.js @@ -1,13 +1,16 @@ -/*global contract, config, it, embark*/ +/*global contract, config, it, embark, web3*/ const assert = require('assert'); const AnotherStorage = embark.require('Embark/contracts/AnotherStorage'); const SimpleStorage = embark.require('Embark/contracts/SimpleStorage'); +let accounts; + config({ deployment: { "accounts": [ { - "mnemonic": "example exile argue silk regular smile grass bomb merge arm assist farm" + "mnemonic": "example exile argue silk regular smile grass bomb merge arm assist farm", + balance: "5ether" } ] }, @@ -19,6 +22,8 @@ config({ args: ["$SimpleStorage"] } } +}, (err, theAccounts) => { + accounts = theAccounts; }); contract("AnotherStorage", function() { @@ -28,4 +33,10 @@ contract("AnotherStorage", function() { let result = await AnotherStorage.methods.simpleStorageAddress().call(); assert.equal(result.toString(), SimpleStorage.options.address); }); + + it('should set the balance correctly', async function () { + const balance = await web3.eth.getBalance(accounts[0]); + assert.ok(balance < 5000000000000000000); + assert.ok(balance > 4000000000000000000); + }); }); From 2a61b2251cbdf69a82f7e4a23f2e2bc39efc2efd Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 6 Jun 2018 16:53:28 -0400 Subject: [PATCH 4/9] use web3 utils function instead --- lib/tests/test.js | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/lib/tests/test.js b/lib/tests/test.js index 9dbc400e..fd9e16a6 100644 --- a/lib/tests/test.js +++ b/lib/tests/test.js @@ -61,39 +61,6 @@ class Test { this.engine.startService("codeGenerator"); } - // eslint-disable-next-line complexity - getMutliplicator(keyword) { - switch (keyword.toLowerCase()) { - case 'wei': return 1; - case 'ether': - case 'eth': return 1000000000000000000; - case 'finney': - case 'milli': - case 'milliether': return 1000000000000000; - case 'szabo': - case 'microether,': - case 'micro': return 1000000000000; - case 'gwei': - case 'nanoether': - case 'shannon': - case 'nano': return 1000000000; - case 'mwei': - case 'babbage': - case 'picoether': return 1000000; - case 'kwei': - case 'ada': - case 'femtoether': return 1000; - case 'kether': - case 'grand': - case 'einstein': return 1000000000000000000000; - case 'mether': return 1000000000000000000000000; - case 'gether': return 1000000000000000000000000000; - case 'tether': return 1000000000000000000000000000000; - default: console.warn('\n' + __(`Unrecognised keyword ${keyword} in balance. Will assume Wei`).yellow); - return 1; - } - } - getBalance(balanceString) { if (!balanceString) { return 0xFFFFFFFFFFFFFFFFFF; @@ -106,7 +73,7 @@ class Test { return this.web3.utils.toHex(parseInt(match[1], 10)); } - return this.web3.utils.toHex(parseInt(match[1], 10) * this.getMutliplicator(match[2])); + return this.web3.utils.toHex(this.web3.utils.toWei(match[1], match[2])); } initWeb3Provider() { From 3d70028cc5713d24a2374eb33c87f84aa138375c Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 7 Jun 2018 10:33:05 -0400 Subject: [PATCH 5/9] fixing small stuff --- lib/core/plugin.js | 1 - lib/modules/solidity/solcP.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/core/plugin.js b/lib/core/plugin.js index b0197522..296f52b5 100644 --- a/lib/core/plugin.js +++ b/lib/core/plugin.js @@ -60,7 +60,6 @@ Plugin.prototype.hasContext = function(context) { Plugin.prototype.loadPlugin = function() { if (!this.isContextValid()) { - console.log(this.acceptedContext); this.logger.warn(__('Plugin {{name}} can only be loaded in the context of "{{contextes}}"', {name: this.name, contextes: this.acceptedContext.join(', ')})); return false; } diff --git a/lib/modules/solidity/solcP.js b/lib/modules/solidity/solcP.js index 2d538324..43f9c024 100644 --- a/lib/modules/solidity/solcP.js +++ b/lib/modules/solidity/solcP.js @@ -19,7 +19,7 @@ class SolcProcess extends ProcessWrapper { return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()}; } if (fs.existsSync(path.join(constants.httpContractsDirectory, filename))) { - return {contents: fs.readFileSync(path.join('./.embark/contracts', filename)).toString()}; + return {contents: fs.readFileSync(path.join(constants.httpContractsDirectory, filename)).toString()}; } return {error: 'File not found'}; } From bb3e87d85e1e0f15224ca0a91f39f2fb9152d16a Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 7 Jun 2018 10:53:20 -0400 Subject: [PATCH 6/9] move getBalance in accountParser --- lib/contracts/accountParser.js | 25 ++++++++++++++++++++++--- lib/tests/test.js | 20 ++------------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/contracts/accountParser.js b/lib/contracts/accountParser.js index e2460bd6..da2ded9c 100644 --- a/lib/contracts/accountParser.js +++ b/lib/contracts/accountParser.js @@ -21,10 +21,29 @@ class AccountParser { return accounts; } + static getHexBalance(balanceString, web3) { + if (!balanceString) { + return 0xFFFFFFFFFFFFFFFFFF; + } + if (web3.utils.isHexStrict(balanceString)) { + return balanceString; + } + const match = balanceString.match(/([0-9]+) ?([a-zA-Z]*)/); + if (!match[2]) { + return web3.utils.toHex(parseInt(match[1], 10)); + } + + return web3.utils.toHex(web3.utils.toWei(match[1], match[2])); + } + static getAccount(accountConfig, web3, logger) { if (!logger) { logger = console; } + let hexBalance = null; + if (accountConfig.balance) { + hexBalance = AccountParser.getHexBalance(accountConfig.balance, web3); + } if (accountConfig.privateKey) { if (!accountConfig.privateKey.startsWith('0x')) { accountConfig.privateKey = '0x' + accountConfig.privateKey; @@ -33,7 +52,7 @@ class AccountParser { logger.warn(`Private key ending with ${accountConfig.privateKey.substr(accountConfig.privateKey.length - 5)} is not a HEX string`); return null; } - return web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey); + return Object.assign(web3.eth.accounts.privateKeyToAccount(accountConfig.privateKey), {hexBalance}); } if (accountConfig.privateKeyFile) { let fileContent = fs.readFileSync(fs.dappPath(accountConfig.privateKeyFile)).toString(); @@ -46,7 +65,7 @@ class AccountParser { logger.warn(`Private key is not a HEX string in file ${accountConfig.privateKeyFile} at index ${index}`); return null; } - return web3.eth.accounts.privateKeyToAccount(key); + return Object.assign(web3.eth.accounts.privateKeyToAccount(key), {hexBalance}); }); } if (accountConfig.mnemonic) { @@ -59,7 +78,7 @@ class AccountParser { const accounts = []; for (let i = addressIndex; i < addressIndex + numAddresses; i++) { const wallet = hdwallet.derivePath(wallet_hdpath + i).getWallet(); - accounts.push(web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex'))); + accounts.push(Object.assign(web3.eth.accounts.privateKeyToAccount('0x' + wallet.getPrivateKey().toString('hex')), {hexBalance})); } return accounts; } diff --git a/lib/tests/test.js b/lib/tests/test.js index fd9e16a6..86e52ca0 100644 --- a/lib/tests/test.js +++ b/lib/tests/test.js @@ -61,29 +61,13 @@ class Test { this.engine.startService("codeGenerator"); } - getBalance(balanceString) { - if (!balanceString) { - return 0xFFFFFFFFFFFFFFFFFF; - } - if (this.web3.utils.isHexStrict(balanceString)) { - return balanceString; - } - const match = balanceString.match(/([0-9]+) ?([a-zA-Z]*)/); - if (!match[2]) { - return this.web3.utils.toHex(parseInt(match[1], 10)); - } - - return this.web3.utils.toHex(this.web3.utils.toWei(match[1], match[2])); - } - initWeb3Provider() { if (this.simOptions.node) { this.web3.setProvider(new this.web3.providers.HttpProvider(this.simOptions.node)); } else { if (this.simOptions.accounts) { - this.simOptions.accounts = this.simOptions.accounts.map((account, index) => { - const balance = this.getBalance(this.options.deployment.accounts[index].balance); - return {balance, secretKey: account.privateKey}; + this.simOptions.accounts = this.simOptions.accounts.map((account) => { + return {balance: account.hexBalance, secretKey: account.privateKey}; }); } this.sim = getSimulator(); From a5ecd9f1f4619c57478a203590fa37c42a3b6999 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 7 Jun 2018 11:30:33 -0400 Subject: [PATCH 7/9] add tests for getBalance --- lib/contracts/accountParser.js | 3 ++ test/accountParser.js | 55 ++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/lib/contracts/accountParser.js b/lib/contracts/accountParser.js index da2ded9c..f407cf54 100644 --- a/lib/contracts/accountParser.js +++ b/lib/contracts/accountParser.js @@ -29,6 +29,9 @@ class AccountParser { return balanceString; } const match = balanceString.match(/([0-9]+) ?([a-zA-Z]*)/); + if (!match) { + throw new Error(__('Unrecognized balance string "%s"', balanceString)); + } if (!match[2]) { return web3.utils.toHex(parseInt(match[1], 10)); } diff --git a/test/accountParser.js b/test/accountParser.js index d79b002f..28801384 100644 --- a/test/accountParser.js +++ b/test/accountParser.js @@ -3,6 +3,9 @@ const assert = require('assert'); const sinon = require('sinon'); const AccountParser = require('../lib/contracts/accountParser'); let TestLogger = require('../lib/tests/test_logger.js'); +const Web3 = require('web3'); +const i18n = require('../lib/i18n/i18n.js'); +i18n.setOrDetectLocale('en'); describe('embark.AccountParser', function () { describe('#getAccount', function () { @@ -25,7 +28,7 @@ describe('embark.AccountParser', function () { privateKey: 'myKey' }, web3, testLogger); - assert.deepEqual(account, {key: '0xmyKey'}); + assert.deepEqual(account, {key: '0xmyKey', hexBalance: null}); }); it('should return two accounts from the keys in the file', function () { @@ -34,8 +37,8 @@ describe('embark.AccountParser', function () { }, web3, testLogger); assert.deepEqual(account, [ - {key: '0xkey1'}, - {key: '0xkey2'} + {key: '0xkey1', hexBalance: null}, + {key: '0xkey2', hexBalance: null} ]); }); @@ -45,7 +48,7 @@ describe('embark.AccountParser', function () { }, web3, testLogger); assert.deepEqual(account, - [{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"}]); + [{key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986", hexBalance: null}]); }); it('should return two accounts from the mnemonic using numAddresses', function () { @@ -56,8 +59,8 @@ describe('embark.AccountParser', function () { assert.deepEqual(account, [ - {key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986"}, - {key: "0x88f37cfbaed8c0c515c62a17a3a1ce2f397d08bbf20dcc788b69f11b5a5c9791"} + {key: "0xf942d5d524ec07158df4354402bfba8d928c99d0ab34d0799a6158d56156d986", hexBalance: null}, + {key: "0x88f37cfbaed8c0c515c62a17a3a1ce2f397d08bbf20dcc788b69f11b5a5c9791", hexBalance: null} ]); }); @@ -68,6 +71,46 @@ describe('embark.AccountParser', function () { assert.strictEqual(account, null); }); + }); + describe('getHexBalance', () => { + it('should return default if no balance', () => { + const hexBalance = AccountParser.getHexBalance(null, Web3); + + assert.strictEqual(hexBalance, 0xFFFFFFFFFFFFFFFFFF); + }); + + it('should return the balance string if already hexadecimal', () => { + const hexBalance = AccountParser.getHexBalance('0xFFF', Web3); + + assert.strictEqual(hexBalance, '0xFFF'); + }); + + it('should convert to hex when decimal', () => { + const hexBalance = AccountParser.getHexBalance('500', Web3); + + assert.strictEqual(hexBalance, '0x1f4'); + }); + + it('should convert to hex with eth string', () => { + const hexBalance = AccountParser.getHexBalance('4ether', Web3); + + assert.strictEqual(hexBalance, '0x3782dace9d900000'); + }); + + it('should convert to hex with eth string with space', () => { + const hexBalance = AccountParser.getHexBalance('673 shannon', Web3); + + assert.strictEqual(hexBalance, '0x9cb1ed0a00'); + }); + + it('should fail when string is not good', () => { + try { + AccountParser.getHexBalance('nogood', Web3); + assert.fail('Should have failed at getHexBalance'); + } catch (e) { + // Ok + } + }); }); }); From 9c9bb761a4b766acb606b1b7250208838bcfade3 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 7 Jun 2018 11:38:18 -0400 Subject: [PATCH 8/9] add error when using deployAll --- lib/tests/run_tests.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/tests/run_tests.js b/lib/tests/run_tests.js index 17872ff8..505d8e2c 100644 --- a/lib/tests/run_tests.js +++ b/lib/tests/run_tests.js @@ -37,6 +37,12 @@ module.exports = { global.assert = assert; global.config = test.config.bind(test); + global.deployAll = function () { + console.error(__('%s is not supported anymore', 'deployAll').red); + console.info(__('You can learn about the new revamped tests here: %s', 'https://embark.status.im/docs/testing.html'.underline)); + process.exit(); + }; + // TODO: this global here might not be necessary at all global.web3 = global.embark.web3; From 1b89199f5024366eaa56d46f197eaa8c2e6bc7f3 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 7 Jun 2018 13:06:09 -0400 Subject: [PATCH 9/9] fund accounts in wallet using contracts config --- lib/contracts/fundAccount.js | 12 ++++++++---- lib/contracts/provider.js | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/contracts/fundAccount.js b/lib/contracts/fundAccount.js index cb9baade..35470b54 100644 --- a/lib/contracts/fundAccount.js +++ b/lib/contracts/fundAccount.js @@ -1,8 +1,12 @@ const async = require('async'); -const TARGET = 15000000000000000000; +const TARGET = 0x7FFFFFFFFFFFFFFF; const ALREADY_FUNDED = 'alreadyFunded'; -function fundAccount(web3, accountAddress, callback) { +function fundAccount(web3, accountAddress, hexBalance, callback) { + if (!hexBalance) { + hexBalance = TARGET; + } + const targetBalance = (typeof hexBalance === 'string') ? parseInt(hexBalance, 16) : hexBalance; let accountBalance; let coinbaseAddress; let lastNonce; @@ -14,7 +18,7 @@ function fundAccount(web3, accountAddress, callback) { if (err) { return next(err); } - if (balance >= TARGET) { + if (balance >= targetBalance) { return next(ALREADY_FUNDED); } accountBalance = balance; @@ -56,7 +60,7 @@ function fundAccount(web3, accountAddress, callback) { web3.eth.sendTransaction({ from: coinbaseAddress, to: accountAddress, - value: TARGET - accountBalance, + value: targetBalance - accountBalance, gasPrice: gasPrice, nonce: lastNonce }, next); diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index f9337962..0e60ee86 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -65,7 +65,7 @@ class Provider { return callback(); } async.each(self.accounts, (account, eachCb) => { - fundAccount(self.web3, account.address, eachCb); + fundAccount(self.web3, account.address, account.hexBalance, eachCb); }, callback); }