diff --git a/lib/contracts/accountParser.js b/lib/contracts/accountParser.js index e2460bd6..f407cf54 100644 --- a/lib/contracts/accountParser.js +++ b/lib/contracts/accountParser.js @@ -21,10 +21,32 @@ 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) { + throw new Error(__('Unrecognized balance string "%s"', balanceString)); + } + 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 +55,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 +68,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 +81,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/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) { 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); } 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'}; } 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; diff --git a/lib/tests/test.js b/lib/tests/test.js index 2e81f943..86e52ca0 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,31 @@ 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) => { + return {balance: account.hexBalance, secretKey: account.privateKey}; + }); + } + this.sim = getSimulator(); + this.web3.setProvider(this.sim.provider(this.simOptions)); + } + } + + initDeployServices() { this.engine.startService("web3", { web3: this.web3 }); @@ -67,7 +83,6 @@ class Test { trackContracts: false, ipcRole: 'client' }); - this.engine.startService("codeGenerator"); } init(callback) { @@ -100,6 +115,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/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 + } + }); }); }); diff --git a/test_apps/test_app/test/another_storage_spec.js b/test_apps/test_app/test/another_storage_spec.js index 82ee75fb..10ee0b35 100644 --- a/test_apps/test_app/test/another_storage_spec.js +++ b/test_apps/test_app/test/another_storage_spec.js @@ -1,9 +1,19 @@ -/*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", + balance: "5ether" + } + ] + }, contracts: { "SimpleStorage": { args: [100] @@ -12,6 +22,8 @@ config({ args: ["$SimpleStorage"] } } +}, (err, theAccounts) => { + accounts = theAccounts; }); contract("AnotherStorage", function() { @@ -21,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); + }); });