Merge pull request #454 from embark-framework/features/blockchain-in-run_rebased

Blockchain process + Blockchain/web3 refactor
This commit is contained in:
Iuri Matias 2018-05-23 12:18:02 -04:00 committed by GitHub
commit f2fe9efd22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2728 additions and 2260 deletions

View File

@ -94,6 +94,7 @@ class Cmd {
.command('build [environment]')
.option('--contracts', 'only compile contracts into Embark wrappers')
.option('--logfile [logfile]', __('filename to output logs (default: none)'))
.option('-c, --client [client]', __('Use a specific ethereum client or simulator (supported: %s)', 'geth, testrpc'))
.option('--loglevel [loglevel]', __('level of logging to display') + ' ["error", "warn", "info", "debug", "trace"]', /^(error|warn|info|debug|trace)$/i, 'debug')
.option('--locale [locale]', __('language to use (default: en)'))
.description(__('deploy and build dapp at ') + 'dist/ (default: development)')
@ -103,6 +104,7 @@ class Cmd {
_options.logFile = _options.logfile; // fix casing
_options.logLevel = _options.loglevel; // fix casing
_options.onlyCompile = _options.contracts;
_options.client = _options.client || 'geth';
embark.build(_options);
});
}
@ -111,6 +113,7 @@ class Cmd {
program
.command('run [environment]')
.option('-p, --port [port]', __('port to run the dev webserver (default: %s)', '8000'))
.option('-c, --client [client]', __('Use a specific ethereum client or simulator (supported: %s)', 'geth, testrpc'))
.option('-b, --host [host]', __('host to run the dev webserver (default: %s)', 'localhost'))
.option('--noserver', __('disable the development webserver'))
.option('--nodashboard', __('simple mode, disables the dashboard'))
@ -125,6 +128,8 @@ class Cmd {
env: env || 'development',
serverPort: options.port,
serverHost: options.host,
client: options.client || 'geth',
locale: options.locale,
runWebserver: !options.noserver,
useDashboard: !options.nodashboard,
logFile: options.logfile,
@ -197,12 +202,14 @@ class Cmd {
.option('--logfile [logfile]', __('filename to output logs (default: %s)', 'none'))
.option('--loglevel [loglevel]', __('level of logging to display') + ' ["error", "warn", "info", "debug", "trace"]', /^(error|warn|info|debug|trace)$/i, 'debug')
.option('--locale [locale]', __('language to use (default: en)'))
.option('-c, --client [client]', __('Use a specific ethereum client or simulator (supported: %s)', 'geth, testrpc'))
.description(__('Upload your dapp to a decentralized storage') + ' (e.g embark upload ipfs).')
.action(function (env, _options) {
i18n.setOrDetectLocale(_options.locale);
_options.env = env || 'development';
_options.logFile = _options.logfile; // fix casing
_options.logLevel = _options.loglevel; // fix casing
_options.client = _options.client || 'geth';
embark.upload(_options);
});
}

View File

@ -1,8 +1,9 @@
var shelljs = require('shelljs');
const async = require('async');
const shelljs = require('shelljs');
var fs = require('../../core/fs.js');
const fs = require('../../core/fs.js');
var GethCommands = require('./geth_commands.js');
const GethCommands = require('./geth_commands.js');
/*eslint complexity: ["error", 35]*/
var Blockchain = function(options) {
@ -10,6 +11,7 @@ var Blockchain = function(options) {
this.env = options.env || 'development';
this.client = options.client;
this.isDev = options.isDev;
this.onReadyCallback = options.onReadyCallback;
if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') {
console.log("===> " + __("warning: running default config on a non-development environment"));
@ -41,7 +43,8 @@ var Blockchain = function(options) {
vmdebug: this.blockchainConfig.vmdebug || false,
targetGasLimit: this.blockchainConfig.targetGasLimit || false,
light: this.blockchainConfig.light || false,
fast: this.blockchainConfig.fast || false
fast: this.blockchainConfig.fast || false,
verbosity: this.blockchainConfig.verbosity
};
if (this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') {
@ -54,15 +57,12 @@ var Blockchain = function(options) {
this.client = new options.client({config: this.config, env: this.env, isDev: this.isDev});
};
Blockchain.prototype.runCommand = function(cmd, options) {
Blockchain.prototype.runCommand = function(cmd, options, callback) {
console.log(__("running: %s", cmd.underline).green);
return shelljs.exec(cmd, options, (err, stdout, _stderr) => {
if (err && this.env === 'development' && stdout.indexOf('Failed to unlock') > 0) {
console.warn('\n' + __('Development blockchain has changed to use the --dev option.').yellow);
console.warn(__('You can reset your workspace to fix the problem with').yellow + ' embark reset'.cyan);
console.warn(__('Otherwise, you can change your data directory in blockchain.json (datadir)').yellow);
}
});
if (this.blockchainConfig.silent) {
options.silent = true;
}
return shelljs.exec(cmd, options, callback);
};
Blockchain.prototype.run = function() {
@ -72,62 +72,130 @@ Blockchain.prototype.run = function() {
console.log(__("Embark Blockchain Using: %s", this.client.name.underline).magenta);
console.log("===============================================================================".magenta);
console.log("===============================================================================".magenta);
if (!this.isClientInstalled()) {
console.log(__("could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?", {geth_bin: this.config.geth_bin, client_name: this.client.name}).green);
return;
}
let address = '';
if (!this.isDev) {
address = this.initChainAndGetAddress();
}
this.client.mainCommand(address, function(cmd) {
self.runCommand(cmd, {async: true});
async.waterfall([
function checkInstallation(next) {
self.isClientInstalled((err) => {
if (err) {
console.log(__("could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?", {geth_bin: this.config.geth_bin, client_name: this.client.name}).green);
return next(err);
}
next();
});
},
function init(next) {
if (!self.isDev) {
return self.initChainAndGetAddress((err, addr) => {
address = addr;
next(err);
});
}
next();
},
function getMainCommand(next) {
self.client.mainCommand(address, function(cmd) {
next(null, cmd);
});
}
], function (err, cmd) {
if (err) {
console.error(err);
return;
}
const child = self.runCommand(cmd, {}, (err, stdout, _stderr) => {
if (err && self.env === 'development' && stdout.indexOf('Failed to unlock') > 0) {
console.warn('\n' + __('Development blockchain has changed to use the --dev option.').yellow);
console.warn(__('You can reset your workspace to fix the problem with').yellow + ' embark reset'.cyan);
console.warn(__('Otherwise, you can change your data directory in blockchain.json (datadir)').yellow);
}
});
if (self.onReadyCallback) {
// Geth logs appear in stderr somehow
let lastMessage;
child.stderr.on('data', (data) => {
if (!self.readyCalled && data.indexOf('Mapped network port') > -1) {
self.readyCalled = true;
self.onReadyCallback();
}
lastMessage = data;
console.log('Geth: ' + data);
});
child.on('exit', (code) => {
if (code) {
console.error('Geth exited with error code ' + 1);
console.error(lastMessage);
}
});
}
});
};
Blockchain.prototype.isClientInstalled = function() {
Blockchain.prototype.isClientInstalled = function(callback) {
let versionCmd = this.client.determineVersion();
let result = this.runCommand(versionCmd);
if (result.output === undefined || result.output.indexOf("not found") >= 0) {
return false;
}
return true;
this.runCommand(versionCmd, {}, (err, stdout, stderr) => {
if (err || stderr || !stdout || stdout.indexOf("not found") >= 0) {
return callback('Geth not found');
}
callback();
});
};
Blockchain.prototype.initChainAndGetAddress = function() {
var address = null, result;
Blockchain.prototype.initChainAndGetAddress = function(callback) {
const self = this;
let address = null;
// ensure datadir exists, bypassing the interactive liabilities prompt.
this.datadir = '.embark/' + this.env + '/datadir';
fs.mkdirpSync(this.datadir);
self.datadir = '.embark/' + self.env + '/datadir';
// copy mining script
fs.copySync(fs.embarkPath("js"), ".embark/" + this.env + "/js", {overwrite: true});
// check if an account already exists, create one if not, return address
result = this.runCommand(this.client.listAccountsCommand());
if (result.output === undefined || result.output.match(/{(\w+)}/) === null || result.output.indexOf("Fatal") >= 0) {
console.log(__("no accounts found").green);
if (this.config.genesisBlock) {
async.waterfall([
function makeDir(next) {
fs.mkdirp(self.datadir, (err, _result) => {
next(err);
});
},
function copy(next) {
// copy mining script
fs.copy(fs.embarkPath("js"), ".embark/" + self.env + "/js", {overwrite: true}, next);
},
function listAccounts(next) {
self.runCommand(self.client.listAccountsCommand(), {}, (err, stdout, stderr) => {
if (err || stderr || stdout === undefined || stdout.match(/{(\w+)}/) === null || stdout.indexOf("Fatal") >= 0) {
console.log(__("no accounts found").green);
return next();
}
console.log(__("already initialized").green);
address = stdout.match(/{(\w+)}/)[1];
next();
});
},
function genesisBlock(next) {
if (!self.config.genesisBlock) {
return next();
}
console.log(__("initializing genesis block").green);
result = this.runCommand(this.client.initGenesisCommmand());
self.runCommand(self.client.initGenesisCommmand(), {}, (err, _stdout, _stderr) => {
next(err);
});
},
function newAccount(next) {
self.runCommand(self.client.newAccountCommand(), {}, (err, stdout, _stderr) => {
if (err) {
return next(err);
}
address = stdout.match(/{(\w+)}/)[1];
next();
});
}
result = this.runCommand(this.client.newAccountCommand());
address = result.output.match(/{(\w+)}/)[1];
} else {
console.log(__("already initialized").green);
address = result.output.match(/{(\w+)}/)[1];
}
return address;
], (err) => {
callback(err, address);
});
};
var BlockchainClient = function(blockchainConfig, client, env, isDev) {
var BlockchainClient = function(blockchainConfig, client, env, isDev, onReadyCallback) {
// TODO add other clients at some point
if (client === 'geth') {
return new Blockchain({blockchainConfig, client: GethCommands, env, isDev});
return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback});
} else {
throw new Error('unknown client');
}

View File

@ -0,0 +1,40 @@
const ProcessWrapper = require('../../process/processWrapper');
const BlockchainClient = require('./blockchain');
const i18n = require('../../i18n/i18n.js');
const constants = require('../../constants');
let blockchainProcess;
class BlockchainProcess extends ProcessWrapper {
constructor(options) {
super();
this.blockchainConfig = options.blockchainConfig;
this.client = options.client;
this.env = options.env;
this.isDev = options.isDev;
i18n.setOrDetectLocale(options.locale);
this.blockchainConfig.silent = true;
this.blockchain = BlockchainClient(
this.blockchainConfig,
this.client,
this.env,
this.isDev,
this.blockchainReady.bind(this)
);
this.blockchain.run();
}
blockchainReady() {
blockchainProcess.send({result: constants.blockchain.blockchainReady});
}
}
process.on('message', (msg) => {
if (msg.action === constants.blockchain.init) {
blockchainProcess = new BlockchainProcess(msg.options);
return blockchainProcess.send({result: constants.blockchain.initiated});
}
});

View File

@ -32,6 +32,10 @@ class GethCommands {
cmd += "--password " + config.account.password + " ";
}
if (Number.isInteger(config.verbosity) && config.verbosity >=0 && config.verbosity <= 5) {
cmd += "--verbosity " + config.verbosity + " ";
}
return cmd;
}

View File

@ -0,0 +1,26 @@
// still needs to be run on a separate file due to the global context
var RunCode = require('./runCode.js');
class CodeRunner {
constructor(options) {
this.plugins = options.plugins;
this.logger = options.logger;
this.events = options.events;
// necessary to init the context
RunCode.initContext();
this.events.on("runcode:register", (varName, code) => {
RunCode.registerVar(varName, code);
});
this.events.setCommandHandler('runcode:eval', (code, cb) => {
let result = RunCode.doEval(code);
if (cb) {
cb(null, result);
}
});
}
}
module.exports = CodeRunner;

View File

@ -1,22 +1,16 @@
/*eslint no-unused-vars: off*/
let Web3 = require('web3');
let web3;
let ipfs;
let __mainContext;
let __mainContext = this;
function initContext() {
doEval("__mainContext = this");
}
// ======================
// the eval is used for evaluating some of the contact calls for different purposes
// this should be at least moved to a different process and scope
// for now it is defined here
// ======================
function doEval(code, opts) {
if (opts && opts.web3) {
web3 = opts.web3;
}
if (opts && opts.ipfs) {
ipfs = opts.ipfs;
}
function doEval(code) {
try {
// TODO: add trace log here
return eval(code);
@ -25,6 +19,12 @@ function doEval(code, opts) {
}
}
function registerVar(varName, code) {
__mainContext[varName] = code;
}
module.exports = {
doEval: doEval
doEval: doEval,
registerVar: registerVar,
initContext: initContext
};

View File

@ -29,5 +29,10 @@
"build": "build",
"initiated": "initiated",
"built": "built"
},
"blockchain": {
"blockchainReady": "blockchainReady",
"init": "init",
"initiated": "initiated"
}
}

282
lib/contracts/blockchain.js Normal file
View File

@ -0,0 +1,282 @@
const Web3 = require('web3');
const async = require('async');
const Provider = require('./provider.js');
const request = require('request');
const BlockchainProcessLauncher = require('../processes/blockchainProcessLauncher');
const utils = require('../utils/utils');
const constants = require('../constants');
const WEB3_READY = 'web3Ready';
class Blockchain {
constructor(options) {
this.plugins = options.plugins;
this.logger = options.logger;
this.events = options.events;
this.contractsConfig = options.contractsConfig;
this.blockchainConfig = options.blockchainConfig;
this.web3 = options.web3;
this.locale = options.locale;
this.isDev = options.isDev;
this.addCheck = options.addCheck;
this.web3Endpoint = '';
this.isWeb3Ready = false;
this.web3StartedInProcess = false;
if (!this.web3) {
this.initWeb3();
} else {
this.isWeb3Ready = true;
}
this.registerServiceCheck();
this.registerRequests();
this.registerWeb3Object();
}
initWeb3(cb) {
if (!cb) {
cb = function(){};
}
if (this.isWeb3Ready) {
return cb();
}
const self = this;
this.web3 = new Web3();
if (this.contractsConfig.deployment.type === "rpc") {
let provider;
this.web3Endpoint = 'http://' + this.contractsConfig.deployment.host + ':' + this.contractsConfig.deployment.port;
const providerOptions = {
web3: this.web3,
accountsConfig: this.contractsConfig.deployment.accounts,
logger: this.logger,
isDev: this.isDev,
web3Endpoint: self.web3Endpoint
};
provider = new Provider(providerOptions);
provider.startWeb3Provider(() => {
self.assertNodeConnection(true, (err) => {
if (err && self.web3StartedInProcess) {
// Already started blockchain in another node, we really have a node problem
self.logger.error(__('Unable to start the blockchain process. Is Geth installed?').red);
return cb(err);
}
if (!err) {
self.isWeb3Ready = true;
self.events.emit(WEB3_READY);
return cb();
}
self.web3StartedInProcess = true;
self.startBlockchainNode(() => {
// Need to re-initialize web3 to connect to the new blockchain node
provider.stop();
self.initWeb3(cb);
});
});
});
} else {
throw new Error("contracts config error: unknown deployment type " + this.contractsConfig.deployment.type);
}
}
onReady(callback) {
if (this.isWeb3Ready) {
return callback();
}
this.events.once(WEB3_READY, () => {
callback();
});
}
startBlockchainNode(callback) {
const self = this;
let blockchainProcess = new BlockchainProcessLauncher({
events: self.events,
logger: self.logger,
normalizeInput: utils.normalizeInput,
blockchainConfig: self.blockchainConfig,
locale: self.locale,
isDev: self.isDev
});
blockchainProcess.startBlockchainNode();
self.events.once(constants.blockchain.blockchainReady, () => {
callback();
});
}
registerServiceCheck() {
const self = this;
this.addCheck('Ethereum', function (cb) {
async.waterfall([
function checkNodeConnection(next) {
self.assertNodeConnection(true, (err) => {
if (err) {
return next(null, {name: "No Blockchain node found", status: 'off'});
}
next();
});
},
function checkVersion(next) {
// TODO: web3_clientVersion method is currently not implemented in web3.js 1.0
self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => {
if (err) {
return next(null, {name: "Ethereum node (version unknown)", status: 'on'});
}
if (version.indexOf("/") < 0) {
return next(null, {name: version, status: 'on'});
}
let nodeName = version.split("/")[0];
let versionNumber = version.split("/")[1].split("-")[0];
let name = nodeName + " " + versionNumber + " (Ethereum)";
return next(null, {name: name, status: 'on'});
});
}
], (err, statusObj) => {
if (err) {
self.logger.error(err);
return;
}
cb(statusObj);
});
});
}
registerRequests() {
const self = this;
this.events.setCommandHandler("blockchain:defaultAccount:get", function(cb) {
cb(self.defaultAccount);
});
this.events.setCommandHandler("blockchain:defaultAccount:set", function(account, cb) {
self.setDefaultAccount(account);
cb();
});
this.events.setCommandHandler("blockchain:block:byNumber", function(blockNumber, cb) {
self.getBlock(blockNumber, cb);
});
}
defaultAccount() {
return this.web3.eth.defaultAccount;
}
setDefaultAccount(account) {
this.web3.eth.defaultAccount = account;
}
getAccounts(cb) {
this.web3.eth.getAccounts(cb);
}
getCode(address, cb) {
this.web3.eth.getCode(address, cb);
}
getBlock(blockNumber, cb) {
this.web3.eth.getBlock(blockNumber, cb);
}
ContractObject(params) {
return new this.web3.eth.Contract(params.abi);
}
deployContractObject(contractObject, params) {
return contractObject.deploy({arguments: params.arguments, data: params.data});
}
estimateDeployContractGas(deployObject, cb) {
return deployObject.estimateGas().then((gasValue) => {
cb(null, gasValue);
}).catch(cb);
}
deployContractFromObject(deployContractObject, params, cb) {
deployContractObject.send({
from: params.from, gas: params.gas, gasPrice: params.gasPrice
}).on('receipt', function(receipt) {
if (receipt.contractAddress !== undefined) {
cb(null, receipt);
}
}).on('error', cb);
}
assertNodeConnection(noLogs, cb) {
if (typeof noLogs === 'function') {
cb = noLogs;
noLogs = false;
}
const NO_NODE_ERROR = Error("error connecting to blockchain node");
const self = this;
async.waterfall([
function checkInstance(next) {
if (!self.web3) {
return next(Error("no web3 instance found"));
}
next();
},
function checkProvider(next) {
if (self.web3.currentProvider === undefined) {
return next(NO_NODE_ERROR);
}
next();
},
function pingEndpoint(next) {
if (!self.web3Endpoint) {
return next();
}
request.get(self.web3Endpoint, function (err, _response, _body) {
if (err) {
return next(NO_NODE_ERROR);
}
next();
});
},
function checkAccounts(next) {
self.getAccounts(function(err, _accounts) {
if (err) {
return next(NO_NODE_ERROR);
}
return next();
});
}
], function (err) {
if (!noLogs && err === NO_NODE_ERROR) {
self.logger.error(("Couldn't connect to an Ethereum node are you sure it's on?").red);
self.logger.info("make sure you have an Ethereum node or simulator running. e.g 'embark blockchain'".magenta);
}
cb(err);
});
}
determineDefaultAccount(cb) {
const self = this;
self.getAccounts(function (err, accounts) {
if (err) {
self.logger.error(err);
return cb(new Error(err));
}
let accountConfig = self.blockchainConfig.account;
let selectedAccount = accountConfig && accountConfig.address;
self.setDefaultAccount(selectedAccount || accounts[0]);
cb();
});
}
registerWeb3Object() {
// doesn't feel quite right, should be a cmd or plugin method
// can just be a command without a callback
this.events.emit("runcode:register", "web3", this.web3);
}
}
module.exports = Blockchain;

View File

@ -26,6 +26,7 @@ class CodeGenerator {
this.contractsConfig = options.contractsConfig || {};
this.storageConfig = options.storageConfig || {};
this.communicationConfig = options.communicationConfig || {};
// TODO: this should also be removed and use events instead
this.contractsManager = options.contractsManager;
this.plugins = options.plugins;
this.events = options.events;
@ -107,6 +108,10 @@ class CodeGenerator {
self.buildContractJS(contractName, self.generateContractJSON(contractName, contract), cb);
});
self.events.setCommandHandler('code-generator:contract:vanilla', (contract, gasLimit, cb) => {
cb(self.generateContractCode(contract, gasLimit));
});
this.events.setCommandHandler('embark-building-placeholder', (cb) => {
this.buildPlaceholderPage(cb);
});

View File

@ -1,7 +1,6 @@
let toposort = require('toposort');
let async = require('async');
let Compiler = require('./compiler.js');
let utils = require('../utils/utils.js');
const constants = require('../constants');
@ -9,6 +8,7 @@ const constants = require('../constants');
class ContractsManager {
constructor(options) {
const self = this;
this.contractFiles = options.contractFiles;
this.contractsConfig = options.contractsConfig;
this.contracts = {};
@ -19,25 +19,39 @@ class ContractsManager {
this.deployOnlyOnConfig = false;
this.events = options.events;
this.events.on(constants.events.contractFilesChanged, (newContractFiles) => {
this.contractFiles = newContractFiles;
self.events.on(constants.events.contractFilesChanged, (newContractFiles) => {
self.contractFiles = newContractFiles;
});
this.events.on(constants.events.contractConfigChanged, (newContracts) => {
this.contractsConfig = newContracts;
self.events.on(constants.events.contractConfigChanged, (newContracts) => {
self.contractsConfig = newContracts;
});
const self = this;
self.events.setCommandHandler('contracts:list', (cb) => {
cb(self.listContracts());
});
self.events.setCommandHandler("contracts:contract", (contractName, cb) => {
cb(self.getContract(contractName));
});
self.events.on("deploy:contract:error", (_contract) => {
self.events.emit('contractsState', self.contractsState());
});
self.events.on("deploy:contract:deployed", (_contract) => {
self.events.emit('contractsState', self.contractsState());
});
self.events.on("deploy:contract:undeployed", (_contract) => {
self.events.emit('contractsState', self.contractsState());
});
}
build(done) {
let self = this;
async.waterfall([
function compileContracts(callback) {
let compiler = new Compiler({plugins: self.plugins, logger: self.logger});
compiler.compile_contracts(self.contractFiles, function (err, compiledObject) {
self.events.request("compiler:contracts", self.contractFiles, function (err, compiledObject) {
self.compiledContracts = compiledObject;
callback(err);
});

View File

@ -1,38 +1,22 @@
let async = require('async');
//require("../utils/debug_util.js")(__filename, async);
let RunCode = require('../core/runCode.js');
let DeployTracker = require('./deploy_tracker.js');
let CodeGenerator = require('./code_generator.js');
let utils = require('../utils/utils.js');
class Deploy {
constructor(options) {
this.web3 = options.web3;
this.contractsManager = options.contractsManager;
this.blockchain = options.blockchain;
this.logger = options.logger;
this.events = options.events;
this.env = options.env;
this.chainConfig = options.chainConfig;
this.plugins = options.plugins;
this.gasLimit = options.gasLimit;
this.events.setCommandHandler("contracts:contract", (contractName, cb) => {
cb(this.contractsManager.getContract(contractName));
});
}
initTracker(cb) {
this.deployTracker = new DeployTracker({
logger: this.logger, chainConfig: this.chainConfig, web3: this.web3, env: this.env
}, cb);
}
determineArguments(suppliedArgs, contract) {
let realArgs = [], l, arg, contractName, referedContract;
// TODO: determining the arguments could also be in a module since it's not
// part of ta 'normal' contract deployment
determineArguments(suppliedArgs, contract, callback) {
const self = this;
let args = suppliedArgs;
if (!Array.isArray(args)) {
args = [];
let abi = contract.abiDefinition.find((abi) => abi.type === 'constructor');
@ -46,171 +30,137 @@ class Deploy {
}
}
for (l = 0; l < args.length; l++) {
arg = args[l];
let realArgs = [];
async.eachLimit(args, 1, (arg, nextEachCb) => {
if (arg[0] === "$") {
contractName = arg.substr(1);
referedContract = this.contractsManager.getContract(contractName);
realArgs.push(referedContract.deployedAddress);
let contractName = arg.substr(1);
self.events.request('contracts:contract', contractName, (referedContract) => {
realArgs.push(referedContract.deployedAddress);
nextEachCb();
});
} else if (Array.isArray(arg)) {
let subRealArgs = [];
for (let sub_arg of arg) {
async.eachLimit(arg, 1, (sub_arg, nextSubEachCb) => {
if (sub_arg[0] === "$") {
contractName = sub_arg.substr(1);
referedContract = this.contractsManager.getContract(contractName);
subRealArgs.push(referedContract.deployedAddress);
let contractName = sub_arg.substr(1);
self.events.request('contracts:contract', contractName, (referedContract) => {
subRealArgs.push(referedContract.deployedAddress);
nextSubEachCb();
});
} else {
subRealArgs.push(sub_arg);
nextSubEachCb();
}
}
realArgs.push(subRealArgs);
}, () => {
realArgs.push(subRealArgs);
nextEachCb();
});
} else {
realArgs.push(arg);
nextEachCb();
}
}
return realArgs;
}, () => {
callback(realArgs);
});
}
checkAndDeployContract(contract, params, callback) {
let self = this;
let realArgs;
contract.error = false;
if (contract.deploy === false) {
self.events.emit('contractsState', self.contractsManager.contractsState());
self.events.emit("deploy:contract:undeployed", contract);
return callback();
}
realArgs = self.determineArguments(params || contract.args, contract);
async.waterfall([
function _determineArguments(next) {
self.determineArguments(params || contract.args, contract, (realArgs) => {
contract.realArgs = realArgs;
next();
});
},
function deployIt(next) {
if (contract.address !== undefined) {
try {
utils.toChecksumAddress(contract.address);
} catch(e) {
self.logger.error(__("error deploying %s", contract.className));
self.logger.error(e.message);
contract.error = e.message;
self.events.emit("deploy:contract:error", contract);
return next(e.message);
}
contract.deployedAddress = contract.address;
self.logger.info(contract.className.bold.cyan + __(" already deployed at ").green + contract.address.bold.cyan);
self.events.emit("deploy:contract:deployed", contract);
return next();
}
if (contract.address !== undefined) {
try {
this.web3.utils.toChecksumAddress(contract.address);
} catch(e) {
self.logger.error(__("error deploying %s", contract.className));
self.logger.error(e.message);
contract.error = e.message;
self.events.emit('contractsState', self.contractsManager.contractsState());
return callback(e.message);
// TODO: this should be a plugin API instead, if not existing, it should by default deploy the contract
self.events.request("deploy:contract:shouldDeploy", contract, function(trackedContract) {
if (!trackedContract) {
return self.contractToDeploy(contract, params, next);
}
self.blockchain.getCode(trackedContract.address, function(_getCodeErr, codeInChain) {
if (codeInChain !== "0x") {
self.contractAlreadyDeployed(contract, trackedContract, next);
} else {
self.contractToDeploy(contract, params, next);
}
});
});
}
contract.deployedAddress = contract.address;
self.logger.info(contract.className.bold.cyan + __(" already deployed at ").green + contract.address.bold.cyan);
if (this.deployTracker) {
self.deployTracker.trackContract(contract.className, contract.realRuntimeBytecode, realArgs, contract.address);
self.deployTracker.save();
}
self.events.emit('contractsState', self.contractsManager.contractsState());
return callback();
}
if (!this.deployTracker) {
return self.contractToDeploy(contract, params, callback);
}
let trackedContract = self.deployTracker.getContract(contract.className, contract.realRuntimeBytecode, realArgs);
if (!trackedContract) {
return self.contractToDeploy(contract, params, callback);
}
this.web3.eth.getCode(trackedContract.address, function(_getCodeErr, codeInChain) {
if (codeInChain !== "0x") {
self.contractAlreadyDeployed(contract, trackedContract, callback);
} else {
self.contractToDeploy(contract, params, callback);
}
});
], callback);
}
contractAlreadyDeployed(contract, trackedContract, callback) {
const self = this;
self.logger.info(contract.className.bold.cyan + __(" already deployed at ").green + trackedContract.address.bold.cyan);
contract.deployedAddress = trackedContract.address;
self.events.emit('contractsState', self.contractsManager.contractsState());
self.events.emit("deploy:contract:deployed", contract);
// always run contractCode so other functionality like 'afterDeploy' can also work
let codeGenerator = new CodeGenerator({contractsManager: self.contractsManager});
let contractCode = codeGenerator.generateContractCode(contract, self.gasLimit);
RunCode.doEval(contractCode, {web3: self.web3});
return callback();
// TODO: can be moved into a afterDeploy event
// just need to figure out the gasLimit coupling issue
self.events.request('code-generator:contract:vanilla', contract, self.gasLimit, (contractCode) => {
self.events.request('runcode:eval', contractCode);
return callback();
});
}
contractToDeploy(contract, params, callback) {
const self = this;
let realArgs = self.determineArguments(params || contract.args, contract);
this.deployContract(contract, realArgs, function (err, address) {
if (err) {
return callback(new Error(err));
}
self.deployTracker.trackContract(contract.className, contract.realRuntimeBytecode, realArgs, address);
self.deployTracker.save();
self.events.emit('contractsState', self.contractsManager.contractsState());
// TODO: refactor to async
self.determineArguments(params || contract.args, contract, (realArgs) => {
contract.realArgs = realArgs;
// always run contractCode so other functionality like 'afterDeploy' can also work
let codeGenerator = new CodeGenerator({contractsManager: self.contractsManager});
let contractCode = codeGenerator.generateContractCode(contract, self.gasLimit);
RunCode.doEval(contractCode, {web3: self.web3});
this.deployContract(contract, contract.realArgs, function (err, address) {
if (err) {
self.events.emit("deploy:contract:error", contract);
return callback(new Error(err));
}
contract.address = address;
self.events.emit("deploy:contract:deployed", contract);
if (contract.onDeploy !== undefined) {
self.logger.info(__('executing onDeploy commands'));
// TODO: can be moved into a afterDeploy event
// just need to figure out the gasLimit coupling issue
self.events.request('code-generator:contract:vanilla', contract, self.gasLimit, (contractCode) => {
self.events.request('runcode:eval', contractCode);
let contractCode = codeGenerator.generateContractCode(contract, self.gasLimit);
RunCode.doEval(contractCode, {web3: self.web3});
let onDeployPlugins = self.plugins.getPluginsProperty('onDeployActions', 'onDeployActions');
let withErrors = false;
let regex = /\$\w+/g;
let onDeployCode = contract.onDeploy.map((cmd) => {
let realCmd = cmd.replace(regex, (match) => {
let referedContractName = match.slice(1);
let referedContract = self.contractsManager.getContract(referedContractName);
if (!referedContract) {
self.logger.error(__('error executing onDeploy for ') + contract.className.cyan);
self.logger.error(referedContractName + __(' does not exist'));
self.logger.error(__("error running onDeploy: ") + cmd);
withErrors = true;
return;
}
if (referedContract && referedContract.deploy === false) {
self.logger.error(__('error executing onDeploy for ') + contract.className.cyan);
self.logger.error(referedContractName + __(" exists but has been set to not deploy"));
self.logger.error(__("error running onDeploy: ") + cmd);
withErrors = true;
return;
}
if (referedContract && !referedContract.deployedAddress) {
self.logger.error(__('error executing onDeploy for ') + contract.className.cyan);
self.logger.error(__("couldn't find a valid address for %s has it been deployed?", referedContractName));
self.logger.error(__("error running onDeploy: ") + cmd);
withErrors = true;
return;
}
return referedContract.deployedAddress;
async.eachLimit(onDeployPlugins, 1, function(plugin, nextEach) {
plugin.call(plugin, contract, nextEach);
}, () => {
callback();
});
return realCmd;
});
if (withErrors) {
contract.error = "onDeployCmdError";
return callback(new Error("error running onDeploy"));
}
// TODO: convert to for to avoid repeated callback
for(let cmd of onDeployCode) {
self.logger.info(__("executing: ") + cmd);
try {
RunCode.doEval(cmd, {web3: self.web3});
} catch(e) {
if (e.message.indexOf("invalid opcode") >= 0) {
self.logger.error(__('the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation'));
}
return callback(new Error(e));
}
}
}
callback();
});
});
}
@ -219,12 +169,13 @@ class Deploy {
let accounts = [];
let contractParams = (params || contract.args).slice();
let contractCode = contract.code;
let deploymentAccount = self.web3.eth.defaultAccount;
let deploymentAccount = self.blockchain.defaultAccount();
let deployObject;
async.waterfall([
// TODO: can potentially go to a beforeDeploy plugin
function getAccounts(next) {
self.web3.eth.getAccounts(function (err, _accounts) {
self.blockchain.getAccounts(function (err, _accounts) {
if (err) {
return next(new Error(err));
}
@ -249,31 +200,31 @@ class Deploy {
});
},
function doLinking(next) {
// Applying linked contracts
let contractsList = self.contractsManager.listContracts();
for (let contractObj of contractsList) {
let filename = contractObj.filename;
let deployedAddress = contractObj.deployedAddress;
if (deployedAddress) {
deployedAddress = deployedAddress.substr(2);
self.events.request('contracts:list', (contracts) => {
for (let contractObj of contracts) {
let filename = contractObj.filename;
let deployedAddress = contractObj.deployedAddress;
if (deployedAddress) {
deployedAddress = deployedAddress.substr(2);
}
let linkReference = '__' + filename + ":" + contractObj.className;
if (contractCode.indexOf(linkReference) < 0) {
continue;
}
if (linkReference.length > 40) {
return next(new Error(__("{{linkReference}} is too long, try reducing the path of the contract ({{filename}}) and/or its name {{contractName}}", {linkReference: linkReference, filename: filename, contractName: contractObj.className})));
}
let toReplace = linkReference + "_".repeat(40 - linkReference.length);
if (deployedAddress === undefined) {
let libraryName = contractObj.className;
return next(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {contractName: contract.className, libraryName: libraryName})));
}
contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress);
}
let linkReference = '__' + filename + ":" + contractObj.className;
if (contractCode.indexOf(linkReference) < 0) {
continue;
}
if (linkReference.length > 40) {
return next(new Error(__("{{linkReference}} is too long, try reducing the path of the contract ({{filename}}) and/or its name {{contractName}}", {linkReference: linkReference, filename: filename, contractName: contractObj.className})));
}
let toReplace = linkReference + "_".repeat(40 - linkReference.length);
if (deployedAddress === undefined) {
let libraryName = contractObj.className;
return next(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {contractName: contract.className, libraryName: libraryName})));
}
contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress);
}
// saving code changes back to contract object
contract.code = contractCode;
next();
// saving code changes back to contract object
contract.code = contractCode;
next();
});
},
function applyBeforeDeploy(next) {
let beforeDeployPlugins = self.plugins.getPluginsFor('beforeDeploy');
@ -306,11 +257,11 @@ class Deploy {
});
},
function createDeployObject(next) {
let contractObject = new self.web3.eth.Contract(contract.abiDefinition);
let contractObject = self.blockchain.ContractObject({abi: contract.abiDefinition});
try {
const dataCode = contractCode.startsWith('0x') ? contractCode : "0x" + contractCode;
deployObject = contractObject.deploy({arguments: contractParams, data: dataCode});
deployObject = self.blockchain.deployContractObject(contractObject, {arguments: contractParams, data: dataCode});
} catch(e) {
if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) {
return next(new Error(__("attempted to deploy %s without specifying parameters", contract.className)));
@ -332,22 +283,18 @@ class Deploy {
function deployTheContract(next) {
self.logger.info(__("deploying") + " " + contract.className.bold.cyan + " " + __("with").green + " " + contract.gas + " " + __("gas").green);
deployObject.send({
self.blockchain.deployContractFromObject(deployObject, {
from: deploymentAccount,
gas: contract.gas,
gasPrice: contract.gasPrice
}).on('receipt', function(receipt) {
if (receipt.contractAddress !== undefined) {
self.logger.info(contract.className.bold.cyan + " " + __("deployed at").green + " " + receipt.contractAddress.bold.cyan);
contract.deployedAddress = receipt.contractAddress;
contract.transactionHash = receipt.transactionHash;
self.events.emit('contractsState', self.contractsManager.contractsState());
return next(null, receipt.contractAddress);
}, function(error, receipt) {
if (error) {
return next(new Error("error deploying =" + contract.className + "= due to error: " + error.message));
}
self.events.emit('contractsState', self.contractsManager.contractsState());
}).on('error', function(error) {
self.events.emit('contractsState', self.contractsManager.contractsState());
return next(new Error(__("error deploying") + " =" + contract.className + "= " + __("due to error") + ": " + error.message));
self.logger.info(contract.className.bold.cyan + " " + __("deployed at").green + " " + receipt.contractAddress.bold.cyan);
contract.deployedAddress = receipt.contractAddress;
contract.transactionHash = receipt.transactionHash;
return next(null, receipt.contractAddress);
});
}
], callback);
@ -356,28 +303,30 @@ class Deploy {
deployAll(done) {
let self = this;
this.logger.info(__("deploying contracts"));
let contracts = this.contractsManager.listContracts();
this.events.emit("deploy:beforeAll");
async.eachOfSeries(contracts,
function (contract, key, callback) {
self.logger.trace(arguments);
self.checkAndDeployContract(contract, null, callback);
},
function (err, _results) {
if (err) {
self.logger.error(__("error deploying contracts"));
self.logger.error(err.message);
self.logger.debug(err.stack);
self.events.request('contracts:list', (contracts) => {
async.eachOfSeries(contracts,
function (contract, key, callback) {
self.logger.trace(arguments);
self.checkAndDeployContract(contract, null, callback);
},
function (err, _results) {
if (err) {
self.logger.error(__("error deploying contracts"));
self.logger.error(err.message);
self.logger.debug(err.stack);
}
if (contracts.length === 0) {
self.logger.info(__("no contracts found"));
return done();
}
self.logger.info(__("finished deploying contracts"));
self.logger.trace(arguments);
done(err);
}
if (contracts.length === 0) {
self.logger.info(__("no contracts found"));
return done();
}
self.logger.info(__("finished deploying contracts"));
self.logger.trace(arguments);
done(err);
}
);
);
});
}
}

View File

@ -1,7 +1,6 @@
let async = require('async');
//require("../utils/debug_util.js")(__filename, async);
let Deploy = require('./deploy.js');
let RunCode = require('../core/runCode.js');
class DeployManager {
constructor(options) {
@ -11,7 +10,7 @@ class DeployManager {
this.events = options.events;
this.plugins = options.plugins;
this.web3 = options.web3;
this.blockchain = options.blockchain;
this.chainConfig = (options.trackContracts !== false) ? this.config.chainTracker : false;
this.contractsManager = options.contractsManager;
this.gasLimit = false;
@ -32,51 +31,40 @@ class DeployManager {
async.waterfall([
function buildContracts(callback) {
self.contractsManager.deployOnlyOnConfig = self.deployOnlyOnConfig; // temporary, should refactor
self.contractsManager.build(callback);
self.contractsManager.build(() => {
callback();
});
},
function checkCompileOnly(contractsManager, callback){
// TODO: shouldn't be necessary
function checkCompileOnly(callback){
if(self.onlyCompile){
self.events.emit('contractsDeployed', contractsManager);
self.events.emit('contractsDeployed', self.contractsManager);
return done();
}
return callback(null, contractsManager);
return callback();
},
function checkWeb3IsConnected(contractsManager, callback) {
if (!self.web3) {
return callback(Error("no web3 instance found"));
}
if (self.web3.currentProvider === undefined) {
self.logger.error(__("Couldn't connect to an Ethereum node are you sure it's on?").red);
self.logger.info(__("make sure you have an Ethereum node or simulator running. e.g '%s'", 'embark blockchain').magenta);
return callback(Error("error connecting to blockchain node"));
}
self.web3.eth.getAccounts(function(err, _accounts) {
if (err) {
self.logger.error(__("Couldn't connect to an Ethereum node are you sure it's on?").red);
self.logger.info(__("make sure you have an Ethereum node or simulator running. e.g '%s'", 'embark blockchain').magenta);
return callback(Error("error connecting to blockchain node"));
}
return callback(null, contractsManager, self.web3);
// TODO: could be implemented as an event (beforeDeployAll)
function checkIsConnectedToBlockchain(callback) {
self.blockchain.onReady(() => {
self.blockchain.assertNodeConnection((err) => {
callback(err);
});
});
},
function setDefaultAccount(contractsManager, web3, callback) {
web3.eth.getAccounts(function (err, accounts) {
if (err) {
self.logger.error(err);
return callback(new Error(err));
}
let accountConfig = self.config.blockchainConfig.account;
let selectedAccount = accountConfig && accountConfig.address;
web3.eth.defaultAccount = (selectedAccount || accounts[0]);
callback(null, contractsManager, web3);
// TODO: this can be done on the fly or as part of the initialization
function determineDefaultAccount(callback) {
self.blockchain.determineDefaultAccount((err) => {
callback(err);
});
},
function deployAllContracts(contractsManager, web3, callback) {
function deployAllContracts(callback) {
let deploy = new Deploy({
web3: web3,
contractsManager: contractsManager,
blockchain: self.blockchain,
contractsManager: self.contractsManager,
logger: self.logger,
events: self.events,
chainConfig: self.chainConfig,
@ -85,75 +73,27 @@ class DeployManager {
gasLimit: self.gasLimit
});
deploy.initTracker(function() {
deploy.deployAll(function (err) {
if (!err) {
self.events.emit('contractsDeployed', contractsManager);
}
if (err && self.fatalErrors) {
return callback(err);
}
callback(null, contractsManager, web3);
});
deploy.deployAll(function (err) {
if (!err) {
self.events.emit('contractsDeployed', self.contractsManager);
}
if (err && self.fatalErrors) {
return callback(err);
}
callback();
});
},
function runAfterDeployCommands(contractsManager, web3, callback) {
let afterDeployCmds = self.config.contractsConfig.afterDeploy || [];
function runAfterDeploy(callback) {
let afterDeployPlugins = self.plugins.getPluginsProperty('afterContractsDeployActions', 'afterContractsDeployActions');
let withErrors = false;
let regex = /\$\w+/g;
let onDeployCode = afterDeployCmds.map((cmd) => {
let realCmd = cmd.replace(regex, (match) => {
let referedContractName = match.slice(1);
let referedContract = contractsManager.getContract(referedContractName);
if (!referedContract) {
self.logger.error(referedContractName + ' does not exist');
self.logger.error(__("error running afterDeploy: ") + cmd);
withErrors = true;
return;
}
if (referedContract && referedContract.deploy === false) {
self.logger.error(referedContractName + " exists but has been set to not deploy");
self.logger.error(__("error running afterDeploy: ") + cmd);
withErrors = true;
return;
}
if (referedContract && !referedContract.deployedAddress) {
self.logger.error("couldn't find a valid address for " + referedContractName + ". has it been deployed?");
self.logger.error(__("error running afterDeploy: ") + cmd);
withErrors = true;
return;
}
return referedContract.deployedAddress;
});
return realCmd;
async.eachLimit(afterDeployPlugins, 1, function(plugin, nextEach) {
plugin.call(plugin, nextEach);
}, () => {
callback();
});
if (withErrors) {
return callback(new Error("error running afterDeploy"));
}
// TODO: convert to for to avoid repeated callback
for(let cmd of onDeployCode) {
self.logger.info(__("executing") + ": " + cmd);
try {
RunCode.doEval(cmd, {web3: web3});
} catch(e) {
if (e.message.indexOf("invalid opcode") >= 0) {
self.logger.error(__('the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation'));
}
return callback(new Error(e));
}
}
callback(null, contractsManager);
}
], function (err, result) {
if (err) {
done(err, null);
} else {
done(null, result);
}
], function (err, _result) {
done(err);
});
}

View File

@ -1,64 +0,0 @@
let fs = require('../core/fs.js');
class DeployTracker {
constructor(options, cb) {
const self = this;
this.logger = options.logger;
this.env = options.env;
this.chainConfig = options.chainConfig;
this.web3 = options.web3;
if (this.chainConfig === false) {
this.currentChain = {contracts: []};
return cb();
}
this.web3.eth.getBlock(0, function(err, block) {
let chainId = block.hash;
if (self.chainConfig[chainId] === undefined) {
self.chainConfig[chainId] = {contracts: {}};
}
self.currentChain = self.chainConfig[chainId];
self.currentChain.name = self.env;
cb();
});
// TODO: add other params
//this.currentChain.networkId = "";
//this.currentChain.networkType = "custom"
}
loadConfig(config) {
this.chainConfig = config;
return this;
}
trackContract(contractName, code, args, address) {
this.currentChain.contracts[this.web3.utils.sha3(code + contractName + args.join(','))] = {
name: contractName,
address: address
};
}
getContract(contractName, code, args) {
let contract = this.currentChain.contracts[this.web3.utils.sha3(code + contractName + args.join(','))];
if (contract && contract.address === undefined) {
return false;
}
return contract;
}
// TODO: abstract this
// chainConfig can be an abstract PersistentObject
save() {
if (this.chainConfig === false) {
return;
}
fs.writeJSONSync("./chains.json", this.chainConfig, {spaces: 2});
}
}
module.exports = DeployTracker;

View File

@ -64,6 +64,10 @@ class Provider {
});
}
stop() {
this.engine.stop();
}
eth_accounts(payload, cb) {
return cb(null, this.addresses);
}

View File

@ -38,7 +38,7 @@ Config.prototype.loadConfigFiles = function(options) {
this.embarkConfig = fs.readJSONSync(options.embarkConfig);
this.embarkConfig.plugins = this.embarkConfig.plugins || {};
this.plugins = new Plugins({plugins: this.embarkConfig.plugins, logger: this.logger, interceptLogs: interceptLogs, events: this.events, config: this, context: this.context});
this.plugins = new Plugins({plugins: this.embarkConfig.plugins, logger: this.logger, interceptLogs: interceptLogs, events: this.events, config: this, context: this.context, env: this.env});
this.plugins.loadPlugins();
this.loadEmbarkConfigFile();

View File

@ -1,21 +1,26 @@
const Web3 = require('web3');
const async = require('async');
const Events = require('./events.js');
const Logger = require('./logger.js');
const Config = require('./config.js');
const Blockchain = require('../contracts/blockchain.js');
const Compiler = require('../contracts/compiler.js');
const ContractsManager = require('../contracts/contracts.js');
const DeployManager = require('../contracts/deploy_manager.js');
const CodeGenerator = require('../contracts/code_generator.js');
const ServicesMonitor = require('./services_monitor.js');
const Pipeline = require('../pipeline/pipeline.js');
const Watch = require('../pipeline/watch.js');
const LibraryManager = require('../versions/library_manager.js');
const Pipeline = require('../pipeline/pipeline.js');
const async = require('async');
const Provider = require('../contracts/provider');
const CodeRunner = require('../coderunner/codeRunner.js');
const utils = require('../utils/utils');
class Engine {
constructor(options) {
this.env = options.env;
this.isDev = options.isDev;
this.client = options.client;
this.locale = options.locale;
this.embarkConfig = options.embarkConfig;
this.interceptLogs = options.interceptLogs;
this.version = options.version;
@ -44,46 +49,29 @@ class Engine {
}
}
normalizeInput(input) {
let args = Object.values(input);
if (args.length === 0) {
return "";
}
if (args.length === 1) {
if (Array.isArray(args[0])) { return args[0].join(','); }
return args[0] || "";
}
return ('[' + args.map((x) => {
if (x === null) { return "null"; }
if (x === undefined) { return "undefined"; }
if (Array.isArray(x)) { return x.join(','); }
return x;
}).toString() + ']');
}
doInterceptLogs() {
var self = this;
let context = {};
context.console = console;
context.console.log = function() {
self.logger.info(self.normalizeInput(arguments));
self.logger.info(utils.normalizeInput(arguments));
};
context.console.warn = function() {
self.logger.warn(self.normalizeInput(arguments));
self.logger.warn(utils.normalizeInput(arguments));
};
context.console.info = function() {
self.logger.info(self.normalizeInput(arguments));
self.logger.info(utils.normalizeInput(arguments));
};
context.console.debug = function() {
// TODO: ue JSON.stringify
self.logger.debug(self.normalizeInput(arguments));
self.logger.debug(utils.normalizeInput(arguments));
};
context.console.trace = function() {
self.logger.trace(self.normalizeInput(arguments));
self.logger.trace(utils.normalizeInput(arguments));
};
context.console.dir = function() {
self.logger.dir(self.normalizeInput(arguments));
self.logger.dir(utils.normalizeInput(arguments));
};
}
@ -112,6 +100,7 @@ class Engine {
let services = {
"pipeline": this.pipelineService,
"codeRunner": this.codeRunnerService,
"codeGenerator": this.codeGeneratorService,
"deployment": this.deploymentService,
"fileWatcher": this.fileWatchService,
@ -142,7 +131,6 @@ class Engine {
assetFiles: this.config.assetFiles,
events: this.events,
logger: this.logger,
normalizeInput: this.normalizeInput,
plugins: this.plugins
});
@ -158,21 +146,30 @@ class Engine {
});
}
codeRunnerService(_options) {
this.codeRunner = new CodeRunner({
plugins: this.plugins,
events: this.events,
logger: this.logger
});
}
codeGeneratorService(_options) {
let self = this;
const generateCode = function (contractsManager) {
let codeGenerator = new CodeGenerator({
blockchainConfig: self.config.blockchainConfig,
contractsConfig: self.config.contractsConfig,
contractsManager: contractsManager,
plugins: self.plugins,
storageConfig: self.config.storageConfig,
communicationConfig: self.config.communicationConfig,
events: self.events
});
codeGenerator.listenToCommands();
codeGenerator.buildEmbarkJS(function() {
this.codeGenerator = new CodeGenerator({
blockchainConfig: self.config.blockchainConfig,
contractsConfig: self.config.contractsConfig,
contractsManager: this.contractsManager,
plugins: self.plugins,
storageConfig: self.config.storageConfig,
communicationConfig: self.config.communicationConfig,
events: self.events
});
this.codeGenerator.listenToCommands();
const generateCode = function () {
self.codeGenerator.buildEmbarkJS(function() {
self.events.emit('code-generator-ready');
});
};
@ -192,6 +189,11 @@ class Engine {
deploymentService(options) {
let self = this;
let compiler = new Compiler({plugins: self.plugins, logger: self.logger});
this.events.setCommandHandler("compiler:contracts", function(contractFiles, cb) {
compiler.compile_contracts(contractFiles, cb);
});
this.registerModule('solidity', {
contractDirectories: self.config.contractDirectories
});
@ -203,6 +205,12 @@ class Engine {
logger: this.logger
});
this.registerModule('deploytracker', {
});
this.registerModule('specialconfigs', {
});
this.contractsManager = new ContractsManager({
contractFiles: this.config.contractsFiles,
contractsConfig: this.config.contractsConfig,
@ -213,7 +221,7 @@ class Engine {
});
this.deployManager = new DeployManager({
web3: options.web3 || self.web3,
blockchain: this.blockchain,
trackContracts: options.trackContracts,
config: this.config,
logger: this.logger,
@ -268,74 +276,30 @@ class Engine {
this.registerModule('swarm', {
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
storageConfig: this.config.storageConfig,
bzz: _options.bzz
// TODO: this should not be needed and should be deducted from the config instead
// the eth provider is not necessary the same as the swarm one
bzz: this.blockchain.web3.bzz
});
}
web3Service(options) {
let self = this;
this.web3 = options.web3;
let provider;
if (this.web3 === undefined) {
this.web3 = new Web3();
if (this.config.contractsConfig.deployment.type === "rpc") {
const web3Endpoint = 'http://' + this.config.contractsConfig.deployment.host + ':' + this.config.contractsConfig.deployment.port;
const providerOptions = {
web3: this.web3,
accountsConfig: this.config.contractsConfig.deployment.accounts,
logger: this.logger,
isDev: this.isDev,
web3Endpoint
};
provider = new Provider(providerOptions);
} else {
throw new Error("contracts config error: unknown deployment type " + this.config.contractsConfig.deployment.type);
}
}
this.blockchain = new Blockchain({
contractsConfig: this.config.contractsConfig,
blockchainConfig: this.config.blockchainConfig,
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
events: this.events,
logger: this.logger,
isDev: this.isDev,
locale: this.locale,
web3: options.web3
});
async.waterfall([
function (next) {
if (!provider) {
return next();
}
provider.startWeb3Provider(next);
}
], function (err) {
if (err) {
console.error(err);
}
self.servicesMonitor.addCheck('Ethereum', function (cb) {
if (self.web3.currentProvider === undefined) {
return cb({name: __("No Blockchain node found"), status: 'off'});
}
self.web3.eth.getAccounts(function(err, _accounts) {
if (err) {
return cb({name: __("No Blockchain node found"), status: 'off'});
}
// TODO: web3_clientVersion method is currently not implemented in web3.js 1.0
self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => {
if (err) {
return cb({name: __("Ethereum node (version unknown)"), status: 'on'});
}
if (version.indexOf("/") < 0) {
return cb({name: version, status: 'on'});
}
let nodeName = version.split("/")[0];
let versionNumber = version.split("/")[1].split("-")[0];
let name = nodeName + " " + versionNumber + " (Ethereum)";
return cb({name: name, status: 'on'});
});
});
});
self.registerModule('whisper', {
addCheck: self.servicesMonitor.addCheck.bind(self.servicesMonitor),
communicationConfig: self.config.communicationConfig,
web3: self.web3
});
this.registerModule('whisper', {
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
communicationConfig: this.config.communicationConfig,
// TODO: this should not be needed and should be deducted from the config instead
// the eth provider is not necessary the same as the whisper one
web3: this.blockchain.web3
});
}

View File

@ -40,7 +40,7 @@ EventEmitter.prototype.request = function() {
};
EventEmitter.prototype.setCommandHandler = function(requestName, cb) {
log("setting command handler for: ", requestName);
log("setting command handler for: " + requestName);
let listener = function(_cb) {
cb.call(this, ...arguments);
};

View File

@ -25,9 +25,12 @@ var Plugin = function(options) {
this.imports = [];
this.embarkjs_code = [];
this.embarkjs_init_code = {};
this.afterContractsDeployActions = [];
this.onDeployActions = [];
this.logger = options.logger;
this.events = options.events;
this.config = options.config;
this.env = options.env;
this.loaded = false;
this.currentContext = options.context;
this.acceptedContext = options.pluginConfig.context || [constants.contexts.any];
@ -202,6 +205,16 @@ Plugin.prototype.registerImportFile = function(importName, importLocation) {
this.pluginTypes.push('imports');
};
Plugin.prototype.registerAfterAllContractsDeploy = function(cb) {
this.afterContractsDeployActions.push(cb);
this.pluginTypes.push('afterContractsDeployActions');
};
Plugin.prototype.registerOnDeployContracts = function(cb) {
this.onDeployActions.push(cb);
this.pluginTypes.push('onDeployActions');
};
Plugin.prototype.runFilePipeline = function() {
var self = this;

View File

@ -10,6 +10,7 @@ var Plugins = function(options) {
this.events = options.events;
this.config = options.config;
this.context = options.context;
this.env = options.env;
};
Plugins.prototype.loadPlugins = function() {
@ -64,7 +65,8 @@ Plugins.prototype.loadInternalPlugin = function(pluginName, pluginConfig) {
events: this.events,
config: this.config,
isInternal: true,
context: this.context
context: this.context,
env: this.env
});
pluginWrapper.loadInternalPlugin();
this.plugins.push(pluginWrapper);

View File

@ -1,5 +1,4 @@
let utils = require('../utils/utils.js');
let RunCode = require('../core/runCode.js');
class Console {
constructor(options) {
@ -10,7 +9,7 @@ class Console {
}
runCode(code) {
RunCode.doEval(code);
this.events.request('runcode:eval', code);
}
processEmbarkCmd (cmd) {
@ -48,8 +47,9 @@ class Console {
}
try {
let result = RunCode.doEval(cmd);
return callback(result);
this.events.request('runcode:eval', cmd, (err, result) => {
callback(result);
});
}
catch (e) {
if (e.message.indexOf('not defined') > 0) {

View File

@ -102,17 +102,30 @@
"Swarm node is offline...": "Swarm node is offline...",
"Swarm node detected...": "Swarm node detected...",
"Cannot find file %s Please ensure you are running this command inside the Dapp folder": "Cannot find file %s Please ensure you are running this command inside the Dapp folder",
"finished building": "finished building",
"compiling Vyper contracts": "compiling Vyper contracts",
"Vyper exited with error code ": "Vyper exited with error code ",
"attempted to deploy %s without specifying parameters": "attempted to deploy %s without specifying parameters",
"adding %s to ipfs": "adding %s to ipfs",
"DApp available at": "DApp available at",
"successfully uploaded to ipfs": "successfully uploaded to ipfs",
"Ethereum node (version unknown)": "Ethereum node (version unknown)",
"No Blockchain node found": "No Blockchain node found",
"Couldn't connect to an Ethereum node are you sure it's on?": "Couldn't connect to an Ethereum node are you sure it's on?",
"make sure you have an Ethereum node or simulator running. e.g '%s'": "make sure you have an Ethereum node or simulator running. e.g '%s'",
"Embark is building, please wait...": "Embark is building, please wait...",
"finished building DApp and deploying to": "finished building DApp and deploying to"
"finished building DApp and deploying to": "finished building DApp and deploying to",
"Type": "Type",
"to see the list of available commands": "to see the list of available commands",
"instantiated js-ipfs object configured to the current environment (available if ipfs is enabled)": "instantiated js-ipfs object configured to the current environment (available if ipfs is enabled)",
"reset done!": "reset done!",
"finished building": "finished building",
"finished deploying": "finished deploying",
"adding %s to ipfs": "adding %s to ipfs",
"DApp available at": "DApp available at",
"successfully uploaded to ipfs": "successfully uploaded to ipfs",
"Starting Blockchain node in another process": "Starting Blockchain node in another process",
"Blockchain node is ready": "Blockchain node is ready",
"terminating due to error": "terminating due to error",
"Unable to start the blockchain process. Is Geth installed?": "Unable to start the blockchain process. Is Geth installed?",
"Cannot upload: {{platform}} node is not running on {{protocol}}://{{host}}:{{port}}.": "Cannot upload: {{platform}} node is not running on {{protocol}}://{{host}}:{{port}}.",
"Error while downloading the file": "Error while downloading the file",
"Error while loading the content of ": "Error while loading the content of ",
"no contracts found": "no contracts found"
}

View File

@ -86,6 +86,8 @@ class Embark {
let engine = new Engine({
env: options.env,
client: options.client,
locale: options.locale,
isDev: this.isDev(options.env),
version: this.version,
embarkConfig: options.embarkConfig || 'embark.json',
@ -128,11 +130,13 @@ class Embark {
engine.startMonitor();
engine.startService("libraryManager");
engine.startService("codeRunner");
engine.startService("web3");
engine.startService("pipeline");
engine.startService("codeGenerator");
engine.startService("deployment");
engine.startService(engine.config.storageConfig.provider, {bzz: engine.web3.bzz});
engine.startService("codeGenerator");
// TODO: this should be just 'storage' and the storage should figure out the module
engine.startService(engine.config.storageConfig.provider);
engine.events.on('check:backOnline:Ethereum', function () {
engine.logger.info(__('Ethereum node detected') + '..');
@ -147,7 +151,6 @@ class Embark {
engine.logger.info(__("Ready").underline);
engine.events.emit("status", __("Ready").green);
});
engine.deployManager.deployContracts(function (err) {
engine.startService("fileWatcher");
if (options.runWebserver) {
@ -179,6 +182,8 @@ class Embark {
let engine = new Engine({
env: options.env,
client: options.client,
locale: options.locale,
isDev: this.isDev(options.env),
version: this.version,
embarkConfig: 'embark.json',
@ -201,12 +206,14 @@ class Embark {
}
engine.startService("libraryManager");
engine.startService("codeRunner");
engine.startService("web3");
engine.startService("pipeline");
engine.startService("codeGenerator");
engine.startService("deployment", {onlyCompile: options.onlyCompile});
engine.startService("codeGenerator");
// TODO: this should be just 'storage' and the storage should figure out the modules to load
engine.startService("ipfs");
engine.startService("swarm", {bzz: engine.web3.bzz});
engine.startService("swarm");
callback();
},
function deploy(callback) {
@ -258,8 +265,8 @@ class Embark {
engine.startMonitor();
engine.startService("libraryManager");
engine.startService("pipeline");
engine.startService("codeGenerator");
engine.startService("deployment", {onlyCompile: true});
engine.startService("codeGenerator");
engine.deployManager.deployContracts(function (err) {
callback(err);
@ -276,8 +283,8 @@ class Embark {
graphGen.generate(options);
engine.logger.info(__("Done. %s generated", "./diagram.svg").underline);
process.exit();
}
process.exit();
});
}
@ -294,6 +301,8 @@ class Embark {
let engine = new Engine({
env: options.env,
client: options.client,
locale: options.locale,
isDev: this.isDev(options.env),
version: this.version,
embarkConfig: 'embark.json',
@ -315,11 +324,13 @@ class Embark {
function startServices(callback) {
engine.startService("libraryManager");
engine.startService("codeRunner");
engine.startService("web3");
engine.startService("pipeline");
engine.startService("codeGenerator");
engine.startService("deployment");
engine.startService(platform.toLowerCase(), {bzz: engine.web3.bzz});
engine.startService("codeGenerator");
// TODO: this should be just 'storage' and the storage should figure out the modules to load
engine.startService(platform.toLowerCase());
engine.startMonitor();
callback();
},
@ -372,11 +383,12 @@ class Embark {
})
.catch(callback);
});
// 1. build the contracts and dapp webpack
engine.deployManager.deployContracts(function (err) {
engine.logger.info(__("finished deploying").underline);
if(err){
callback(err);
callback(err);
}
});
}

View File

@ -0,0 +1,89 @@
let utils = require('../../utils/utils.js');
let fs = require('../../core/fs.js');
class DeployTracker {
constructor(embark, options) {
this.logger = embark.logger;
this.events = embark.events;
// TODO: unclear where it comes from
this.env = options.env;
//this.chainConfig = options.chainConfig;
this.chainConfig = embark.config.chainTracker;
this.registerEvents();
}
registerEvents() {
const self = this;
this.events.on("deploy:beforeAll", this.setCurrentChain.bind(this));
this.events.on("deploy:contract:deployed", (contract) => {
self.trackContract(contract.className, contract.realRuntimeBytecode, contract.realArgs, contract.address);
self.save();
});
this.events.setCommandHandler("deploy:contract:shouldDeploy", (contract, cb) => {
let trackedContract = self.getContract(contract.className, contract.realRuntimeBytecode, contract.realArgs);
cb(trackedContract);
});
}
// TODO: just an event might not be enought to the async nature
// it needs to be a plugin api before deploy, that makes the deployment wait
setCurrentChain() {
const self = this;
if (this.chainConfig === false) {
this.currentChain = {contracts: []};
//return cb();
}
this.events.request("blockchain:block:byNumber", 0, function(_err, block) {
let chainId = block.hash;
if (self.chainConfig[chainId] === undefined) {
self.chainConfig[chainId] = {contracts: {}};
}
self.currentChain = self.chainConfig[chainId];
self.currentChain.name = self.env;
//cb();
});
}
loadConfig(config) {
this.chainConfig = config;
return this;
}
trackContract(contractName, code, args, address) {
if (!this.currentChain) return false;
this.currentChain.contracts[utils.sha3(code + contractName + args.join(','))] = {
name: contractName,
address: address
};
}
getContract(contractName, code, args) {
if (!this.currentChain) return false;
let contract = this.currentChain.contracts[utils.sha3(code + contractName + args.join(','))];
if (contract && contract.address === undefined) {
return false;
}
return contract;
}
// TODO: abstract this
// chainConfig can be an abstract PersistentObject
save() {
if (this.chainConfig === false) {
return;
}
fs.writeJSONSync("./chains.json", this.chainConfig, {spaces: 2});
}
}
module.exports = DeployTracker;

View File

@ -1,7 +1,7 @@
let UploadIPFS = require('./upload.js');
let utils = require('../../utils/utils.js');
let fs = require('../../core/fs.js');
let RunCode = require('../../core/runCode.js');
let RunCode = require('../../coderunner/runCode');
let IpfsApi = require('ipfs-api');
class IPFS {

View File

@ -0,0 +1,118 @@
const stringReplaceAsync = require('string-replace-async');
const async = require('async');
class SpecialConfigs {
constructor(embark, options) {
this.logger = embark.logger;
this.events = embark.events;
this.buildDir = options.buildDir;
this.addCheck = options.addCheck;
this.embark = embark;
this.contractsConfig = embark.config.contractsConfig;
this.registerAfterDeployAction();
this.registerOnDeployAction();
}
replaceWithAddresses(cmd, cb) {
const self = this;
let regex = /\$\w+/g;
stringReplaceAsync.seq(cmd, regex, (match) => {
return (new Promise((resolve, reject) => {
let referedContractName = match.slice(1);
self.events.request('contracts:contract', referedContractName, (referedContract) => {
if (!referedContract) {
self.logger.error(referedContractName + ' does not exist');
self.logger.error("error running cmd: " + cmd);
return reject(new Error("ReferedContractDoesNotExist"));
}
if (referedContract && referedContract.deploy === false) {
self.logger.error(referedContractName + " exists but has been set to not deploy");
self.logger.error("error running cmd: " + cmd);
return reject(new Error("ReferedContracSetToNotdeploy"));
}
if (referedContract && !referedContract.deployedAddress) {
self.logger.error("couldn't find a valid address for " + referedContractName + ". has it been deployed?");
self.logger.error("error running cmd: " + cmd);
return reject(new Error("ReferedContractAddressNotFound"));
}
return resolve(referedContract.deployedAddress);
});
}));
}).then((result) => {
cb(null, result);
}).catch(cb);
}
registerAfterDeployAction() {
const self = this;
this.embark.registerAfterAllContractsDeploy((cb) => {
let afterDeployCmds = self.contractsConfig.afterDeploy || [];
async.mapLimit(afterDeployCmds, 1, (cmd, nextMapCb) => {
self.replaceWithAddresses(cmd, nextMapCb);
}, (err, result) => {
if (err) {
return cb(new Error("error running afterDeploy"));
}
let onDeployCode = result;
// TODO: convert to for to avoid repeated callback
for(let cmd of onDeployCode) {
self.logger.info("==== executing: " + cmd);
try {
self.events.request('runcode:eval', cmd);
} catch(e) {
if (e.message.indexOf("invalid opcode") >= 0) {
self.logger.error('the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation');
}
return cb(new Error(e));
}
}
cb();
});
});
}
registerOnDeployAction() {
const self = this;
this.embark.registerOnDeployContracts((contract, cb) => {
if (!contract.onDeploy) {
return cb();
}
self.logger.info(__('executing onDeploy commands'));
let onDeployCmds = contract.onDeploy;
async.mapLimit(onDeployCmds, 1, (cmd, nextMapCb) => {
self.replaceWithAddresses(cmd, nextMapCb);
}, (err, result) => {
if (err) {
return cb(new Error("error running onDeploy for " + contract.className.cyan));
}
let onDeployCode = result;
// TODO: convert to for to avoid repeated callback
for(let cmd of onDeployCode) {
self.logger.info("==== executing: " + cmd);
try {
self.events.request('runcode:eval', cmd);
} catch(e) {
if (e.message.indexOf("invalid opcode") >= 0) {
self.logger.error('the transaction was rejected; this usually happens due to a throw or a require, it can also happen due to an invalid operation');
}
return cb(new Error(e));
}
}
cb();
});
});
}
}
module.exports = SpecialConfigs;

View File

@ -8,6 +8,7 @@ class Whisper {
this.events = embark.events;
this.communicationConfig = options.communicationConfig;
this.addCheck = options.addCheck;
// TODO: this should not be needed and should be deducted from the config instead
this.web3 = options.web3;
this.embark = embark;

View File

@ -18,7 +18,6 @@ class Pipeline {
this.assetFiles = options.assetFiles;
this.events = options.events;
this.logger = options.logger;
this.normalizeInput = options.normalizeInput;
this.plugins = options.plugins;
this.pipelinePlugins = this.plugins.getPluginsFor('pipeline');
}
@ -103,7 +102,7 @@ class Pipeline {
modulePath: utils.joinPath(__dirname, 'webpackProcess.js'),
logger: self.logger,
events: self.events,
normalizeInput: self.normalizeInput
normalizeInput: utils.normalizeInput
});
webpackProcess.send({action: constants.pipeline.init, options: {}});
webpackProcess.send({action: constants.pipeline.build, file, importsList});

View File

@ -1,6 +1,6 @@
const child_process = require('child_process');
const constants = require('../constants');
const path = require('path');
class ProcessLauncher {
@ -14,10 +14,13 @@ class ProcessLauncher {
* @return {ProcessLauncher} The ProcessLauncher instance
*/
constructor(options) {
this.name = path.basename(options.modulePath);
this.process = child_process.fork(options.modulePath);
this.logger = options.logger;
this.normalizeInput = options.normalizeInput;
this.events = options.events;
this.silent = options.silent;
this.exitCallback = options.exitCallback;
this.subscriptions = {};
this._subscribeToMessages();
@ -31,14 +34,26 @@ class ProcessLauncher {
return self._handleLog(msg);
}
if (msg.event) {
return this._handleEvent(msg);
return self._handleEvent(msg);
}
self._checkSubscriptions(msg);
});
this.process.on('exit', (code) => {
if (self.exitCallback) {
return self.exitCallback(code);
}
if (code) {
this.logger.info(`Child Process ${this.name} exited with code ${code}`);
}
this._checkSubscriptions(msg);
});
}
// Translates logs from the child process to the logger
_handleLog(msg) {
if (this.silent && msg.type !== 'error') {
return;
}
if (this.logger[msg.type]) {
return this.logger[msg.type](this.normalizeInput(msg.message));
}

View File

@ -45,6 +45,10 @@ class ProcessWrapper {
}
process.send({result: constants.process.log, message: messages, type});
}
send() {
process.send(...arguments);
}
}
process.on('exit', () => {

View File

@ -0,0 +1,51 @@
const ProcessLauncher = require('../process/processLauncher');
const utils = require('../utils/utils.js');
const constants = require('../constants');
class BlockchainProcessLauncher {
constructor (options) {
this.events = options.events;
this.logger = options.logger;
this.normalizeInput = options.normalizeInput;
this.blockchainConfig = options.blockchainConfig;
this.locale = options.locale;
this.isDev = options.isDev;
}
processEnded(code) {
this.logger.error('Blockchain process ended before the end of this process. Code: ' + code);
}
startBlockchainNode() {
this.logger.info('Starting Blockchain node in another process'.cyan);
this.blockchainProcess = new ProcessLauncher({
modulePath: utils.joinPath(__dirname, '../cmds/blockchain/blockchainProcess.js'),
logger: this.logger,
events: this.events,
normalizeInput: this.normalizeInput,
silent: true,
exitCallback: this.processEnded.bind(this)
});
this.blockchainProcess.send({
action: constants.blockchain.init, options: {
blockchainConfig: this.blockchainConfig,
//client: this.client,
// TODO: assume for now it's geth
client: 'geth',
env: this.env,
isDev: this.isDev,
locale: this.locale
}
});
this.blockchainProcess.once('result', constants.blockchain.blockchainReady, () => {
this.logger.info('Blockchain node is ready'.cyan);
this.events.emit(constants.blockchain.blockchainReady);
});
}
}
module.exports = BlockchainProcessLauncher;

View File

@ -2,7 +2,6 @@ var async = require('async');
//require("../utils/debug_util.js")(__filename, async);
var Web3 = require('web3');
var Engine = require('../core/engine.js');
var RunCode = require('../core/runCode.js');
var TestLogger = require('./test_logger.js');
var getSimulator = function() {
@ -68,11 +67,14 @@ Test.prototype.deployAll = function(contractsConfig, cb) {
function startServices(callback) {
//{abiType: 'contracts', embarkJS: false}
self.engine.startService("libraryManager");
self.engine.startService("codeGenerator");
self.engine.startService("codeRunner");
self.engine.startService("web3", {
web3: self.web3
});
self.engine.startService("deployment", {
web3: self.web3,
trackContracts: false
});
self.engine.startService("codeGenerator");
callback();
},
function deploy(callback) {
@ -104,7 +106,7 @@ Test.prototype.deployAll = function(contractsConfig, cb) {
throw new Error(err);
}
self.web3.eth.defaultAccount = accounts[0];
RunCode.doEval(result, {web3: self.web3});
self.engine.events.request('runcode:eval', result);
//cb();
cb(accounts);
});

View File

@ -6,6 +6,7 @@ let https = require('follow-redirects').https;
let shelljs = require('shelljs');
var tar = require('tar');
var propose = require('propose');
var Web3 = require('web3');
const constants = require('../constants');
//let fs = require('../core/fs.js');
@ -173,6 +174,31 @@ function getExternalContractUrl(file) {
};
}
function toChecksumAddress(address) {
return Web3.utils.toChecksumAddress(address);
}
function sha3(arg) {
return Web3.utils.sha3(arg);
}
function normalizeInput(input) {
let args = Object.values(input);
if (args.length === 0) {
return "";
}
if (args.length === 1) {
if (Array.isArray(args[0])) { return args[0].join(','); }
return args[0] || "";
}
return ('[' + args.map((x) => {
if (x === null) { return "null"; }
if (x === undefined) { return "undefined"; }
if (Array.isArray(x)) { return x.join(','); }
return x;
}).toString() + ']');
}
module.exports = {
joinPath: joinPath,
filesMatchingPattern: filesMatchingPattern,
@ -190,5 +216,8 @@ module.exports = {
extractTar: extractTar,
proposeAlternative: proposeAlternative,
pwd: pwd,
getExternalContractUrl
getExternalContractUrl,
toChecksumAddress: toChecksumAddress,
sha3: sha3,
normalizeInput
};

3206
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,7 @@
"serve-static": "^1.11.1",
"shelljs": "^0.5.0",
"solc": "0.4.23",
"string-replace-async": "^1.2.1",
"style-loader": "^0.19.0",
"tar": "^3.1.5",
"toposort": "^1.0.0",

View File

@ -38,7 +38,8 @@ describe('embark.Blockchain', function () {
wsRPC: true,
targetGasLimit: false,
fast: false,
light: false
light: false,
verbosity: undefined
};
let blockchain = new Blockchain(config, 'geth');
@ -75,7 +76,8 @@ describe('embark.Blockchain', function () {
wsRPC: true,
targetGasLimit: false,
fast: false,
light: false
light: false,
verbosity: undefined
};
let blockchain = new Blockchain(config, 'geth');

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,6 @@
/*globals describe, it*/
let ContractsManager = require('../lib/contracts/contracts.js');
let Compiler = require('../lib/contracts/compiler.js');
let Logger = require('../lib/core/logger.js');
let File = require('../lib/core/file.js');
let TestLogger = require('../lib/tests/test_logger.js');
@ -29,6 +30,12 @@ describe('embark.Contracts', function() {
});
plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']});
let compiler = new Compiler({plugins: plugins, logger: plugins.logger});
let events = new Events();
events.setCommandHandler("compiler:contracts", function(contractFiles, cb) {
compiler.compile_contracts(contractFiles, cb);
});
let contractsManager = new ContractsManager({
plugins: plugins,
contractFiles: [
@ -65,7 +72,7 @@ describe('embark.Contracts', function() {
}
},
logger: new Logger({}),
events: new Events()
events: events
});
describe('#build', function() {
@ -112,6 +119,12 @@ describe('embark.Contracts', function() {
});
plugins.loadInternalPlugin('solidity', {solcVersion: '0.4.17', contractDirectories: ['app/contracts/']});
let compiler = new Compiler({plugins: plugins, logger: plugins.logger});
let events = new Events();
events.setCommandHandler("compiler:contracts", function(contractFiles, cb) {
compiler.compile_contracts(contractFiles, cb);
});
let contractsManager = new ContractsManager({
plugins: plugins,
contractFiles: [
@ -158,7 +171,7 @@ describe('embark.Contracts', function() {
}
},
logger: new Logger({}),
events: new Events()
events: events
});
describe('#build', function() {

View File

@ -10,7 +10,8 @@ describe('ProcessWrapper', () => {
before(() => {
sinon.stub(ProcessLauncher.prototype, '_subscribeToMessages');
processLauncher = new ProcessLauncher({
logger: new TestLogger({})
logger: new TestLogger({}),
modulePath: 'test.js'
});
});