mirror of https://github.com/embarklabs/embark.git
Merge pull request #454 from embark-framework/features/blockchain-in-run_rebased
Blockchain process + Blockchain/web3 refactor
This commit is contained in:
commit
f2fe9efd22
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
});
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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
|
||||
};
|
|
@ -29,5 +29,10 @@
|
|||
"build": "build",
|
||||
"initiated": "initiated",
|
||||
"built": "built"
|
||||
},
|
||||
"blockchain": {
|
||||
"blockchainReady": "blockchainReady",
|
||||
"init": "init",
|
||||
"initiated": "initiated"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -64,6 +64,10 @@ class Provider {
|
|||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.engine.stop();
|
||||
}
|
||||
|
||||
eth_accounts(payload, cb) {
|
||||
return cb(null, this.addresses);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"
|
||||
}
|
32
lib/index.js
32
lib/index.js
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -45,6 +45,10 @@ class ProcessWrapper {
|
|||
}
|
||||
process.send({result: constants.process.log, message: messages, type});
|
||||
}
|
||||
|
||||
send() {
|
||||
process.send(...arguments);
|
||||
}
|
||||
}
|
||||
|
||||
process.on('exit', () => {
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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",
|
||||
|
|
|
@ -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
|
@ -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() {
|
||||
|
|
|
@ -10,7 +10,8 @@ describe('ProcessWrapper', () => {
|
|||
before(() => {
|
||||
sinon.stub(ProcessLauncher.prototype, '_subscribeToMessages');
|
||||
processLauncher = new ProcessLauncher({
|
||||
logger: new TestLogger({})
|
||||
logger: new TestLogger({}),
|
||||
modulePath: 'test.js'
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue