mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-22 03:29:43 +00:00
Add support for Parity
Addons - New chain initialization and genesis management - Option to choose client to use - Option to "ping forever" for Geth - Creation and unlock of accounts at client's start - Utility to fund accounts with ethers - Miner settings inside the ethereum client - Workaround to CORS problem: origin is now http://embark - Several double callback's checks Updates - Boilerplate, templates, configuration files and demo stuff - Messages and i18n strings - Tests Fixes - Geth client now uses miner.gastarget instead of the deprecated targetGasLimit - Workaround for shh_version with Parity Reworks of other PRs into the new code - Included delayed proxy - Send ready only when the proxy is started - Start HTTP and WS proxies individually - Async setupProxy - Fixed datadir for GethMiner
This commit is contained in:
parent
25bfea48b1
commit
81e798c89c
28
cmd/cmd.js
28
cmd/cmd.js
@ -3,7 +3,7 @@ const EmbarkController = require('./cmd_controller.js');
|
||||
const i18n = require('../lib/core/i18n/i18n.js');
|
||||
const utils = require('../lib/utils/utils.js');
|
||||
|
||||
let embark = new EmbarkController;
|
||||
let embark = new EmbarkController();
|
||||
|
||||
// set PWD to process.cwd() since Windows doesn't have a value for PWD
|
||||
if (!process.env.PWD) {
|
||||
@ -130,7 +130,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 (supported: %s)', 'geth'))
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client [%s] (default: %s)', 'geth, parity', 'geth'))
|
||||
.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('--pipeline [pipeline]', __('webpack config to use (default: production)'))
|
||||
@ -141,7 +141,7 @@ class Cmd {
|
||||
_options.logFile = _options.logfile; // fix casing
|
||||
_options.logLevel = _options.loglevel; // fix casing
|
||||
_options.onlyCompile = _options.contracts;
|
||||
_options.client = _options.client || 'geth';
|
||||
_options.client = _options.client;
|
||||
_options.webpackConfigName = _options.pipeline || 'production';
|
||||
embark.build(_options);
|
||||
});
|
||||
@ -151,7 +151,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 (supported: %s)', 'geth'))
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client [%s] (default: %s)', 'geth, parity', 'geth'))
|
||||
.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'))
|
||||
@ -167,9 +167,9 @@ class Cmd {
|
||||
const nullify = (v) => (!v || typeof v !== 'string') ? null : v;
|
||||
embark.run({
|
||||
env: env || 'development',
|
||||
serverPort: nullify(options.port),
|
||||
serverHost: nullify(options.host),
|
||||
client: options.client || 'geth',
|
||||
serverPort: options.port,
|
||||
serverHost: options.host,
|
||||
client: options.client,
|
||||
locale: options.locale,
|
||||
runWebserver: options.noserver == null ? null : !options.noserver,
|
||||
useDashboard: !options.nodashboard,
|
||||
@ -184,7 +184,7 @@ class Cmd {
|
||||
console() {
|
||||
program
|
||||
.command('console [environment]')
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client (supported: %s)', 'geth'))
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client [%s] (default: %s)', 'geth, parity', 'geth'))
|
||||
.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)'))
|
||||
@ -194,7 +194,7 @@ class Cmd {
|
||||
i18n.setOrDetectLocale(options.locale);
|
||||
embark.console({
|
||||
env: env || 'development',
|
||||
client: options.client || 'geth',
|
||||
client: options.client,
|
||||
locale: options.locale,
|
||||
logFile: options.logfile,
|
||||
logLevel: options.loglevel,
|
||||
@ -206,7 +206,7 @@ class Cmd {
|
||||
blockchain() {
|
||||
program
|
||||
.command('blockchain [environment]')
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client (supported: %s)', 'geth'))
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client [%s] (default: %s)', 'geth, parity', 'geth'))
|
||||
.option('--locale [locale]', __('language to use (default: en)'))
|
||||
.description(__('run blockchain server (default: %s)', 'development'))
|
||||
.action(function(env, options) {
|
||||
@ -215,7 +215,7 @@ class Cmd {
|
||||
embarkConfig: 'embark.json',
|
||||
interceptLogs: false
|
||||
});
|
||||
embark.blockchain(env || 'development', options.client || 'geth');
|
||||
embark.blockchain(env || 'development', options.client);
|
||||
});
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ class Cmd {
|
||||
program
|
||||
.command('simulator [environment]')
|
||||
.description(__('run a fast ethereum rpc simulator'))
|
||||
.option('--testrpc', __('use testrpc as the rpc simulator [%s]', 'default'))
|
||||
.option('--testrpc', __('use ganache-cli (former "testrpc") as the rpc simulator [%s]', 'default'))
|
||||
.option('-p, --port [port]', __('port to run the rpc simulator (default: %s)', '8545'))
|
||||
.option('-h, --host [host]', __('host to run the rpc simulator (default: %s)', 'localhost'))
|
||||
.option('-a, --accounts [numAccounts]', __('number of accounts (default: %s)', '10'))
|
||||
@ -288,7 +288,7 @@ 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 (supported: %s)', 'geth'))
|
||||
.option('-c, --client [client]', __('Use a specific ethereum client [%s] (default: %s)', 'geth, parity', 'geth'))
|
||||
.option('--pipeline [pipeline]', __('webpack config to use (default: production)'))
|
||||
.description(__('Upload your dapp to a decentralized storage') + '.')
|
||||
.action(function(env, _options) {
|
||||
@ -301,7 +301,7 @@ class Cmd {
|
||||
_options.ensDomain = _options.ens;
|
||||
_options.logFile = _options.logfile; // fix casing
|
||||
_options.logLevel = _options.loglevel; // fix casing
|
||||
_options.client = _options.client || 'geth';
|
||||
_options.client = _options.client;
|
||||
_options.webpackConfigName = _options.pipeline || 'production';
|
||||
embark.upload(_options);
|
||||
});
|
||||
|
@ -120,7 +120,7 @@ Config.prototype._updateBlockchainCors = function(){
|
||||
}
|
||||
// add whisper cors
|
||||
if(this.communicationConfig && this.communicationConfig.enabled && this.communicationConfig.provider === 'whisper'){
|
||||
corsParts.push('embark');
|
||||
corsParts.push('http://embark');
|
||||
}
|
||||
|
||||
let cors = corsParts.join(',');
|
||||
|
@ -232,6 +232,7 @@ class Engine {
|
||||
|
||||
web3Service(options) {
|
||||
this.registerModule('blockchain_process', {
|
||||
client: this.client,
|
||||
locale: this.locale,
|
||||
isDev: this.isDev,
|
||||
ipc: this.ipc
|
||||
|
@ -19,7 +19,13 @@ class Provider {
|
||||
if (this.type === 'rpc') {
|
||||
self.provider = new this.web3.providers.HttpProvider(self.web3Endpoint);
|
||||
} else if (this.type === 'ws') {
|
||||
self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "embark"}});
|
||||
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
||||
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
||||
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the followin error:
|
||||
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
||||
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
||||
self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "http://embark"}});
|
||||
|
||||
self.provider.on('error', e => self.logger.error('Websocket Error', e));
|
||||
self.provider.on('end', e => self.logger.error('Websocket connection ended', e));
|
||||
} else {
|
||||
|
@ -1,65 +1,65 @@
|
||||
const async = require('async');
|
||||
const child_process = require('child_process');
|
||||
const {spawn, exec} = require('child_process');
|
||||
|
||||
const fs = require('../../core/fs.js');
|
||||
const constants = require('../../constants.json');
|
||||
const utils = require('../../utils/utils.js');
|
||||
|
||||
const GethCommands = require('./geth_commands.js');
|
||||
const GethClient = require('./gethClient.js');
|
||||
const ParityClient = require('./parityClient.js');
|
||||
const DevFunds = require('./dev_funds.js');
|
||||
|
||||
const proxy = require('./proxy');
|
||||
const Ipc = require('../../core/ipc');
|
||||
|
||||
const {defaultHost, dockerHostSwap} = require('../../utils/host');
|
||||
|
||||
/*eslint complexity: ["error", 37]*/
|
||||
var Blockchain = function(options) {
|
||||
this.blockchainConfig = options.blockchainConfig;
|
||||
this.env = options.env || 'development';
|
||||
this.client = options.client;
|
||||
this.isDev = options.isDev;
|
||||
this.onReadyCallback = options.onReadyCallback || (() => {});
|
||||
this.onExitCallback = options.onExitCallback;
|
||||
/*eslint complexity: ["error", 36]*/
|
||||
var Blockchain = function(userConfig, clientClass) {
|
||||
this.userConfig = userConfig;
|
||||
this.env = userConfig.env || 'development';
|
||||
this.isDev = userConfig.isDev;
|
||||
this.onReadyCallback = userConfig.onReadyCallback || (() => {});
|
||||
this.onExitCallback = userConfig.onExitCallback;
|
||||
this.proxyIpc = null;
|
||||
|
||||
if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') {
|
||||
console.log("===> " + __("warning: running default config on a non-development environment"));
|
||||
}
|
||||
|
||||
let defaultWsApi = ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub'];
|
||||
if (this.isDev) {
|
||||
defaultWsApi.push('personal');
|
||||
}
|
||||
let defaultWsApi = clientClass.DEFAULTS.WS_API;
|
||||
if (this.isDev) defaultWsApi = clientClass.DEFAULTS.DEV_WS_API;
|
||||
|
||||
this.config = {
|
||||
geth_bin: this.blockchainConfig.geth_bin || 'geth',
|
||||
networkType: this.blockchainConfig.networkType || 'custom',
|
||||
genesisBlock: this.blockchainConfig.genesisBlock || false,
|
||||
datadir: this.blockchainConfig.datadir || false,
|
||||
mineWhenNeeded: this.blockchainConfig.mineWhenNeeded || false,
|
||||
rpcHost: dockerHostSwap(this.blockchainConfig.rpcHost) || defaultHost,
|
||||
rpcPort: this.blockchainConfig.rpcPort || 8545,
|
||||
rpcCorsDomain: this.blockchainConfig.rpcCorsDomain || false,
|
||||
networkId: this.blockchainConfig.networkId || 1337,
|
||||
port: this.blockchainConfig.port || 30303,
|
||||
nodiscover: this.blockchainConfig.nodiscover || false,
|
||||
mine: this.blockchainConfig.mine || false,
|
||||
account: this.blockchainConfig.account || {},
|
||||
whisper: (this.blockchainConfig.whisper === undefined) || this.blockchainConfig.whisper,
|
||||
maxpeers: ((this.blockchainConfig.maxpeers === 0) ? 0 : (this.blockchainConfig.maxpeers || 25)),
|
||||
bootnodes: this.blockchainConfig.bootnodes || "",
|
||||
rpcApi: (this.blockchainConfig.rpcApi || ['eth', 'web3', 'net', 'debug']),
|
||||
wsRPC: (this.blockchainConfig.wsRPC === undefined) || this.blockchainConfig.wsRPC,
|
||||
wsHost: dockerHostSwap(this.blockchainConfig.wsHost) || defaultHost,
|
||||
wsPort: this.blockchainConfig.wsPort || 8546,
|
||||
wsOrigins: this.blockchainConfig.wsOrigins || false,
|
||||
wsApi: (this.blockchainConfig.wsApi || defaultWsApi),
|
||||
vmdebug: this.blockchainConfig.vmdebug || false,
|
||||
targetGasLimit: this.blockchainConfig.targetGasLimit || false,
|
||||
syncMode: this.blockchainConfig.syncMode,
|
||||
syncmode: this.blockchainConfig.syncmode,
|
||||
verbosity: this.blockchainConfig.verbosity
|
||||
silent: this.userConfig.silent,
|
||||
ethereumClientName: this.userConfig.ethereumClientName,
|
||||
ethereumClientBin: this.userConfig.ethereumClientBin || this.userConfig.ethereumClientName || 'geth',
|
||||
networkType: this.userConfig.networkType || clientClass.DEFAULTS.NETWORK_TYPE,
|
||||
networkId: this.userConfig.networkId || clientClass.DEFAULTS.NETWORK_ID,
|
||||
genesisBlock: this.userConfig.genesisBlock || false,
|
||||
datadir: this.userConfig.datadir || false,
|
||||
mineWhenNeeded: this.userConfig.mineWhenNeeded || false,
|
||||
rpcHost: dockerHostSwap(this.userConfig.rpcHost) || defaultHost,
|
||||
rpcPort: this.userConfig.rpcPort || 8545,
|
||||
rpcCorsDomain: this.userConfig.rpcCorsDomain || false,
|
||||
rpcApi: this.userConfig.rpcApi || clientClass.DEFAULTS.RPC_API,
|
||||
port: this.userConfig.port || 30303,
|
||||
nodiscover: this.userConfig.nodiscover || false,
|
||||
mine: this.userConfig.mine || false,
|
||||
account: this.userConfig.account || {},
|
||||
devPassword: this.userConfig.devPassword || "",
|
||||
whisper: (this.userConfig.whisper != false),
|
||||
maxpeers: ((this.userConfig.maxpeers === 0) ? 0 : (this.userConfig.maxpeers || 25)),
|
||||
bootnodes: this.userConfig.bootnodes || "",
|
||||
wsRPC: (this.userConfig.wsRPC != false),
|
||||
wsHost: dockerHostSwap(this.userConfig.wsHost) || defaultHost,
|
||||
wsPort: this.userConfig.wsPort || 8546,
|
||||
wsOrigins: this.userConfig.wsOrigins || false,
|
||||
wsApi: this.userConfig.wsApi || defaultWsApi,
|
||||
vmdebug: this.userConfig.vmdebug || false,
|
||||
targetGasLimit: this.userConfig.targetGasLimit || false,
|
||||
syncMode: this.userConfig.syncMode || this.userConfig.syncmode,
|
||||
verbosity: this.userConfig.verbosity,
|
||||
proxy: this.userConfig.proxy || true
|
||||
};
|
||||
|
||||
if (this.blockchainConfig === {} || this.blockchainConfig.default) {
|
||||
if (this.userConfig === {} || this.userConfig.default || JSON.stringify(this.userConfig) === '{"enabled":true}') {
|
||||
this.config.account = {};
|
||||
if (this.env === 'development') {
|
||||
this.isDev = true;
|
||||
@ -87,35 +87,25 @@ var Blockchain = function(options) {
|
||||
process.exit();
|
||||
}
|
||||
this.initProxy();
|
||||
this.client = new options.client({config: this.config, env: this.env, isDev: this.isDev});
|
||||
this.client = new clientClass({config: this.config, env: this.env, isDev: this.isDev});
|
||||
};
|
||||
|
||||
Blockchain.prototype.initProxy = function() {
|
||||
this.config.proxy = true;
|
||||
if (this.blockchainConfig.proxy === false) {
|
||||
this.config.proxy = false;
|
||||
return;
|
||||
if (this.config.proxy) {
|
||||
this.config.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
this.config.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
}
|
||||
|
||||
this.config.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
this.config.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
};
|
||||
|
||||
Blockchain.prototype.setupProxy = async function() {
|
||||
const proxy = require('./proxy');
|
||||
const Ipc = require('../../core/ipc');
|
||||
if (!this.proxyIpc) this.proxyIpc = new Ipc({ipcRole: 'client'});
|
||||
|
||||
if(!this.proxyIpc) this.proxyIpc = new Ipc({ipcRole: 'client'});
|
||||
|
||||
let wsProxy;
|
||||
if(this.config.wsRPC) {
|
||||
if (this.config.wsRPC) {
|
||||
wsProxy = proxy.serve(this.proxyIpc, this.config.wsHost, this.config.wsPort, true, this.config.wsOrigins);
|
||||
}
|
||||
|
||||
[this.rpcProxy, this.wsProxy] = await Promise.all([
|
||||
proxy.serve(this.proxyIpc, this.config.rpcHost, this.config.rpcPort, false),
|
||||
wsProxy
|
||||
]);
|
||||
|
||||
[this.rpcProxy, this.wsProxy] = await Promise.all([proxy.serve(this.proxyIpc, this.config.rpcHost, this.config.rpcPort, false), wsProxy]);
|
||||
};
|
||||
|
||||
Blockchain.prototype.shutdownProxy = function() {
|
||||
@ -123,52 +113,55 @@ Blockchain.prototype.shutdownProxy = function() {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.rpcProxy) this.rpcProxy.close();
|
||||
if(this.wsProxy) this.wsProxy.close();
|
||||
if (this.rpcProxy) this.rpcProxy.close();
|
||||
if (this.wsProxy) this.wsProxy.close();
|
||||
};
|
||||
|
||||
Blockchain.prototype.runCommand = function(cmd, options, callback) {
|
||||
console.log(__("running: %s", cmd.underline).green);
|
||||
if (this.blockchainConfig.silent) {
|
||||
if (this.config.silent) {
|
||||
options.silent = true;
|
||||
}
|
||||
return child_process.exec(cmd, options, callback);
|
||||
return exec(cmd, options, callback);
|
||||
};
|
||||
|
||||
Blockchain.prototype.run = function() {
|
||||
var self = this;
|
||||
console.log("===============================================================================".magenta);
|
||||
console.log("===============================================================================".magenta);
|
||||
console.log(__("Embark Blockchain Using: %s", this.client.name.underline).magenta);
|
||||
console.log(__("Embark Blockchain using %s", self.client.prettyName.underline).magenta);
|
||||
console.log("===============================================================================".magenta);
|
||||
console.log("===============================================================================".magenta);
|
||||
this.checkPathLength();
|
||||
|
||||
if (self.client.name === 'geth') this.checkPathLength();
|
||||
|
||||
let address = '';
|
||||
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);
|
||||
return next({message: err});
|
||||
}
|
||||
next();
|
||||
});
|
||||
},
|
||||
function init(next) {
|
||||
if (!self.isDev) {
|
||||
return self.initChainAndGetAddress((err, addr) => {
|
||||
address = addr;
|
||||
if (self.isDev) {
|
||||
return self.initDevChain((err) => {
|
||||
next(err);
|
||||
});
|
||||
}
|
||||
next();
|
||||
return self.initChainAndGetAddress((err, addr) => {
|
||||
address = addr;
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function getMainCommand(next) {
|
||||
self.client.mainCommand(address, function(cmd, args) {
|
||||
next(null, cmd, args);
|
||||
}, true);
|
||||
}
|
||||
], function (err, cmd, args) {
|
||||
], function(err, cmd, args) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
@ -177,7 +170,8 @@ Blockchain.prototype.run = function() {
|
||||
|
||||
let full_cmd = cmd + " " + args.join(' ');
|
||||
console.log(__("running: %s", full_cmd.underline).green);
|
||||
self.child = child_process.spawn(cmd, args, {cwd: process.cwd()});
|
||||
self.child = spawn(cmd, args, {cwd: process.cwd()});
|
||||
|
||||
self.child.on('error', (err) => {
|
||||
err = err.toString();
|
||||
console.error('Blockchain error: ', err);
|
||||
@ -187,28 +181,20 @@ Blockchain.prototype.run = function() {
|
||||
console.error(__('Otherwise, you can change your data directory in blockchain.json (datadir)').yellow);
|
||||
}
|
||||
});
|
||||
|
||||
// TOCHECK I don't understand why stderr and stdout are reverted.
|
||||
// This happens with Geth and Parity, so it does not seems a client problem
|
||||
self.child.stdout.on('data', (data) => {
|
||||
console.error(`Geth error: ${data}`);
|
||||
console.error(`${self.client.name} error: ${data}`);
|
||||
});
|
||||
let httpReady = false;
|
||||
let wsReady = !self.config.wsRPC;
|
||||
// Geth logs appear in stderr somehow
|
||||
|
||||
self.child.stderr.on('data', async (data) => {
|
||||
data = data.toString();
|
||||
if (data.indexOf('HTTP endpoint opened') > -1) {
|
||||
httpReady = true;
|
||||
}
|
||||
|
||||
if (data.indexOf('WebSocket endpoint opened') > -1) {
|
||||
wsReady = true;
|
||||
}
|
||||
|
||||
if (!self.readyCalled && wsReady && httpReady) {
|
||||
if (!self.readyCalled && self.client.isReady(data)) {
|
||||
self.readyCalled = true;
|
||||
if (self.isDev) {
|
||||
self.createFundAndUnlockAccounts((err) => {
|
||||
// TODO: this is never called!
|
||||
if(err) console.error('Error creating, unlocking, and funding accounts', err);
|
||||
self.fundAccounts((err) => {
|
||||
if (err) console.error('Error funding accounts', err);
|
||||
});
|
||||
}
|
||||
if (self.config.proxy) {
|
||||
@ -216,36 +202,34 @@ Blockchain.prototype.run = function() {
|
||||
}
|
||||
self.readyCallback();
|
||||
}
|
||||
|
||||
console.log('Geth: ' + data);
|
||||
console.log(`${self.client.name}: ${data}`);
|
||||
});
|
||||
|
||||
self.child.on('exit', (code) => {
|
||||
let strCode;
|
||||
if (code) {
|
||||
strCode = ' with error code ' + code;
|
||||
strCode = 'with error code ' + code;
|
||||
} else {
|
||||
strCode = ' with no error code (manually killed?)';
|
||||
strCode = 'with no error code (manually killed?)';
|
||||
}
|
||||
console.error('Geth exited' + strCode);
|
||||
|
||||
if(self.onExitCallback){
|
||||
console.error(self.client.name + ' exited ' + strCode);
|
||||
if (self.onExitCallback) {
|
||||
self.onExitCallback();
|
||||
}
|
||||
});
|
||||
|
||||
self.child.on('uncaughtException', (err) => {
|
||||
console.error('Uncaught geth exception', err);
|
||||
|
||||
if(self.onExitCallback){
|
||||
console.error('Uncaught ' + self.client.name + ' exception', err);
|
||||
if (self.onExitCallback) {
|
||||
self.onExitCallback();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Blockchain.prototype.createFundAndUnlockAccounts = function(cb) {
|
||||
Blockchain.prototype.fundAccounts = function(cb) {
|
||||
DevFunds.new({blockchainConfig: this.config}).then(devFunds => {
|
||||
devFunds.createFundAndUnlockAccounts((err) => {
|
||||
devFunds.fundAccounts(this.client.needKeepAlive(), (err) => {
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
@ -255,16 +239,13 @@ Blockchain.prototype.readyCallback = function() {
|
||||
if (this.onReadyCallback) {
|
||||
this.onReadyCallback();
|
||||
}
|
||||
|
||||
if (this.config.mineWhenNeeded && !this.isDev) {
|
||||
const GethMiner = require('./miner');
|
||||
this.miner = new GethMiner({datadir: this.blockchainConfig.datadir});
|
||||
this.miner = this.client.getMiner();
|
||||
}
|
||||
};
|
||||
|
||||
Blockchain.prototype.kill = function() {
|
||||
this.shutdownProxy();
|
||||
|
||||
if (this.child) {
|
||||
this.child.kill();
|
||||
}
|
||||
@ -275,8 +256,8 @@ Blockchain.prototype.checkPathLength = function() {
|
||||
if (dappPath.length > 66) {
|
||||
// console.error is captured and sent to the console output regardless of silent setting
|
||||
console.error("===============================================================================".yellow);
|
||||
console.error("===========> ".yellow + __('WARNING! DApp path length is too long: ').yellow + dappPath.yellow);
|
||||
console.error("===========> ".yellow + __('This is known to cause issues with starting geth, please consider reducing your DApp path\'s length to 66 characters or less.').yellow);
|
||||
console.error("===========> ".yellow + __('WARNING! ÐApp path length is too long: ').yellow + dappPath.yellow);
|
||||
console.error("===========> ".yellow + __('This is known to cause issues with starting geth, please consider reducing your ÐApp path\'s length to 66 characters or less.').yellow);
|
||||
console.error("===============================================================================".yellow);
|
||||
}
|
||||
};
|
||||
@ -285,12 +266,81 @@ Blockchain.prototype.isClientInstalled = function(callback) {
|
||||
let versionCmd = this.client.determineVersionCommand();
|
||||
this.runCommand(versionCmd, {}, (err, stdout, stderr) => {
|
||||
if (err || !stdout || stderr.indexOf("not found") >= 0 || stdout.indexOf("not found") >= 0) {
|
||||
return callback('Geth not found');
|
||||
return callback(__('Ethereum client bin not found:') + ' ' + this.client.getBinaryPath());
|
||||
}
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
Blockchain.prototype.initDevChain = function(callback) {
|
||||
const self = this;
|
||||
const ACCOUNTS_ALREADY_PRESENT = 'accounts_already_present';
|
||||
// Init the dev chain
|
||||
self.client.initDevChain('.embark/development/datadir', (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let needToCreateOtherAccounts = self.config.account && self.config.account.numAccounts;
|
||||
if (!needToCreateOtherAccounts) return callback();
|
||||
|
||||
// Create other accounts
|
||||
async.waterfall([
|
||||
function listAccounts(next) {
|
||||
self.runCommand(self.client.listAccountsCommand(), {}, (err, stdout, _stderr) => {
|
||||
if (err || stdout === undefined || stdout.indexOf("Fatal") >= 0) {
|
||||
console.log(__("no accounts found").green);
|
||||
return next();
|
||||
}
|
||||
// List current addresses
|
||||
self.config.unlockAddressList = self.client.parseListAccountsCommandResultToAddressList(stdout);
|
||||
// Count current addresses and remove the default account from the count (because password can be different)
|
||||
let addressCount = self.client.parseListAccountsCommandResultToAddressCount(stdout);
|
||||
let utilityAddressCount = self.client.parseListAccountsCommandResultToAddressCount(stdout) - 1;
|
||||
utilityAddressCount = (utilityAddressCount > 0 ? utilityAddressCount : 0);
|
||||
let accountsToCreate = self.config.account.numAccounts - utilityAddressCount;
|
||||
if (accountsToCreate > 0) {
|
||||
next(null, accountsToCreate, addressCount === 0);
|
||||
} else {
|
||||
next(ACCOUNTS_ALREADY_PRESENT);
|
||||
}
|
||||
});
|
||||
},
|
||||
function newAccounts(accountsToCreate, firstAccount, next) {
|
||||
// At first launch, Geth --dev does not create its own dev account if any other account are present. Parity --dev always does. Make this choerent between the two
|
||||
if (firstAccount && self.client.name === 'geth') accountsToCreate++;
|
||||
var accountNumber = 0;
|
||||
async.whilst(
|
||||
function() {
|
||||
return accountNumber < accountsToCreate;
|
||||
},
|
||||
function(callback) {
|
||||
accountNumber++;
|
||||
self.runCommand(self.client.newAccountCommand(firstAccount), {}, (err, stdout, _stderr) => {
|
||||
if (err) {
|
||||
return callback(err, accountNumber);
|
||||
}
|
||||
self.config.unlockAddressList.push(self.client.parseNewAccountCommandResultToAddress(stdout));
|
||||
firstAccount = false;
|
||||
callback(null, accountNumber);
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
next(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
], (err) => {
|
||||
if (err && err !== ACCOUNTS_ALREADY_PRESENT) {
|
||||
console.log(err);
|
||||
return callback(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Blockchain.prototype.initChainAndGetAddress = function(callback) {
|
||||
const self = this;
|
||||
let address = null;
|
||||
@ -307,17 +357,23 @@ Blockchain.prototype.initChainAndGetAddress = function(callback) {
|
||||
},
|
||||
function listAccounts(next) {
|
||||
self.runCommand(self.client.listAccountsCommand(), {}, (err, stdout, _stderr) => {
|
||||
if (err || stdout === undefined || stdout.match(/{(\w+)}/) === null || stdout.indexOf("Fatal") >= 0) {
|
||||
if (err || stdout === undefined || stdout.indexOf("Fatal") >= 0) {
|
||||
console.log(__("no accounts found").green);
|
||||
return next();
|
||||
}
|
||||
let firstAccountFound = self.client.parseListAccountsCommandResultToAddress(stdout);
|
||||
if (firstAccountFound === undefined || firstAccountFound === "") {
|
||||
console.log(__("no accounts found").green);
|
||||
return next();
|
||||
}
|
||||
console.log(__("already initialized").green);
|
||||
address = stdout.match(/{(\w+)}/)[1];
|
||||
address = firstAccountFound;
|
||||
next(ALREADY_INITIALIZED);
|
||||
});
|
||||
},
|
||||
function genesisBlock(next) {
|
||||
if (!self.config.genesisBlock) {
|
||||
//There's no genesis init with Parity. Custom network are set in the chain property at startup
|
||||
if (!self.config.genesisBlock || self.client.name === 'parity') {
|
||||
return next();
|
||||
}
|
||||
console.log(__("initializing genesis block").green);
|
||||
@ -330,7 +386,7 @@ Blockchain.prototype.initChainAndGetAddress = function(callback) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
address = stdout.match(/{(\w+)}/)[1];
|
||||
address = self.client.parseNewAccountCommandResultToAddress(stdout);
|
||||
next();
|
||||
});
|
||||
}
|
||||
@ -342,13 +398,34 @@ Blockchain.prototype.initChainAndGetAddress = function(callback) {
|
||||
});
|
||||
};
|
||||
|
||||
var BlockchainClient = function(blockchainConfig, client, env, onReadyCallback, onExitCallback) {
|
||||
const isDev = !!blockchainConfig.isDev;
|
||||
// TODO add other clients at some point
|
||||
if (client === 'geth') {
|
||||
return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback, onExitCallback});
|
||||
var BlockchainClient = function(userConfig, clientName, env, onReadyCallback, onExitCallback) {
|
||||
if ((userConfig === {} || JSON.stringify(userConfig) === '{"enabled":true}') && env !== 'development') {
|
||||
console.log("===> " + __("warning: running default config on a non-development environment"));
|
||||
}
|
||||
throw new Error('unknown client');
|
||||
// if client is not set in preferences, default is geth
|
||||
if (!userConfig.ethereumClientName) userConfig.ethereumClientName = 'geth';
|
||||
// if clientName is set, it overrides preferences
|
||||
if (clientName) userConfig.ethereumClientName = clientName;
|
||||
// Choose correct client instance based on clientName
|
||||
let clientClass;
|
||||
switch (userConfig.ethereumClientName) {
|
||||
case 'geth':
|
||||
clientClass = GethClient;
|
||||
break;
|
||||
|
||||
case 'parity':
|
||||
clientClass = ParityClient;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error(__('Unknow client "%s". Please use one of the following: %s', userConfig.ethereumClientName, 'geth, parity'));
|
||||
process.exit();
|
||||
}
|
||||
userConfig.isDev = (userConfig.isDev || userConfig.default);
|
||||
userConfig.env = env;
|
||||
userConfig.onReadyCallback = onReadyCallback;
|
||||
userConfig.onExitCallback = onExitCallback;
|
||||
return new Blockchain(userConfig, clientClass);
|
||||
};
|
||||
|
||||
module.exports = BlockchainClient;
|
||||
|
@ -32,7 +32,7 @@ class BlockchainProcess extends ProcessWrapper {
|
||||
}
|
||||
|
||||
blockchainExit() {
|
||||
// tell our parent process that geth has exited
|
||||
// tell our parent process that ethereum client has exited
|
||||
blockchainProcess.send({result: constants.blockchain.blockchainExit});
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ class BlockchainProcessLauncher {
|
||||
this.blockchainConfig = options.blockchainConfig;
|
||||
this.locale = options.locale;
|
||||
this.isDev = options.isDev;
|
||||
this.client = options.client;
|
||||
}
|
||||
|
||||
processEnded(code) {
|
||||
@ -30,9 +31,7 @@ class BlockchainProcessLauncher {
|
||||
this.blockchainProcess.send({
|
||||
action: constants.blockchain.init, options: {
|
||||
blockchainConfig: this.blockchainConfig,
|
||||
//client: this.client,
|
||||
// TODO: assume for now it's geth
|
||||
client: 'geth',
|
||||
client: this.client,
|
||||
env: this.env,
|
||||
isDev: this.isDev,
|
||||
locale: this.locale
|
||||
|
@ -4,28 +4,28 @@ const {getWeiBalanceFromString, buildUrl} = require('../../utils/utils.js');
|
||||
const {readFileSync, dappPath} = require('../../core/fs');
|
||||
|
||||
class DevFunds {
|
||||
constructor(options) {
|
||||
constructor(options) {
|
||||
this.blockchainConfig = options.blockchainConfig;
|
||||
this.accounts = [];
|
||||
this.numAccounts = this.blockchainConfig.account.numAccounts || 0;
|
||||
this.password = this.blockchainConfig.account.password ? readFileSync(dappPath(this.blockchainConfig.account.password), 'utf8').replace('\n', '') : 'dev_password';
|
||||
this.networkId = null;
|
||||
this.balance = Web3.utils.toWei("1", "ether");
|
||||
this.provider = options.provider || new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: "http://localhost:8000"}});
|
||||
this.provider = options.provider || new Web3.providers.WebsocketProvider(buildUrl('ws', this.blockchainConfig.wsHost, this.blockchainConfig.wsPort), {headers: {Origin: "http://embark"}});
|
||||
this.web3 = new Web3(this.provider);
|
||||
if (this.blockchainConfig.account.balance) {
|
||||
this.balance = getWeiBalanceFromString(this.blockchainConfig.account.balance, this.web3);
|
||||
}
|
||||
this.logger = options.logger || console;
|
||||
}
|
||||
|
||||
static async new(options){
|
||||
|
||||
static async new(options) {
|
||||
const df = new DevFunds(options);
|
||||
await df._init();
|
||||
return df;
|
||||
}
|
||||
|
||||
async _init () {
|
||||
|
||||
async _init() {
|
||||
const accounts = await this.web3.eth.getAccounts();
|
||||
this.web3.eth.defaultAccount = accounts[0];
|
||||
if (accounts.length > 1) {
|
||||
@ -34,13 +34,13 @@ class DevFunds {
|
||||
}
|
||||
|
||||
_sendTx() {
|
||||
if (this.networkId !== 1337) {
|
||||
// Send TXs only in dev networks
|
||||
if (this.networkId !== 1337 && this.networkId !== 17) {
|
||||
return;
|
||||
}
|
||||
this.web3.eth.sendTransaction({value: "1000000000000000", to: "0xA2817254cb8E7b6269D1689c3E0eBadbB78889d1", from: this.web3.eth.defaultAccount});
|
||||
}
|
||||
|
||||
// trigger regular txs due to a bug in geth and stuck transactions in --dev mode
|
||||
_regularTxs(cb) {
|
||||
const self = this;
|
||||
self.web3.eth.net.getId().then((networkId) => {
|
||||
@ -48,23 +48,30 @@ class DevFunds {
|
||||
if (self.networkId !== 1337) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInterval(function () { self._sendTx(); }, 1500);
|
||||
setInterval(function() { self._sendTx(); }, 1500);
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_regularUnlocks() {
|
||||
const self = this;
|
||||
setInterval(function () { self.unlockAccounts(self.password, () => { }); }, 20000);
|
||||
_fundAccounts(balance, cb) {
|
||||
async.each(this.accounts, (account, next) => {
|
||||
this.web3.eth.getBalance(account).then(currBalance => {
|
||||
const remainingBalance = balance - currBalance;
|
||||
if (remainingBalance <= 0) return next();
|
||||
this.web3.eth.sendTransaction({to: account, value: remainingBalance}).catch(console.error);
|
||||
next(); // don't wait for the tx receipt as it never comes!
|
||||
}).catch(console.error);
|
||||
}, cb);
|
||||
}
|
||||
|
||||
// TOCHECK:
|
||||
// This function is not used anymore, but I leave because it is used for testing purpose (see test/devFunds.js)
|
||||
// I suggest to remove this function and the corresponding test case
|
||||
createAccounts(numAccounts, password, cb) {
|
||||
const numAccountsToCreate = numAccounts - (this.accounts.length + 1);
|
||||
if (numAccountsToCreate === 0) return cb();
|
||||
|
||||
async.timesLimit(numAccountsToCreate, 1, (_, next) => {
|
||||
this.web3.eth.personal.newAccount(password, next);
|
||||
}, (err, accounts) => {
|
||||
@ -74,6 +81,9 @@ class DevFunds {
|
||||
});
|
||||
}
|
||||
|
||||
// TOCHECK:
|
||||
// This function is not used anymore, but I leave because it is used for testing purpose (see test/devFunds.js)
|
||||
// I suggest to remove this function and the corresponding test case
|
||||
unlockAccounts(password, cb) {
|
||||
async.each(this.accounts, (account, next) => {
|
||||
this.web3.eth.personal.unlockAccount(account, password).then((_result) => {
|
||||
@ -82,33 +92,14 @@ class DevFunds {
|
||||
}, cb);
|
||||
}
|
||||
|
||||
fundAccounts(balance, cb) {
|
||||
async.each(this.accounts, (account, next) => {
|
||||
this.web3.eth.getBalance(account).then(currBalance => {
|
||||
const remainingBalance = balance - currBalance;
|
||||
if (remainingBalance <= 0) return next();
|
||||
|
||||
this.web3.eth.sendTransaction({to: account, value: remainingBalance}).catch(next);
|
||||
next(); // don't wait for the tx receipt as it never comes!
|
||||
}).catch(cb);
|
||||
}, cb);
|
||||
}
|
||||
|
||||
createFundAndUnlockAccounts(cb) {
|
||||
fundAccounts(pingForever = false, cb) {
|
||||
if (!this.web3) {
|
||||
return cb();
|
||||
}
|
||||
async.waterfall([
|
||||
(next) => {
|
||||
this.createAccounts(this.numAccounts, this.password, next);
|
||||
},
|
||||
(next) => {
|
||||
this.unlockAccounts(this.password, next);
|
||||
},
|
||||
(next) => {
|
||||
this._regularTxs();
|
||||
this._regularUnlocks();
|
||||
this.fundAccounts(this.balance, next);
|
||||
if (pingForever) this._regularTxs();
|
||||
this._fundAccounts(this.balance, next);
|
||||
}
|
||||
], cb);
|
||||
}
|
||||
|
@ -1,16 +1,59 @@
|
||||
const async = require('async');
|
||||
const GethMiner = require('./miner');
|
||||
const os = require('os');
|
||||
|
||||
const DEFAULTS = {
|
||||
"BIN": "geth",
|
||||
"NETWORK_TYPE": "custom",
|
||||
"NETWORK_ID": 1337,
|
||||
"RPC_API": ['eth', 'web3', 'net', 'debug'],
|
||||
"WS_API": ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub'],
|
||||
"DEV_WS_API": ['eth', 'web3', 'net', 'shh', 'debug', 'pubsub', 'personal'],
|
||||
"TARGET_GAS_LIMIT": 8000000
|
||||
};
|
||||
|
||||
// TODO: make all of this async
|
||||
class GethCommands {
|
||||
class GethClient {
|
||||
|
||||
static get DEFAULTS() {
|
||||
return DEFAULTS;
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
this.config = options && options.hasOwnProperty('config') ? options.config : {};
|
||||
this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
|
||||
this.isDev = options && options.hasOwnProperty('isDev') ? options.isDev : (this.env === 'development');
|
||||
this.name = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
|
||||
this.geth_bin = this.config.geth_bin || "geth";
|
||||
this.name = "geth";
|
||||
this.prettyName = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
|
||||
this.bin = this.config.ethereumClientBin || DEFAULTS.BIN;
|
||||
this.httpReady = false;
|
||||
this.wsReady = !this.config.wsRPC;
|
||||
}
|
||||
|
||||
commonOptions() {
|
||||
isReady(data) {
|
||||
if (data.indexOf('HTTP endpoint opened') > -1) {
|
||||
this.httpReady = true;
|
||||
}
|
||||
if (data.indexOf('WebSocket endpoint opened') > -1) {
|
||||
this.wsReady = true;
|
||||
}
|
||||
return this.httpReady && this.wsReady;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the client needs some sort of 'keep alive' transactions to avoid freezing by inactivity
|
||||
* @returns {boolean} if keep alive is needed
|
||||
*/
|
||||
needKeepAlive() {
|
||||
// TODO: check version also (geth version < 1.8.15)
|
||||
if (this.isDev) {
|
||||
// Trigger regular txs due to a bug in geth (< 1.8.15) and stuck transactions in --dev mode.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
commonOptions(firstAccount = false) {
|
||||
let config = this.config;
|
||||
let cmd = [];
|
||||
|
||||
@ -20,23 +63,33 @@ class GethCommands {
|
||||
cmd.push(`--datadir=${config.datadir}`);
|
||||
}
|
||||
|
||||
if (config.syncMode || config.syncmode) {
|
||||
cmd.push("--syncmode=" + (config.syncmode || config.syncMode));
|
||||
if (config.syncMode) {
|
||||
cmd.push("--syncmode=" + config.syncMode);
|
||||
}
|
||||
|
||||
// geth in dev mode needs the first account to have a blank password, so we use for convenience the same Parity's devpassword
|
||||
if (config.account && config.account.password) {
|
||||
cmd.push(`--password=${config.account.password}`);
|
||||
if (firstAccount) cmd.push(`--password=${config.account.devPassword}`);
|
||||
else cmd.push(`--password=${config.account.password}`);
|
||||
}
|
||||
|
||||
if (Number.isInteger(config.verbosity) && config.verbosity >=0 && config.verbosity <= 5) {
|
||||
if (Number.isInteger(config.verbosity) && config.verbosity >= 0 && config.verbosity <= 5) {
|
||||
cmd.push("--verbosity=" + config.verbosity);
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
getMiner() {
|
||||
return new GethMiner({datadir: this.config.datadir});
|
||||
}
|
||||
|
||||
getBinaryPath() {
|
||||
return this.bin;
|
||||
}
|
||||
|
||||
determineVersionCommand() {
|
||||
return this.geth_bin + " version";
|
||||
return this.bin + " version";
|
||||
}
|
||||
|
||||
determineNetworkType(config) {
|
||||
@ -53,89 +106,101 @@ class GethCommands {
|
||||
|
||||
initGenesisCommmand() {
|
||||
let config = this.config;
|
||||
let cmd = this.geth_bin + " " + this.commonOptions().join(' ');
|
||||
|
||||
let cmd = this.bin + " " + this.commonOptions().join(' ');
|
||||
if (config.genesisBlock) {
|
||||
cmd += " init \"" + config.genesisBlock + "\" ";
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
newAccountCommand() {
|
||||
if (!(this.config.account && this.config.account.password)){
|
||||
newAccountCommand(firstAccount = false) {
|
||||
if (!(this.config.account && this.config.account.password)) {
|
||||
console.warn(__('Your blockchain is missing a password and creating an account may fail. Please consider updating ').yellow + __('config/blockchain > account > password').cyan + __(' then re-run the command').yellow);
|
||||
}
|
||||
return this.geth_bin + " " + this.commonOptions().join(' ') + " account new ";
|
||||
return this.bin + " " + this.commonOptions(firstAccount).join(' ') + " account new ";
|
||||
}
|
||||
|
||||
parseNewAccountCommandResultToAddress(data = "") {
|
||||
if (data.match(/{(\w+)}/)) return "0x" + data.match(/{(\w+)}/)[1];
|
||||
return "";
|
||||
}
|
||||
|
||||
listAccountsCommand() {
|
||||
return this.geth_bin + " " + this.commonOptions().join(' ') + " account list ";
|
||||
return this.bin + " " + this.commonOptions().join(' ') + " account list ";
|
||||
}
|
||||
|
||||
parseListAccountsCommandResultToAddress(data = "") {
|
||||
if (data.match(/{(\w+)}/)) return "0x" + data.match(/{(\w+)}/)[1];
|
||||
return "";
|
||||
}
|
||||
|
||||
parseListAccountsCommandResultToAddressList(data = "") {
|
||||
let list = data.split(os.EOL);
|
||||
list.pop(); // Remove empty value
|
||||
return list.map(el => "0x" + el.match(/{(\w+)}/)[1]);
|
||||
}
|
||||
|
||||
parseListAccountsCommandResultToAddressCount(data = "") {
|
||||
const count = this.parseListAccountsCommandResultToAddressList(data).length;
|
||||
return (count > 0 ? count : 0);
|
||||
}
|
||||
|
||||
determineRpcOptions(config) {
|
||||
let cmd = [];
|
||||
|
||||
cmd.push("--port=" + config.port);
|
||||
cmd.push("--rpc");
|
||||
cmd.push("--rpcport=" + config.rpcPort);
|
||||
cmd.push("--rpcaddr=" + config.rpcHost);
|
||||
if (config.rpcCorsDomain) {
|
||||
if (config.rpcCorsDomain === '*') {
|
||||
console.log('==================================');
|
||||
console.log(__('rpcCorsDomain set to *'));
|
||||
console.log(__('make sure you know what you are doing'));
|
||||
console.log('==================================');
|
||||
console.warn('==================================');
|
||||
console.warn(__('rpcCorsDomain set to *'));
|
||||
console.warn(__('make sure you know what you are doing'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
cmd.push("--rpccorsdomain=" + config.rpcCorsDomain);
|
||||
} else {
|
||||
console.log('==================================');
|
||||
console.log(__('warning: cors is not set'));
|
||||
console.log('==================================');
|
||||
console.warn('==================================');
|
||||
console.warn(__('warning: cors is not set'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
determineWsOptions(config) {
|
||||
let cmd = [];
|
||||
|
||||
if (config.wsRPC) {
|
||||
cmd.push("--ws");
|
||||
cmd.push("--wsport=" + config.wsPort);
|
||||
cmd.push("--wsaddr=" + config.wsHost);
|
||||
if (config.wsOrigins) {
|
||||
if (config.wsOrigins === '*') {
|
||||
console.log('==================================');
|
||||
console.log(__('wsOrigins set to *'));
|
||||
console.log(__('make sure you know what you are doing'));
|
||||
console.log('==================================');
|
||||
console.warn('==================================');
|
||||
console.warn(__('wsOrigins set to *'));
|
||||
console.warn(__('make sure you know what you are doing'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
cmd.push("--wsorigins=" + config.wsOrigins);
|
||||
} else {
|
||||
console.log('==================================');
|
||||
console.log(__('warning: wsOrigins is not set'));
|
||||
console.log('==================================');
|
||||
console.warn('==================================');
|
||||
console.warn(__('warning: wsOrigins is not set'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
initDevChain(datadir, callback) {
|
||||
// No specific configuration needed for the dev chain
|
||||
return callback();
|
||||
}
|
||||
|
||||
mainCommand(address, done) {
|
||||
let self = this;
|
||||
let config = this.config;
|
||||
let rpc_api = (this.config.rpcApi || ['eth', 'web3', 'net', 'debug']);
|
||||
|
||||
let defaultWsApi = ['eth', 'web3', 'net', 'shh', 'debug'];
|
||||
if (this.isDev) {
|
||||
defaultWsApi.push('personal');
|
||||
}
|
||||
|
||||
let ws_api = (this.config.wsApi || defaultWsApi);
|
||||
|
||||
let rpc_api = this.config.rpcApi;
|
||||
let ws_api = this.config.wsApi;
|
||||
let args = [];
|
||||
|
||||
async.series([
|
||||
function commonOptions(callback) {
|
||||
let cmd = self.commonOptions();
|
||||
@ -205,13 +270,18 @@ class GethCommands {
|
||||
callback(null, '--wsapi=' + ws_api.join(','));
|
||||
},
|
||||
function accountToUnlock(callback) {
|
||||
if (self.isDev && self.config.unlockAddressList) {
|
||||
// The first address is the dev account, that is automatically unlocked by the client using blank password
|
||||
args.push("--unlock=" + self.config.unlockAddressList.slice(1));
|
||||
return callback(null, "--unlock=" + self.config.unlockAddressList.slice(1));
|
||||
}
|
||||
let accountAddress = "";
|
||||
if(config.account && config.account.address) {
|
||||
if (config.account && config.account.address) {
|
||||
accountAddress = config.account.address;
|
||||
} else {
|
||||
accountAddress = address;
|
||||
}
|
||||
if (accountAddress && !self.isDev) {
|
||||
if (accountAddress) {
|
||||
args.push("--unlock=" + accountAddress);
|
||||
return callback(null, "--unlock=" + accountAddress);
|
||||
}
|
||||
@ -219,8 +289,8 @@ class GethCommands {
|
||||
},
|
||||
function gasLimit(callback) {
|
||||
if (config.targetGasLimit) {
|
||||
args.push("--targetgaslimit=" + config.targetGasLimit);
|
||||
return callback(null, "--targetgaslimit=" + config.targetGasLimit);
|
||||
args.push("--miner.gastarget=" + config.targetGasLimit);
|
||||
return callback(null, "--miner.gastarget=" + config.targetGasLimit);
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
@ -231,13 +301,13 @@ class GethCommands {
|
||||
}
|
||||
callback(null, '');
|
||||
}
|
||||
], function (err) {
|
||||
], function(err) {
|
||||
if (err) {
|
||||
throw new Error(err.message);
|
||||
}
|
||||
return done(self.geth_bin, args);
|
||||
return done(self.bin, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GethCommands;
|
||||
module.exports = GethClient;
|
@ -14,6 +14,7 @@ class BlockchainModule {
|
||||
this.locale = options.locale;
|
||||
this.isDev = options.isDev;
|
||||
this.ipc = options.ipc;
|
||||
this.client = options.client;
|
||||
|
||||
this.registerBlockchainProcess();
|
||||
}
|
||||
@ -87,7 +88,7 @@ class BlockchainModule {
|
||||
const {host, port, type, protocol} = self.contractsConfig.deployment;
|
||||
utils.pingEndpoint(host, port, type, protocol, self.blockchainConfig.wsOrigins.split(',')[0], next);
|
||||
}
|
||||
], function (err) {
|
||||
], function(err) {
|
||||
if (err === true || err === undefined) {
|
||||
return cb(true);
|
||||
}
|
||||
@ -97,13 +98,15 @@ class BlockchainModule {
|
||||
|
||||
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
|
||||
isDev: self.isDev,
|
||||
client: self.client
|
||||
});
|
||||
|
||||
blockchainProcess.startBlockchainNode();
|
||||
|
345
lib/modules/blockchain_process/parityClient.js
Normal file
345
lib/modules/blockchain_process/parityClient.js
Normal file
@ -0,0 +1,345 @@
|
||||
const async = require('async');
|
||||
const fs = require('../../core/fs.js');
|
||||
const os = require('os');
|
||||
|
||||
const DEFAULTS = {
|
||||
"BIN": "parity",
|
||||
"NETWORK_TYPE": "dev",
|
||||
"NETWORK_ID": 17,
|
||||
"RPC_API": ["web3", "eth", "pubsub", "net", "parity", "private", "parity_pubsub", "traces", "rpc", "shh", "shh_pubsub"],
|
||||
"WS_API": ["web3", "eth", "pubsub", "net", "parity", "private", "parity_pubsub", "traces", "rpc", "shh", "shh_pubsub"],
|
||||
"DEV_WS_API": ["web3", "eth", "pubsub", "net", "parity", "private", "parity_pubsub", "traces", "rpc", "shh", "shh_pubsub", "personal"],
|
||||
"TARGET_GAS_LIMIT": 8000000,
|
||||
"DEV_ACCOUNT": "0x00a329c0648769a73afac7f9381e08fb43dbea72",
|
||||
"DEV_WALLET": {"id": "d9460e00-6895-8f58-f40c-bb57aebe6c00", "version": 3, "crypto": {"cipher": "aes-128-ctr", "cipherparams": {"iv": "74245f453143f9d06a095c6e6e309d5d"}, "ciphertext": "2fa611c4aa66452ef81bd1bd288f9d1ed14edf61aa68fc518093f97c791cf719", "kdf": "pbkdf2", "kdfparams": {"c": 10240, "dklen": 32, "prf": "hmac-sha256", "salt": "73b74e437a1144eb9a775e196f450a23ab415ce2c17083c225ddbb725f279b98"}, "mac": "f5882ae121e4597bd133136bf15dcbcc1bb2417a25ad205041a50c59def812a8"}, "address": "00a329c0648769a73afac7f9381e08fb43dbea72", "name": "Development Account", "meta": "{\"description\":\"Never use this account outside of development chain!\",\"passwordHint\":\"Password is empty string\"}"}
|
||||
};
|
||||
|
||||
const safePush = function(set, value) {
|
||||
if (set.indexOf(value) === -1) {
|
||||
set.push(value);
|
||||
}
|
||||
};
|
||||
|
||||
class ParityClient {
|
||||
|
||||
static get DEFAULTS() {
|
||||
return DEFAULTS;
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
this.config = options && options.hasOwnProperty('config') ? options.config : {};
|
||||
this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
|
||||
this.isDev = options && options.hasOwnProperty('isDev') ? options.isDev : (this.env === 'development');
|
||||
this.name = "parity";
|
||||
this.prettyName = "Parity-Ethereum (https://github.com/paritytech/parity-ethereum)";
|
||||
this.bin = this.config.ethereumClientBin || DEFAULTS.BIN;
|
||||
}
|
||||
|
||||
isReady(data) {
|
||||
return data.indexOf('Public node URL') > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the client needs some sort of 'keep alive' transactions to avoid freezing by inactivity
|
||||
* @returns {boolean} if keep alive is needed
|
||||
*/
|
||||
needKeepAlive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
commonOptions() {
|
||||
let config = this.config;
|
||||
let cmd = [];
|
||||
|
||||
cmd.push(this.determineNetworkType(config));
|
||||
|
||||
if (config.networkId) {
|
||||
cmd.push(`--network-id=${config.networkId}`);
|
||||
}
|
||||
|
||||
if (config.datadir) {
|
||||
cmd.push(`--base-path=${config.datadir}`);
|
||||
}
|
||||
|
||||
if (config.syncMode === 'light') {
|
||||
cmd.push("--light");
|
||||
} else if (config.syncMode === 'fast') {
|
||||
cmd.push("--pruning=fast");
|
||||
} else if (config.syncMode === 'full') {
|
||||
cmd.push("--pruning=archive");
|
||||
}
|
||||
|
||||
// In dev mode we store all users passwords in the devPassword file, so Parity can unlock all users from the start
|
||||
if (this.isDev) cmd.push(`--password=${config.account.devPassword}`);
|
||||
else if (config.account && config.account.password) {
|
||||
cmd.push(`--password=${config.account.password}`);
|
||||
}
|
||||
|
||||
if (Number.isInteger(config.verbosity) && config.verbosity >= 0 && config.verbosity <= 5) {
|
||||
switch (config.verbosity) {
|
||||
case 0: // No option to silent Parity, go to less verbose
|
||||
case 1:
|
||||
cmd.push("--logging=error");
|
||||
break;
|
||||
case 2:
|
||||
cmd.push("--logging=warn");
|
||||
break;
|
||||
case 3:
|
||||
cmd.push("--logging=info");
|
||||
break;
|
||||
case 4: // Debug is the max verbosity for Parity
|
||||
case 5:
|
||||
cmd.push("--logging=debug");
|
||||
break;
|
||||
default:
|
||||
cmd.push("--logging=info");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
getMiner() {
|
||||
console.warn(__("Miner requested, but Parity does not embed a miner! Use Geth or install ethminer (https://github.com/ethereum-mining/ethminer)").yellow);
|
||||
return;
|
||||
}
|
||||
|
||||
getBinaryPath() {
|
||||
return this.bin;
|
||||
}
|
||||
|
||||
determineVersionCommand() {
|
||||
return this.bin + " --version";
|
||||
}
|
||||
|
||||
determineNetworkType(config) {
|
||||
if (this.isDev) {
|
||||
return "--chain=dev";
|
||||
}
|
||||
if (config.networkType === 'rinkeby') {
|
||||
console.warn(__('Parity does not support the Rinkeby PoA network, switching to Kovan PoA network'));
|
||||
config.networkType = 'kovan';
|
||||
} else if (config.networkType === 'testnet') {
|
||||
console.warn(__('Parity "testnet" corresponds to Kovan network, switching to Ropsten to be compliant with Geth parameters'));
|
||||
config.networkType = "ropsten";
|
||||
}
|
||||
if (config.genesisBlock) {
|
||||
config.networkType = config.genesisBlock;
|
||||
}
|
||||
return "--chain=" + config.networkType;
|
||||
}
|
||||
|
||||
newAccountCommand() {
|
||||
return this.bin + " " + this.commonOptions().join(' ') + " account new ";
|
||||
}
|
||||
|
||||
parseNewAccountCommandResultToAddress(data = "") {
|
||||
return data.replace(/^\n|\n$/g, "");
|
||||
}
|
||||
|
||||
listAccountsCommand() {
|
||||
return this.bin + " " + this.commonOptions().join(' ') + " account list ";
|
||||
}
|
||||
|
||||
parseListAccountsCommandResultToAddress(data = "") {
|
||||
return data.replace(/^\n|\n$/g, "").split('\n')[0];
|
||||
}
|
||||
|
||||
parseListAccountsCommandResultToAddressList(data = "") {
|
||||
let list = data.split(os.EOL);
|
||||
list.pop();
|
||||
return list;
|
||||
}
|
||||
|
||||
parseListAccountsCommandResultToAddressCount(data = "") {
|
||||
const count = this.parseListAccountsCommandResultToAddressList(data).length;
|
||||
return (count > 0 ? count : 0);
|
||||
}
|
||||
|
||||
determineRpcOptions(config) {
|
||||
let cmd = [];
|
||||
cmd.push("--port=" + config.port);
|
||||
cmd.push("--jsonrpc-port=" + config.rpcPort);
|
||||
cmd.push("--jsonrpc-interface=" + (config.rpcHost === 'localhost' ? 'local' : config.rpcHost));
|
||||
if (config.rpcCorsDomain) {
|
||||
if (config.rpcCorsDomain === '*') {
|
||||
console.warn('==================================');
|
||||
console.warn(__('rpcCorsDomain set to "all"'));
|
||||
console.warn(__('make sure you know what you are doing'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
cmd.push("--jsonrpc-cors=" + (config.rpcCorsDomain === '*' ? 'all' : config.rpcCorsDomain));
|
||||
} else {
|
||||
console.warn('==================================');
|
||||
console.warn(__('warning: cors is not set'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
cmd.push("--jsonrpc-hosts=all");
|
||||
return cmd;
|
||||
}
|
||||
|
||||
determineWsOptions(config) {
|
||||
let cmd = [];
|
||||
if (config.wsRPC) {
|
||||
cmd.push("--ws-port=" + config.wsPort);
|
||||
cmd.push("--ws-interface=" + (config.wsHost === 'localhost' ? 'local' : config.wsHost));
|
||||
if (config.wsOrigins) {
|
||||
if (config.wsOrigins === '*') {
|
||||
console.warn('==================================');
|
||||
console.warn(__('wsOrigins set to "all"'));
|
||||
console.warn(__('make sure you know what you are doing'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
cmd.push("--ws-origins=" + (config.wsOrigins === '*' ? 'all' : config.wsOrigins));
|
||||
} else {
|
||||
console.warn('==================================');
|
||||
console.warn(__('warning: wsOrigins is not set'));
|
||||
console.warn('==================================');
|
||||
}
|
||||
cmd.push("--ws-hosts=all");
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
initDevChain(datadir, callback) {
|
||||
// Parity requires specific initialization also for the dev chain
|
||||
const self = this;
|
||||
const keysDataDir = '.embark/development/datadir/keys/DevelopmentChain';
|
||||
async.series([
|
||||
function makeDir(next) {
|
||||
fs.mkdirp(keysDataDir, (err, _result) => {
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function createDevAccount(next) {
|
||||
self.createDevAccount(keysDataDir, next);
|
||||
},
|
||||
function updatePasswordFile(next) {
|
||||
if (self.config.account.password) {
|
||||
let passwordList = os.EOL + (self.config.account.password ? fs.readFileSync(fs.dappPath(self.config.account.password), 'utf8').replace('\n', '') : 'dev_password');
|
||||
fs.writeFileSync(self.config.account.devPassword, passwordList, function(err) {
|
||||
return next(err);
|
||||
});
|
||||
}
|
||||
next();
|
||||
}
|
||||
], (err) => {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
createDevAccount(keysDataDir, cb) {
|
||||
const devAccountWallet = keysDataDir + '/dev.wallet';
|
||||
fs.writeFile(devAccountWallet, JSON.stringify(DEFAULTS.DEV_WALLET), function(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
mainCommand(address, done) {
|
||||
let self = this;
|
||||
let config = this.config;
|
||||
let rpc_api = this.config.rpcApi;
|
||||
let ws_api = this.config.wsApi;
|
||||
let args = [];
|
||||
async.series([
|
||||
function commonOptions(callback) {
|
||||
let cmd = self.commonOptions();
|
||||
args = args.concat(cmd);
|
||||
callback(null, cmd);
|
||||
},
|
||||
function rpcOptions(callback) {
|
||||
let cmd = self.determineRpcOptions(self.config);
|
||||
args = args.concat(cmd);
|
||||
callback(null, cmd);
|
||||
},
|
||||
function wsOptions(callback) {
|
||||
let cmd = self.determineWsOptions(self.config);
|
||||
args = args.concat(cmd);
|
||||
callback(null, cmd);
|
||||
},
|
||||
function dontGetPeers(callback) {
|
||||
if (config.nodiscover) {
|
||||
args.push("--no-discovery");
|
||||
return callback(null, "--no-discovery");
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
function vmDebug(callback) {
|
||||
if (config.vmdebug) {
|
||||
args.push("--tracing on");
|
||||
return callback(null, "--tracing on");
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
function maxPeers(callback) {
|
||||
let cmd = "--max-peers=" + config.maxpeers;
|
||||
args.push(cmd);
|
||||
callback(null, cmd);
|
||||
},
|
||||
function bootnodes(callback) {
|
||||
if (config.bootnodes && config.bootnodes !== "" && config.bootnodes !== []) {
|
||||
args.push("--bootnodes=" + config.bootnodes);
|
||||
return callback(null, "--bootnodes=" + config.bootnodes);
|
||||
}
|
||||
callback("");
|
||||
},
|
||||
function whisper(callback) {
|
||||
if (config.whisper) {
|
||||
safePush(rpc_api, 'shh');
|
||||
safePush(rpc_api, 'shh_pubsub');
|
||||
safePush(ws_api, 'shh');
|
||||
safePush(ws_api, 'shh_pubsub');
|
||||
args.push("--whisper");
|
||||
return callback(null, "--whisper");
|
||||
}
|
||||
callback("");
|
||||
},
|
||||
function rpcApi(callback) {
|
||||
args.push('--jsonrpc-apis=' + rpc_api.join(','));
|
||||
callback(null, '--jsonrpc-apis=' + rpc_api.join(','));
|
||||
},
|
||||
function wsApi(callback) {
|
||||
args.push('--ws-apis=' + ws_api.join(','));
|
||||
callback(null, '--ws-apis=' + ws_api.join(','));
|
||||
},
|
||||
function accountToUnlock(callback) {
|
||||
if (self.isDev) {
|
||||
let unlockAddressList = self.config.unlockAddressList ? self.config.unlockAddressList : DEFAULTS.DEV_ACCOUNT;
|
||||
args.push("--unlock=" + unlockAddressList);
|
||||
return callback(null, "--unlock=" + unlockAddressList);
|
||||
}
|
||||
let accountAddress = "";
|
||||
if (config.account && config.account.address) {
|
||||
accountAddress = config.account.address;
|
||||
} else {
|
||||
accountAddress = address;
|
||||
}
|
||||
if (accountAddress && !self.isDev) {
|
||||
args.push("--unlock=" + accountAddress);
|
||||
return callback(null, "--unlock=" + accountAddress);
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
function gasLimit(callback) {
|
||||
if (config.targetGasLimit) {
|
||||
args.push("--gas-floor-target=" + config.targetGasLimit);
|
||||
return callback(null, "--gas-floor-target=" + config.targetGasLimit);
|
||||
}
|
||||
// Default Parity gas limit is 4700000: let's set to the geth default
|
||||
args.push("--gas-floor-target=" + DEFAULTS.TARGET_GAS_LIMIT);
|
||||
return callback(null, "--gas-floor-target=" + DEFAULTS.TARGET_GAS_LIMIT);
|
||||
}
|
||||
], function(err) {
|
||||
if (err) {
|
||||
throw new Error(err.message);
|
||||
}
|
||||
return done(self.bin, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ParityClient;
|
@ -26,20 +26,42 @@ class Whisper {
|
||||
connectToProvider() {
|
||||
let {host, port} = this.communicationConfig.connection;
|
||||
let web3Endpoint = 'ws://' + host + ':' + port;
|
||||
this.web3.setProvider(new Web3.providers.WebsocketProvider(web3Endpoint, {headers: {Origin: "embark"}}));
|
||||
// Note: dont't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
||||
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
||||
// Moreover, Parity reject origins that are not urls so if you try to connect with Origin: "embark" it gives the followin error:
|
||||
// << Blocked connection to WebSockets server from untrusted origin: Some("embark") >>
|
||||
// The best choice is to use void origin, BUT Geth rejects void origin, so to keep both clients happy we can use http://embark
|
||||
this.web3.setProvider(new Web3.providers.WebsocketProvider(web3Endpoint, {headers: {Origin: "http://embark"}}));
|
||||
}
|
||||
|
||||
setServiceCheck() {
|
||||
const self = this;
|
||||
self.events.request("services:register", 'Whisper', function (cb) {
|
||||
self.events.request("services:register", 'Whisper', function(cb) {
|
||||
if (!self.web3.currentProvider || self.web3.currentProvider.connection.readyState !== 1) {
|
||||
return self.connectToProvider();
|
||||
}
|
||||
self.web3.shh.getVersion(function (err, version) {
|
||||
if (err || version == "2") {
|
||||
return cb({name: 'Whisper', status: 'off'});
|
||||
}
|
||||
return cb({name: 'Whisper (version ' + version + ')', status: 'on'});
|
||||
// 1) Parity does not implement shh_version JSON-RPC method
|
||||
// 2) web3 1.0 still does not implement web3_clientVersion
|
||||
// so we must do all by our own
|
||||
self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, clientVersion) => {
|
||||
if (err) return cb(err);
|
||||
if (clientVersion.indexOf("Parity-Ethereum//v2") === 0) {
|
||||
// This is Parity
|
||||
return self.web3.shh.getInfo(function(err) {
|
||||
if (err) {
|
||||
return cb({name: 'Whisper', status: 'off'});
|
||||
}
|
||||
// TOFIX Assume Whisper v6 until there's a way to understand it via JSON-RPC
|
||||
return cb({name: 'Whisper (version 6)', status: 'on'});
|
||||
});
|
||||
}
|
||||
// Assume it is a Geth compliant client
|
||||
self.web3.shh.getVersion(function(err, version) {
|
||||
if (err || version == "2") {
|
||||
return cb({name: 'Whisper', status: 'off'});
|
||||
}
|
||||
return cb({name: 'Whisper (version ' + version + ')', status: 'on'});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -85,7 +107,7 @@ class Whisper {
|
||||
const code = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(config)});`;
|
||||
this.embark.addProviderInit('communication', code, shouldInit);
|
||||
|
||||
const consoleConfig = Object.assign({}, config, {providerOptions: {headers: {Origin: "embark"}}});
|
||||
const consoleConfig = Object.assign({}, config, {providerOptions: {headers: {Origin: "http://embark"}}});
|
||||
const consoleCode = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(consoleConfig)});`;
|
||||
this.embark.addConsoleProviderInit('communication', consoleCode, shouldInit);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// for the whisper v5 and web3.js 1.0
|
||||
let __embarkWhisperNewWeb3 = {};
|
||||
|
||||
__embarkWhisperNewWeb3.setProvider = function (options) {
|
||||
__embarkWhisperNewWeb3.setProvider = function(options) {
|
||||
const self = this;
|
||||
let provider;
|
||||
if (options === undefined) {
|
||||
@ -14,7 +14,7 @@ __embarkWhisperNewWeb3.setProvider = function (options) {
|
||||
// TODO: take into account type
|
||||
self.web3 = new Web3(new Web3.providers.WebsocketProvider("ws://" + provider, options.providerOptions));
|
||||
self.web3.currentProvider.on('connect', () => {
|
||||
self.getWhisperVersion(function (err, version) {
|
||||
self.getWhisperVersion(function(err, version) {
|
||||
if (err) {
|
||||
console.log("whisper not available");
|
||||
} else if (version >= 5) {
|
||||
@ -35,7 +35,7 @@ __embarkWhisperNewWeb3.setProvider = function (options) {
|
||||
});
|
||||
};
|
||||
|
||||
__embarkWhisperNewWeb3.sendMessage = function (options) {
|
||||
__embarkWhisperNewWeb3.sendMessage = function(options) {
|
||||
var topics, data, ttl, payload;
|
||||
topics = options.topic;
|
||||
data = options.data || options.payload;
|
||||
@ -67,7 +67,7 @@ __embarkWhisperNewWeb3.sendMessage = function (options) {
|
||||
|
||||
if (options.pubKey) {
|
||||
message.pubKey = options.pubKey; // encrypt using a given pubKey
|
||||
} else if(options.symKeyID) {
|
||||
} else if (options.symKeyID) {
|
||||
message.symKeyID = options.symKeyID; // encrypts using given sym key ID
|
||||
} else {
|
||||
message.symKeyID = this.symKeyID; // encrypts using the sym key ID
|
||||
@ -77,18 +77,18 @@ __embarkWhisperNewWeb3.sendMessage = function (options) {
|
||||
throw new Error("missing option: topic");
|
||||
}
|
||||
|
||||
this.web3.shh.post(message, function () {
|
||||
this.web3.shh.post(message, function() {
|
||||
});
|
||||
};
|
||||
|
||||
__embarkWhisperNewWeb3.listenTo = function (options, callback) {
|
||||
__embarkWhisperNewWeb3.listenTo = function(options, callback) {
|
||||
var topics = options.topic;
|
||||
|
||||
let promise = new __MessageEvents();
|
||||
|
||||
let subOptions = {};
|
||||
|
||||
if(topics){
|
||||
if (topics) {
|
||||
if (typeof topics === 'string') {
|
||||
topics = [this.web3.utils.toHex(topics).slice(0, 10)];
|
||||
} else {
|
||||
@ -116,34 +116,53 @@ __embarkWhisperNewWeb3.listenTo = function (options, callback) {
|
||||
}
|
||||
|
||||
let filter = this.web3.shh.subscribe("messages", subOptions)
|
||||
.on('data', function (result) {
|
||||
var payload = JSON.parse(EmbarkJS.Utils.toAscii(result.payload));
|
||||
var data;
|
||||
data = {
|
||||
topic: EmbarkJS.Utils.toAscii(result.topic),
|
||||
data: payload,
|
||||
//from: result.from,
|
||||
time: result.timestamp
|
||||
};
|
||||
.on('data', function(result) {
|
||||
var payload = JSON.parse(EmbarkJS.Utils.toAscii(result.payload));
|
||||
var data;
|
||||
data = {
|
||||
topic: EmbarkJS.Utils.toAscii(result.topic),
|
||||
data: payload,
|
||||
//from: result.from,
|
||||
time: result.timestamp
|
||||
};
|
||||
|
||||
if (callback) {
|
||||
return callback(null, data);
|
||||
}
|
||||
promise.cb(payload, data, result);
|
||||
});
|
||||
if (callback) {
|
||||
return callback(null, data);
|
||||
}
|
||||
promise.cb(payload, data, result);
|
||||
});
|
||||
|
||||
promise.filter = filter;
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
__embarkWhisperNewWeb3.getWhisperVersion = function (cb) {
|
||||
this.web3.shh.getVersion(function (err, version) {
|
||||
cb(err, version);
|
||||
__embarkWhisperNewWeb3.getWhisperVersion = function(cb) {
|
||||
// 1) Parity does not implement shh_version JSON-RPC method
|
||||
// 2) web3 1.0 still does not implement web3_clientVersion
|
||||
// so we must do all by our own
|
||||
const self = this;
|
||||
self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, clientVersion) => {
|
||||
if (err) return cb(err);
|
||||
if (clientVersion.indexOf("Parity-Ethereum//v2") === 0) {
|
||||
// This is Parity
|
||||
self.web3.shh.getInfo(function(err) {
|
||||
if (err) {
|
||||
return cb(err, 0);
|
||||
}
|
||||
// TOFIX Assume Whisper v6 until there's a way to understand it via JSON-RPC
|
||||
return cb(err, 6);
|
||||
});
|
||||
} else {
|
||||
// Assume it is a Geth compliant client
|
||||
self.web3.shh.getVersion(function(err, version) {
|
||||
cb(err, version);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
__embarkWhisperNewWeb3.isAvailable = function () {
|
||||
__embarkWhisperNewWeb3.isAvailable = function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.web3.shh) {
|
||||
return resolve(false);
|
||||
|
@ -14,7 +14,9 @@
|
||||
"no colors in case it's needed for compatbility purposes": "no colors in case it's needed for compatbility purposes",
|
||||
"filename to output logs (default: %s)": "filename to output logs (default: %s)",
|
||||
"run dapp (default: %s)": "run dapp (default: %s)",
|
||||
"Use a specific ethereum client or simulator (supported: %s)": "Use a specific ethereum client or simulator (supported: %s)",
|
||||
"Use a specific ethereum client [%s] (default: %s)": "Use a specific ethereum client [%s] (default: %s)",
|
||||
"Unknow client \"%s\". Please use one of the following: %s": "Unknow client \"%s\". Please use one of the following: %s",
|
||||
"Miner requested, but Parity does not embed a miner! Use Geth or install ethminer (https://github.com/ethereum-mining/ethminer)":"Miner requested, but Parity does not embed a miner! Use Geth or install ethminer (https://github.com/ethereum-mining/ethminer)",
|
||||
"run blockchain server (default: %s)": "run blockchain server (default: %s)",
|
||||
"run a fast ethereum rpc simulator": "run a fast ethereum rpc simulator",
|
||||
"use testrpc as the rpc simulator [%s]": "use testrpc as the rpc simulator [%s]",
|
||||
@ -123,7 +125,6 @@
|
||||
"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?",
|
||||
"Error while downloading the file": "Error while downloading the file",
|
||||
"Error while loading the content of ": "Error while loading the content of ",
|
||||
"Installing packages...": "Installing packages...",
|
||||
@ -144,6 +145,7 @@
|
||||
"DApp path length is too long: ": "DApp path length is too long: ",
|
||||
"WARNING! DApp path length is too long: ": "WARNING! DApp path length is too long: ",
|
||||
"This is known to cause issues with starting geth, please consider reducing your DApp path's length to 66 characters or less.": "This is known to cause issues with starting geth, please consider reducing your DApp path's length to 66 characters or less.",
|
||||
"Ethereum client bin not found:":"Ethereum client bin not found:",
|
||||
"%s is not installed on your machine": "%s is not installed on your machine",
|
||||
"You can install it by visiting: %s": "You can install it by visiting: %s",
|
||||
"Starting ipfs process": "Starting ipfs process",
|
||||
|
@ -76,7 +76,7 @@
|
||||
"unknown command": "comando desconocido",
|
||||
"did you mean": "quiso decir",
|
||||
"warning: running default config on a non-development environment": "precaución: ejecutando la configuración predeterminada en un ambiente de no-desarrollo",
|
||||
"could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?": "no se pudo encontrar el comando {{geth_bin}}; ¿Se encuentra {{client_name}} instalado o en la ruta (PATH)?",
|
||||
"Ethereum client bin not found:":"Ethereum client bin not found:",
|
||||
"no accounts found": "no se encontraron cuentas",
|
||||
"initializing genesis block": "inicializando bloque genesis",
|
||||
"rpcCorsDomain set to *": "rpcCorsDomain definido como *",
|
||||
|
@ -18,14 +18,14 @@
|
||||
"filename to output logs (default: none)": "nom de fichier pour les journaux de sortie (par défaut: aucun)",
|
||||
"level of logging to display": "niveau de journalisation à afficher",
|
||||
"deploy and build dapp at ": "Publiez et créez la dapp dans ",
|
||||
"port to run the dev webserver (default: %s)": "port pour exécuter le serveur de développement Web (par défaut:% s)",
|
||||
"host to run the dev webserver (default: %s)": "hôte pour exécuter le serveur de développement Web (par défaut:% s)",
|
||||
"port to run the dev webserver (default: %s)": "port pour exécuter le serveur de développement Web (par défaut: %s)",
|
||||
"host to run the dev webserver (default: %s)": "hôte pour exécuter le serveur de développement Web (par défaut: %s)",
|
||||
"disable the development webserver": "désactiver le serveur de développement Web",
|
||||
"simple mode, disables the dashboard": "mode simple, désactive le tableau de bord",
|
||||
"no colors in case it's needed for compatbility purposes": "pas de couleur au cas où cela serait nécessaire à des fins de compatibilité",
|
||||
"filename to output logs (default: %s)": "nom de fichier pour les journaux de sortie (par défaut: %s)",
|
||||
"run dapp (default: %s)": "lancer la dapp (par défaut: %s)",
|
||||
"Use a specific ethereum client or simulator (supported: %s)": "Utiliser un client ou simulateur ethereum spécifique (supporté:% s)",
|
||||
"Use a specific ethereum client [%s] (default: %s)": "Utiliser un client ethereum spécifique [%s] (supporté: %s)",
|
||||
"run blockchain server (default: %s)": "exécuter le serveur blockchain (par défaut: %s)",
|
||||
"run a fast ethereum rpc simulator": "exécuter un simulateur ethereum RPC rapide",
|
||||
"use testrpc as the rpc simulator [%s]": "utiliser testrpc comme simulateur RPC [%s]",
|
||||
@ -76,7 +76,7 @@
|
||||
"unknown command": "commande inconnue",
|
||||
"did you mean": "vouliez-vous dire",
|
||||
"warning: running default config on a non-development environment": "avertissement: exécution de la configuration par défaut sur un environnement de non-développement",
|
||||
"could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?": "Impossible de trouver la commande {{geth_bin}}, est-ce que {{client_name}} est installé ou dans le PATH?",
|
||||
"Ethereum client bin not found:":"Ethereum client bin not found:",
|
||||
"no accounts found": "Aucun compte trouvé",
|
||||
"initializing genesis block": "initialisation du bloc de genèse",
|
||||
"rpcCorsDomain set to *": "rpcCorsDomain défini sur *",
|
||||
|
@ -25,7 +25,7 @@
|
||||
"no colors in case it's needed for compatbility purposes": "sem cores, em caso seja necessario para compabitilidade com a terminal",
|
||||
"filename to output logs (default: %s)": "ficheiro/arquivo para os logs (predefinido: %s)",
|
||||
"run dapp (default: %s)": "executa a dapp (applicacao decentralizada) (predefinido: %s)",
|
||||
"Use a specific ethereum client or simulator (supported: %s)": "Usa um cliente ou simulador de ethereum específico (supportado: %s)",
|
||||
"Use a specific ethereum client [%s] (default: %s)": "Usa um cliente de ethereum específico [%s] (supportado: %s)",
|
||||
"run blockchain server (default: %s)": "executa un node de blockchain (predefinido: %s)",
|
||||
"run a fast ethereum rpc simulator": "executa um simulador RPC de ethereum",
|
||||
"use testrpc as the rpc simulator [%s]": "usa testrpc como simulator de rpc [%s]",
|
||||
@ -76,7 +76,7 @@
|
||||
"unknown command": "comando desconhecido",
|
||||
"did you mean": "você quis dizer",
|
||||
"warning: running default config on a non-development environment": "aviso: executando a configuração padrão em um ambiente de não desenvolvimento",
|
||||
"could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?": "não foi possível encontrar o comando {{geth_bin}}; o {{client_name}} instalado ou no PATH?",
|
||||
"Ethereum client bin not found:":"Ethereum client bin not found:",
|
||||
"no accounts found": "nenhuma conta encontrada",
|
||||
"initializing genesis block": "inicializando o bloco de gênese",
|
||||
"rpcCorsDomain set to *": "rpcCorsDomain definido como *",
|
||||
|
16
npm-shrinkwrap.json
generated
16
npm-shrinkwrap.json
generated
@ -15327,6 +15327,22 @@
|
||||
"write-file-atomic": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.0.0.tgz",
|
||||
"integrity": "sha1-mN2wAFbIOQy3Ued4h4hJf5kQO2w=",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.0.1",
|
||||
"ultron": "~1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
||||
"integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
|
||||
|
@ -16,10 +16,12 @@ module.exports = {
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run` and `embark blockchain`
|
||||
development: {
|
||||
ethereumClientName: "geth", // Can be geth or parity (default:geth)
|
||||
//ethereumClientBin: "geth", // path to the client binary. Useful if it is not in the global PATH
|
||||
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
|
||||
networkId: "1337", // Network id used when networkType is custom
|
||||
networkId: 1337, // Network id used when networkType is custom
|
||||
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
|
||||
datadir: ".embark/development/datadir", // Data directory for the databases and keystore
|
||||
datadir: ".embark/development/datadir", // Data directory for the databases and keystore (Geth 1.8.15 and Parity 2.0.4 can use the same base folder, till now they does not conflict with each other)
|
||||
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
|
||||
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
|
||||
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
|
||||
@ -30,7 +32,8 @@ module.exports = {
|
||||
account: {
|
||||
// numAccounts: 3, // When specified, creates accounts for use in the dapp. This option only works in the development environment, and can be used as a quick start option that bypasses the need for MetaMask in development. These accounts are unlocked and funded with the below settings.
|
||||
// password: "config/development/password", // Password for the created accounts (as specified in the `numAccounts` setting). If `mineWhenNeeded` is enabled (and isDev is not), this password is used to create a development account controlled by the node.
|
||||
// balance: "5 ether" // Balance to be given to the created accounts (as specified in the `numAccounts` setting)
|
||||
// balance: "5 ether", // Balance to be given to the created accounts (as specified in the `numAccounts` setting)
|
||||
devPassword: "config/development/devpassword" // [Parity-only] File with a void line to unlock the Parity dev account
|
||||
}
|
||||
},
|
||||
|
||||
@ -38,7 +41,7 @@ module.exports = {
|
||||
// used with "embark run privatenet" and/or "embark blockchain privatenet"
|
||||
privatenet: {
|
||||
networkType: "custom",
|
||||
networkId: "1337",
|
||||
networkId: 1337,
|
||||
isDev: false,
|
||||
datadir: ".embark/privatenet/datadir",
|
||||
// -- mineWhenNeeded --
|
||||
@ -60,8 +63,28 @@ module.exports = {
|
||||
maxpeers: 0,
|
||||
proxy: true,
|
||||
account: {
|
||||
// "address": "", // When specified, uses that address instead of the default one for the network
|
||||
password: "config/privatenet/password" // Password to unlock the account. If `mineWhenNeeded` is enabled (and isDev is not), this password is used to create a development account controlled by the node.
|
||||
// address: "", // When specified, uses that address instead of the default one for the network
|
||||
password: "config/privatenet/password" // Password to unlock the account
|
||||
},
|
||||
targetGasLimit: 8000000,
|
||||
simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm",
|
||||
simulatorBlocktime: 0
|
||||
},
|
||||
|
||||
privateparitynet: {
|
||||
ethereumClientName: "parity",
|
||||
networkType: "custom",
|
||||
networkId: 1337,
|
||||
isDev: false,
|
||||
genesisBlock: "config/privatenet/genesis-parity.json", // Genesis block to initiate on first creation of a development node
|
||||
datadir: ".embark/privatenet/datadir",
|
||||
mineWhenNeeded: false,
|
||||
nodiscover: true,
|
||||
maxpeers: 0,
|
||||
proxy: true,
|
||||
account: {
|
||||
// address: "", // When specified, uses that address instead of the default one for the network
|
||||
password: "config/privatenet/password" // Password to unlock the account
|
||||
},
|
||||
targetGasLimit: 8000000,
|
||||
simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm",
|
||||
|
1
templates/boilerplate/config/development/devpassword
Normal file
1
templates/boilerplate/config/development/devpassword
Normal file
@ -0,0 +1 @@
|
||||
|
1
templates/boilerplate/config/development/password
Normal file
1
templates/boilerplate/config/development/password
Normal file
@ -0,0 +1 @@
|
||||
dev_password
|
147
templates/boilerplate/config/privatenet/genesis-parity.json
Normal file
147
templates/boilerplate/config/privatenet/genesis-parity.json
Normal file
File diff suppressed because one or more lines are too long
@ -16,10 +16,12 @@ module.exports = {
|
||||
// default environment, merges with the settings in default
|
||||
// assumed to be the intended environment by `embark run` and `embark blockchain`
|
||||
development: {
|
||||
ethereumClientName: "geth", // Can be geth or parity (default:geth)
|
||||
//ethereumClientBin: "geth", // path to the client binary. Useful if it is not in the global PATH
|
||||
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
|
||||
networkId: "1337", // Network id used when networkType is custom
|
||||
networkId: 1337, // Network id used when networkType is custom
|
||||
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
|
||||
datadir: ".embark/development/datadir", // Data directory for the databases and keystore
|
||||
datadir: ".embark/development/datadir", // Data directory for the databases and keystore (Geth 1.8.15 and Parity 2.0.4 can use the same base folder, till now they does not conflict with each other)
|
||||
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
|
||||
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
|
||||
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
|
||||
@ -30,7 +32,8 @@ module.exports = {
|
||||
account: {
|
||||
// numAccounts: 3, // When specified, creates accounts for use in the dapp. This option only works in the development environment, and can be used as a quick start option that bypasses the need for MetaMask in development. These accounts are unlocked and funded with the below settings.
|
||||
// password: "config/development/password", // Password for the created accounts (as specified in the `numAccounts` setting). If `mineWhenNeeded` is enabled (and isDev is not), this password is used to create a development account controlled by the node.
|
||||
// balance: "5 ether" // Balance to be given to the created accounts (as specified in the `numAccounts` setting)
|
||||
// balance: "5 ether", // Balance to be given to the created accounts (as specified in the `numAccounts` setting)
|
||||
devPassword: "config/development/devpassword" // [Parity-only] File with a void line to unlock the Parity dev account
|
||||
}
|
||||
},
|
||||
|
||||
@ -38,7 +41,7 @@ module.exports = {
|
||||
// used with "embark run privatenet" and/or "embark blockchain privatenet"
|
||||
privatenet: {
|
||||
networkType: "custom",
|
||||
networkId: "1337",
|
||||
networkId: 1337,
|
||||
isDev: false,
|
||||
datadir: ".embark/privatenet/datadir",
|
||||
// -- mineWhenNeeded --
|
||||
@ -70,6 +73,28 @@ module.exports = {
|
||||
simulatorBlocktime: 0
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run privatparityenet" and/or "embark blockchain privateparitynet"
|
||||
privateparitynet: {
|
||||
ethereumClientName: "parity",
|
||||
networkType: "custom",
|
||||
networkId: 1337,
|
||||
isDev: false,
|
||||
genesisBlock: "config/privatenet/genesis-parity.json", // Genesis block to initiate on first creation of a development node
|
||||
datadir: ".embark/privatenet/datadir", // (Geth 1.8.15 and Parity 2.0.4 can use the same base folder, till now they does not conflict with each other)
|
||||
mineWhenNeeded: false,
|
||||
nodiscover: true,
|
||||
maxpeers: 0,
|
||||
proxy: true,
|
||||
account: {
|
||||
// address: "", // When specified, uses that address instead of the default one for the network
|
||||
password: "config/privatenet/password" // Password to unlock the account
|
||||
},
|
||||
targetGasLimit: 8000000,
|
||||
simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm",
|
||||
simulatorBlocktime: 0
|
||||
},
|
||||
|
||||
// merges with the settings in default
|
||||
// used with "embark run testnet" and/or "embark blockchain testnet"
|
||||
testnet: {
|
||||
@ -90,7 +115,7 @@ module.exports = {
|
||||
account: {
|
||||
password: "config/livenet/password"
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// you can name an environment with specific settings and then specify with
|
||||
// "embark run custom_name" or "embark blockchain custom_name"
|
||||
|
1
templates/demo/config/development/devpassword
Normal file
1
templates/demo/config/development/devpassword
Normal file
@ -0,0 +1 @@
|
||||
|
1
templates/demo/config/development/password
Normal file
1
templates/demo/config/development/password
Normal file
@ -0,0 +1 @@
|
||||
dev_password
|
147
templates/demo/config/privatenet/genesis-parity.json
Normal file
147
templates/demo/config/privatenet/genesis-parity.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,30 +1,29 @@
|
||||
/*globals describe, it*/
|
||||
const Blockchain = require('../lib/modules/blockchain_process/blockchain.js');
|
||||
const Blockchain = require('../lib/modules/blockchain_process/blockchain.js');
|
||||
const constants = require('../lib/constants.json');
|
||||
const {defaultHost} = require('../lib/utils/host');
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
describe('embark.Blockchain', function () {
|
||||
//let Client = function() {};
|
||||
//Client.prototype.name = "ClientName";
|
||||
describe('embark.Blockchain', function() {
|
||||
|
||||
describe('#initializer', function () {
|
||||
//let client = new Client();
|
||||
describe('#initializer', function() {
|
||||
|
||||
describe('with empty config', function () {
|
||||
it('should have a default config', function (done) {
|
||||
let config = {
|
||||
describe('with empty config', function() {
|
||||
it('should have a default config', function(done) {
|
||||
let blockchain = new Blockchain({});
|
||||
let expectedConfig = {
|
||||
networkType: 'custom',
|
||||
genesisBlock: false,
|
||||
geth_bin: 'geth',
|
||||
ethereumClientName: 'geth',
|
||||
ethereumClientBin: 'geth',
|
||||
datadir: false,
|
||||
mineWhenNeeded: false,
|
||||
rpcHost: defaultHost,
|
||||
rpcPort: 8545,
|
||||
rpcApi: ['eth', 'web3', 'net', 'debug'],
|
||||
rpcCorsDomain: false,
|
||||
networkId: 12301,
|
||||
networkId: 1337,
|
||||
port: 30303,
|
||||
nodiscover: false,
|
||||
maxpeers: 25,
|
||||
@ -32,36 +31,35 @@ describe('embark.Blockchain', function () {
|
||||
vmdebug: false,
|
||||
whisper: true,
|
||||
account: {},
|
||||
devPassword: "",
|
||||
bootnodes: "",
|
||||
wsApi: ["eth", "web3", "net", "shh", "debug"],
|
||||
wsApi: ["eth", "web3", "net", "shh", "debug", "pubsub"],
|
||||
wsHost: defaultHost,
|
||||
wsOrigins: false,
|
||||
wsPort: 8546,
|
||||
wsRPC: true,
|
||||
targetGasLimit: false,
|
||||
syncmode: undefined,
|
||||
syncMode: undefined,
|
||||
syncmode: undefined,
|
||||
verbosity: undefined,
|
||||
proxy: true
|
||||
proxy: true,
|
||||
silent: undefined
|
||||
};
|
||||
let blockchain = new Blockchain(config, 'geth');
|
||||
// We check also proxy's ports because proxy is set to true
|
||||
expectedConfig.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
expectedConfig.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
|
||||
if(config.proxy){
|
||||
config.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
config.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
}
|
||||
assert.deepEqual(blockchain.config, config);
|
||||
assert.deepEqual(blockchain.config, expectedConfig);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with config', function () {
|
||||
it('should take config params', function (done) {
|
||||
describe('with config', function() {
|
||||
it('should take config params', function(done) {
|
||||
let config = {
|
||||
networkType: 'livenet',
|
||||
genesisBlock: 'foo/bar/genesis.json',
|
||||
geth_bin: 'geth',
|
||||
ethereumClientName: 'parity',
|
||||
ethereumClientBin: 'parity',
|
||||
datadir: '/foo/datadir/',
|
||||
mineWhenNeeded: true,
|
||||
rpcHost: defaultHost,
|
||||
@ -76,6 +74,7 @@ describe('embark.Blockchain', function () {
|
||||
vmdebug: false,
|
||||
whisper: false,
|
||||
account: {},
|
||||
devPassword: "foo/bar/devpassword",
|
||||
bootnodes: "",
|
||||
wsApi: ["eth", "web3", "net", "shh", "debug"],
|
||||
wsHost: defaultHost,
|
||||
@ -84,18 +83,48 @@ describe('embark.Blockchain', function () {
|
||||
wsRPC: true,
|
||||
targetGasLimit: false,
|
||||
syncMode: undefined,
|
||||
syncmode: undefined,
|
||||
verbosity: undefined,
|
||||
proxy: true
|
||||
};
|
||||
let blockchain = new Blockchain(config, 'geth');
|
||||
let blockchain = new Blockchain(config);
|
||||
|
||||
if(config.proxy){
|
||||
config.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
config.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
}
|
||||
let expectedConfig = {
|
||||
networkType: 'livenet',
|
||||
genesisBlock: 'foo/bar/genesis.json',
|
||||
ethereumClientName: 'parity',
|
||||
ethereumClientBin: 'parity',
|
||||
datadir: '/foo/datadir/',
|
||||
mineWhenNeeded: true,
|
||||
rpcHost: defaultHost,
|
||||
rpcPort: 12345,
|
||||
rpcApi: ['eth', 'web3', 'net', 'debug'],
|
||||
rpcCorsDomain: true,
|
||||
networkId: 1,
|
||||
port: 123456,
|
||||
nodiscover: true,
|
||||
maxpeers: 25,
|
||||
mine: true,
|
||||
vmdebug: false,
|
||||
whisper: false,
|
||||
account: {},
|
||||
devPassword: "foo/bar/devpassword",
|
||||
bootnodes: "",
|
||||
wsApi: ["eth", "web3", "net", "shh", "debug"],
|
||||
wsHost: defaultHost,
|
||||
wsOrigins: false,
|
||||
wsPort: 12346,
|
||||
wsRPC: true,
|
||||
targetGasLimit: false,
|
||||
syncMode: undefined,
|
||||
verbosity: undefined,
|
||||
proxy: true,
|
||||
silent: undefined
|
||||
};
|
||||
// We check also proxy's ports because proxy is set to true
|
||||
expectedConfig.wsPort += constants.blockchain.servicePortOnProxy;
|
||||
expectedConfig.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
|
||||
assert.deepEqual(blockchain.config, config);
|
||||
assert.deepEqual(blockchain.config, expectedConfig);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ const FakeIpcProvider = require('./helpers/fakeIpcProvider');
|
||||
const utils = require('../lib/utils/utils');
|
||||
i18n.setOrDetectLocale('en');
|
||||
|
||||
describe('embark.DevFunds', function () {
|
||||
describe('embark.DevFunds', function() {
|
||||
let config = {
|
||||
networkType: 'livenet',
|
||||
genesisBlock: 'foo/bar/genesis.json',
|
||||
@ -41,7 +41,6 @@ describe('embark.DevFunds', function () {
|
||||
wsRPC: true,
|
||||
targetGasLimit: false,
|
||||
syncMode: undefined,
|
||||
syncmode: undefined,
|
||||
verbosity: undefined,
|
||||
proxy: true
|
||||
};
|
||||
@ -51,7 +50,7 @@ describe('embark.DevFunds', function () {
|
||||
config.rpcPort += constants.blockchain.servicePortOnProxy;
|
||||
}
|
||||
|
||||
describe('#create, fund, and unlock accounts', function () {
|
||||
describe('#create, fund, and unlock accounts', function() {
|
||||
let provider = new FakeIpcProvider();
|
||||
const web3 = new Web3(provider);
|
||||
let devFunds;
|
||||
@ -61,7 +60,8 @@ describe('embark.DevFunds', function () {
|
||||
devFunds = await DevFunds.new({blockchainConfig: config, provider: provider, logger: new TestLogger({})});
|
||||
});
|
||||
|
||||
it('should create correct number of accounts', function (done) {
|
||||
// TOCHECK: DevFunds does not provide this function anymore, please consider to remove this test
|
||||
it('should create correct number of accounts', function(done) {
|
||||
provider.injectResult('0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae'); // createAccount #1
|
||||
provider.injectResult('0x22f4d0a3c12e86b4b5f39b213f7e19d048276dab'); // createAccount #2
|
||||
|
||||
@ -81,7 +81,8 @@ describe('embark.DevFunds', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should unlock accounts', function (done) {
|
||||
// TOCHECK: DevFunds does not provide this function anymore, please consider to remove this test
|
||||
it('should unlock accounts', function(done) {
|
||||
if (devFunds.accounts.length === 0) {
|
||||
assert.equal(true, true, "no accounts to unlock");
|
||||
return done();
|
||||
@ -97,7 +98,7 @@ describe('embark.DevFunds', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should fund accounts', function (done) {
|
||||
it('should fund accounts', function(done) {
|
||||
|
||||
if (devFunds.accounts.length === 0) {
|
||||
assert.equal(true, true, "no accounts to fund");
|
||||
@ -108,7 +109,7 @@ describe('embark.DevFunds', function () {
|
||||
// provider.injectResult('0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe'); // send tx response
|
||||
});
|
||||
|
||||
devFunds.fundAccounts(devFunds.balance, (errFundAccounts) => {
|
||||
devFunds.fundAccounts(false, (errFundAccounts) => {
|
||||
|
||||
assert.equal(errFundAccounts, null);
|
||||
|
||||
@ -136,7 +137,7 @@ describe('embark.DevFunds', function () {
|
||||
cb();
|
||||
}).catch(cb);
|
||||
|
||||
}, function (errAcctsBalance) {
|
||||
}, function(errAcctsBalance) {
|
||||
if (errAcctsBalance) throw errAcctsBalance;
|
||||
done();
|
||||
});
|
||||
|
128
test_apps/test_app/package-lock.json
generated
128
test_apps/test_app/package-lock.json
generated
@ -19,9 +19,9 @@
|
||||
"integrity": "sha512-5PgPDV6F5s69XNznTcP0za3qH7qgBkr9DVQTXfZtpF+3iEyuIZB1Mjxu52F5CFxgzQUQJoBYHVxtH4Itdb5MgA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "2.4.1",
|
||||
"esutils": "2.0.2",
|
||||
"js-tokens": "3.0.2"
|
||||
"chalk": "^2.0.0",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"js-tokens": {
|
||||
@ -38,7 +38,7 @@
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.2"
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"asap": {
|
||||
@ -51,8 +51,8 @@
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
|
||||
"requires": {
|
||||
"core-js": "2.5.7",
|
||||
"regenerator-runtime": "0.11.1"
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
@ -73,9 +73,9 @@
|
||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"supports-color": "5.4.0"
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
@ -111,7 +111,7 @@
|
||||
"embark-service": {
|
||||
"version": "file:extensions/embark-service",
|
||||
"requires": {
|
||||
"haml": "0.4.3"
|
||||
"haml": "^0.4.3"
|
||||
}
|
||||
},
|
||||
"encoding": {
|
||||
@ -119,7 +119,7 @@
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
|
||||
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
|
||||
"requires": {
|
||||
"iconv-lite": "0.4.23"
|
||||
"iconv-lite": "~0.4.13"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
@ -139,13 +139,13 @@
|
||||
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
|
||||
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
|
||||
"requires": {
|
||||
"core-js": "1.2.7",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"loose-envify": "1.4.0",
|
||||
"object-assign": "4.1.1",
|
||||
"promise": "7.3.1",
|
||||
"setimmediate": "1.0.5",
|
||||
"ua-parser-js": "0.7.18"
|
||||
"core-js": "^1.0.0",
|
||||
"isomorphic-fetch": "^2.1.1",
|
||||
"loose-envify": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"promise": "^7.1.1",
|
||||
"setimmediate": "^1.0.5",
|
||||
"ua-parser-js": "^0.7.18"
|
||||
}
|
||||
},
|
||||
"haml": {
|
||||
@ -164,7 +164,7 @@
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
|
||||
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
|
||||
"requires": {
|
||||
"safer-buffer": "2.1.2"
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"invariant": {
|
||||
@ -172,7 +172,7 @@
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"requires": {
|
||||
"loose-envify": "1.4.0"
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-stream": {
|
||||
@ -185,8 +185,8 @@
|
||||
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
|
||||
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
|
||||
"requires": {
|
||||
"node-fetch": "1.7.3",
|
||||
"whatwg-fetch": "2.0.4"
|
||||
"node-fetch": "^1.0.1",
|
||||
"whatwg-fetch": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
@ -209,7 +209,7 @@
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "4.0.0"
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
@ -217,8 +217,8 @@
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
|
||||
"requires": {
|
||||
"encoding": "0.1.12",
|
||||
"is-stream": "1.1.0"
|
||||
"encoding": "^0.1.11",
|
||||
"is-stream": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
@ -231,7 +231,7 @@
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"requires": {
|
||||
"asap": "2.0.6"
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
@ -239,8 +239,8 @@
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
|
||||
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
|
||||
"requires": {
|
||||
"loose-envify": "1.4.0",
|
||||
"object-assign": "4.1.1"
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"prop-types-extra": {
|
||||
@ -248,8 +248,8 @@
|
||||
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz",
|
||||
"integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==",
|
||||
"requires": {
|
||||
"react-is": "16.4.2",
|
||||
"warning": "3.0.0"
|
||||
"react-is": "^16.3.2",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
@ -257,10 +257,10 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
||||
"integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==",
|
||||
"requires": {
|
||||
"fbjs": "0.8.17",
|
||||
"loose-envify": "1.4.0",
|
||||
"object-assign": "4.1.1",
|
||||
"prop-types": "15.6.2"
|
||||
"fbjs": "^0.8.16",
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-bootstrap": {
|
||||
@ -268,18 +268,18 @@
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.32.1.tgz",
|
||||
"integrity": "sha512-RbfzKUbsukWsToWqGHfCCyMFq9QQI0TznutdyxyJw6dih2NvIne25Mrssg8LZsprqtPpyQi8bN0L0Fx3fUsL8Q==",
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
"classnames": "2.2.6",
|
||||
"dom-helpers": "3.3.1",
|
||||
"invariant": "2.2.4",
|
||||
"keycode": "2.2.0",
|
||||
"prop-types": "15.6.2",
|
||||
"prop-types-extra": "1.1.0",
|
||||
"react-overlays": "0.8.3",
|
||||
"react-prop-types": "0.4.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"uncontrollable": "4.1.0",
|
||||
"warning": "3.0.0"
|
||||
"babel-runtime": "^6.11.6",
|
||||
"classnames": "^2.2.5",
|
||||
"dom-helpers": "^3.2.0",
|
||||
"invariant": "^2.2.1",
|
||||
"keycode": "^2.1.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-overlays": "^0.8.0",
|
||||
"react-prop-types": "^0.4.0",
|
||||
"react-transition-group": "^2.0.0",
|
||||
"uncontrollable": "^4.1.0",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
@ -287,10 +287,10 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz",
|
||||
"integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==",
|
||||
"requires": {
|
||||
"fbjs": "0.8.17",
|
||||
"loose-envify": "1.4.0",
|
||||
"object-assign": "4.1.1",
|
||||
"prop-types": "15.6.2"
|
||||
"fbjs": "^0.8.16",
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
@ -308,12 +308,12 @@
|
||||
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.8.3.tgz",
|
||||
"integrity": "sha512-h6GT3jgy90PgctleP39Yu3eK1v9vaJAW73GOA/UbN9dJ7aAN4BTZD6793eI1D5U+ukMk17qiqN/wl3diK1Z5LA==",
|
||||
"requires": {
|
||||
"classnames": "2.2.6",
|
||||
"dom-helpers": "3.3.1",
|
||||
"prop-types": "15.6.2",
|
||||
"prop-types-extra": "1.1.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"warning": "3.0.0"
|
||||
"classnames": "^2.2.5",
|
||||
"dom-helpers": "^3.2.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-transition-group": "^2.2.0",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-prop-types": {
|
||||
@ -321,7 +321,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",
|
||||
"integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=",
|
||||
"requires": {
|
||||
"warning": "3.0.0"
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
@ -329,10 +329,10 @@
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz",
|
||||
"integrity": "sha512-Xv5d55NkJUxUzLCImGSanK8Cl/30sgpOEMGc5m86t8+kZwrPxPCPcFqyx83kkr+5Lz5gs6djuvE5By+gce+VjA==",
|
||||
"requires": {
|
||||
"dom-helpers": "3.3.1",
|
||||
"loose-envify": "1.4.0",
|
||||
"prop-types": "15.6.2",
|
||||
"react-lifecycles-compat": "3.0.4"
|
||||
"dom-helpers": "^3.3.1",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
@ -356,7 +356,7 @@
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "3.0.0"
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"ua-parser-js": {
|
||||
@ -369,7 +369,7 @@
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-4.1.0.tgz",
|
||||
"integrity": "sha1-4DWCkSUuGGUiLZCTmxny9J+Bwak=",
|
||||
"requires": {
|
||||
"invariant": "2.2.4"
|
||||
"invariant": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
@ -377,7 +377,7 @@
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
||||
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
|
||||
"requires": {
|
||||
"loose-envify": "1.4.0"
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user