2018-05-22 18:13:56 +00:00
const async = require ( 'async' ) ;
2018-10-06 16:05:37 +00:00
const { spawn , exec } = require ( 'child_process' ) ;
2018-05-22 18:13:56 +00:00
const fs = require ( '../../core/fs.js' ) ;
2018-06-11 20:43:08 +00:00
const constants = require ( '../../constants.json' ) ;
2018-07-24 12:29:06 +00:00
const utils = require ( '../../utils/utils.js' ) ;
2018-10-06 16:05:37 +00:00
const GethClient = require ( './gethClient.js' ) ;
const ParityClient = require ( './parityClient.js' ) ;
2018-07-13 12:56:59 +00:00
const DevFunds = require ( './dev_funds.js' ) ;
2018-10-06 16:05:37 +00:00
const proxy = require ( './proxy' ) ;
const Ipc = require ( '../../core/ipc' ) ;
2018-07-15 17:30:51 +00:00
const { defaultHost , dockerHostSwap } = require ( '../../utils/host' ) ;
2018-10-22 12:56:14 +00:00
const Logger = require ( '../../core/logger' ) ;
// time between IPC connection attmpts (in ms)
const IPC _CONNECT _INTERVAL = 2000 ;
2018-07-15 17:30:51 +00:00
2018-10-22 12:56:14 +00:00
/*eslint complexity: ["error", 38]*/
2018-10-06 16:05:37 +00:00
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 ;
2018-10-24 06:28:27 +00:00
this . logger = userConfig . logger || new Logger ( { logLevel : 'debug' , context : constants . contexts . blockchain } ) ; // do not pass in events as we don't want any log events emitted
2018-10-22 12:56:14 +00:00
this . events = userConfig . events ;
2018-09-20 05:08:02 +00:00
this . proxyIpc = null ;
2018-10-22 12:56:14 +00:00
this . isStandalone = userConfig . isStandalone ;
2017-03-31 11:34:43 +00:00
2018-10-06 16:05:37 +00:00
let defaultWsApi = clientClass . DEFAULTS . WS _API ;
if ( this . isDev ) defaultWsApi = clientClass . DEFAULTS . DEV _WS _API ;
2018-07-19 07:58:47 +00:00
2017-03-31 11:34:43 +00:00
this . config = {
2018-10-06 16:05:37 +00:00
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
2017-03-31 11:34:43 +00:00
} ;
2018-10-06 16:05:37 +00:00
if ( this . userConfig === { } || this . userConfig . default || JSON . stringify ( this . userConfig ) === '{"enabled":true}' ) {
2018-01-12 22:16:46 +00:00
this . config . account = { } ;
2018-09-28 20:32:37 +00:00
if ( this . env === 'development' ) {
this . isDev = true ;
} else {
this . config . account . password = fs . embarkPath ( "templates/boilerplate/config/privatenet/password" ) ;
this . config . genesisBlock = fs . embarkPath ( "templates/boilerplate/config/privatenet/genesis.json" ) ;
}
2018-09-13 12:37:44 +00:00
this . config . datadir = fs . dappPath ( ".embark/development/datadir" ) ;
2018-09-28 20:32:37 +00:00
this . config . wsOrigins = "http://localhost:8000" ;
this . config . rpcCorsDomain = "http://localhost:8000" ;
this . config . targetGasLimit = 8000000 ;
2018-01-12 22:16:46 +00:00
}
2018-05-28 15:55:16 +00:00
const spaceMessage = 'The path for %s in blockchain config contains spaces, please remove them' ;
2018-05-28 19:56:03 +00:00
if ( this . config . datadir && this . config . datadir . indexOf ( ' ' ) > 0 ) {
2018-10-22 12:56:14 +00:00
this . logger . error ( _ _ ( spaceMessage , 'datadir' ) ) ;
2018-05-28 15:55:16 +00:00
process . exit ( ) ;
}
2018-05-28 19:56:03 +00:00
if ( this . config . account . password && this . config . account . password . indexOf ( ' ' ) > 0 ) {
2018-10-22 12:56:14 +00:00
this . logger . error ( _ _ ( spaceMessage , 'account.password' ) ) ;
2018-05-28 15:55:16 +00:00
process . exit ( ) ;
}
2018-05-28 19:56:03 +00:00
if ( this . config . genesisBlock && this . config . genesisBlock . indexOf ( ' ' ) > 0 ) {
2018-10-22 12:56:14 +00:00
this . logger . error ( _ _ ( spaceMessage , 'genesisBlock' ) ) ;
2018-05-28 15:55:16 +00:00
process . exit ( ) ;
}
2018-09-18 11:12:17 +00:00
this . initProxy ( ) ;
2018-10-06 16:05:37 +00:00
this . client = new clientClass ( { config : this . config , env : this . env , isDev : this . isDev } ) ;
2018-10-22 12:56:14 +00:00
this . initStandaloneProcess ( ) ;
2016-08-21 14:42:42 +00:00
} ;
2018-10-22 12:56:14 +00:00
/ * *
* Polls for a connection to an IPC server ( generally this is set up
* in the Embark process ) . Once connected , any logs logged to the
* Logger will be shipped off to the IPC server . In the case of ` embark
* run ` , the BlockchainListener module is listening for these logs.
*
* @ returns { void }
* /
Blockchain . prototype . initStandaloneProcess = function ( ) {
if ( this . isStandalone ) {
// on every log logged in logger (say that 3x fast), send the log
// to the IPC serve listening (only if we're connected of course)
this . events . on ( 'log' , ( logLevel , message ) => {
if ( this . ipc . connected ) {
this . ipc . request ( 'blockchain:log' , { logLevel , message } ) ;
}
} ) ;
this . ipc = new Ipc ( { ipcRole : 'client' } ) ;
// Wait for an IPC server to start (ie `embark run`) by polling `.connect()`.
// Do not kill this interval as the IPC server may restart (ie restart
// `embark run` without restarting `embark blockchain`)
setInterval ( ( ) => {
if ( ! this . ipc . connected ) {
this . ipc . connect ( ( ) => { } ) ;
}
} , IPC _CONNECT _INTERVAL ) ;
}
} ;
Blockchain . prototype . initProxy = function ( ) {
2018-10-06 16:05:37 +00:00
if ( this . config . proxy ) {
this . config . rpcPort += constants . blockchain . servicePortOnProxy ;
this . config . wsPort += constants . blockchain . servicePortOnProxy ;
2018-06-11 16:02:00 +00:00
}
2018-09-18 11:12:17 +00:00
} ;
2018-10-22 12:56:14 +00:00
Blockchain . prototype . setupProxy = async function ( ) {
2018-10-06 16:05:37 +00:00
if ( ! this . proxyIpc ) this . proxyIpc = new Ipc ( { ipcRole : 'client' } ) ;
2018-06-11 20:40:14 +00:00
2018-09-20 09:16:48 +00:00
let wsProxy ;
2018-10-06 16:05:37 +00:00
if ( this . config . wsRPC ) {
2018-09-20 09:16:48 +00:00
wsProxy = proxy . serve ( this . proxyIpc , this . config . wsHost , this . config . wsPort , true , this . config . wsOrigins ) ;
2018-09-20 05:08:02 +00:00
}
2018-10-06 16:05:37 +00:00
[ this . rpcProxy , this . wsProxy ] = await Promise . all ( [ proxy . serve ( this . proxyIpc , this . config . rpcHost , this . config . rpcPort , false ) , wsProxy ] ) ;
2018-06-11 20:40:14 +00:00
} ;
2018-06-07 19:13:35 +00:00
2018-10-22 12:56:14 +00:00
Blockchain . prototype . shutdownProxy = function ( ) {
2018-07-11 15:38:58 +00:00
if ( ! this . config . proxy ) {
return ;
}
2018-10-06 16:05:37 +00:00
if ( this . rpcProxy ) this . rpcProxy . close ( ) ;
if ( this . wsProxy ) this . wsProxy . close ( ) ;
2018-07-11 15:44:06 +00:00
} ;
2018-07-11 15:38:58 +00:00
2018-10-22 12:56:14 +00:00
Blockchain . prototype . runCommand = function ( cmd , options , callback ) {
this . logger . info ( _ _ ( "running: %s" , cmd . underline ) . green ) ;
2018-10-06 16:05:37 +00:00
if ( this . config . silent ) {
2018-05-22 18:13:56 +00:00
options . silent = true ;
}
2018-10-06 16:05:37 +00:00
return exec ( cmd , options , callback ) ;
2017-03-31 11:34:43 +00:00
} ;
2016-08-21 14:42:42 +00:00
2018-10-22 12:56:14 +00:00
Blockchain . prototype . run = function ( ) {
2017-03-31 11:34:43 +00:00
var self = this ;
2018-10-22 12:56:14 +00:00
this . logger . info ( "===============================================================================" . magenta ) ;
this . logger . info ( "===============================================================================" . magenta ) ;
this . logger . info ( _ _ ( "Embark Blockchain using %s" , self . client . prettyName . underline ) . magenta ) ;
this . logger . info ( "===============================================================================" . magenta ) ;
this . logger . info ( "===============================================================================" . magenta ) ;
2018-10-06 16:05:37 +00:00
if ( self . client . name === 'geth' ) this . checkPathLength ( ) ;
2018-05-08 20:25:48 +00:00
let address = '' ;
2018-05-22 18:13:56 +00:00
async . waterfall ( [
function checkInstallation ( next ) {
self . isClientInstalled ( ( err ) => {
if ( err ) {
2018-10-06 16:05:37 +00:00
return next ( { message : err } ) ;
2018-05-22 18:13:56 +00:00
}
next ( ) ;
} ) ;
} ,
function init ( next ) {
2018-10-06 16:05:37 +00:00
if ( self . isDev ) {
return self . initDevChain ( ( err ) => {
2018-05-22 18:13:56 +00:00
next ( err ) ;
} ) ;
}
2018-10-06 16:05:37 +00:00
return self . initChainAndGetAddress ( ( err , addr ) => {
address = addr ;
next ( err ) ;
} ) ;
2018-05-22 18:13:56 +00:00
} ,
function getMainCommand ( next ) {
2018-10-22 12:56:14 +00:00
self . client . mainCommand ( address , function ( cmd , args ) {
2018-05-28 15:54:31 +00:00
next ( null , cmd , args ) ;
} , true ) ;
2018-05-22 18:13:56 +00:00
}
2018-10-06 16:05:37 +00:00
] , function ( err , cmd , args ) {
2018-05-22 18:13:56 +00:00
if ( err ) {
2018-10-22 12:56:14 +00:00
self . logger . error ( err . message ) ;
2018-05-22 18:13:56 +00:00
return ;
}
2018-07-24 12:29:06 +00:00
args = utils . compact ( args ) ;
2018-06-12 17:58:21 +00:00
let full _cmd = cmd + " " + args . join ( ' ' ) ;
2018-10-22 12:56:14 +00:00
self . logger . info ( _ _ ( "running: %s" , full _cmd . underline ) . green ) ;
2018-10-06 16:05:37 +00:00
self . child = spawn ( cmd , args , { cwd : process . cwd ( ) } ) ;
2018-05-30 14:52:15 +00:00
self . child . on ( 'error' , ( err ) => {
2018-05-28 15:54:31 +00:00
err = err . toString ( ) ;
2018-10-22 12:56:14 +00:00
self . logger . error ( 'Blockchain error: ' , err ) ;
2018-05-28 15:54:31 +00:00
if ( self . env === 'development' && err . indexOf ( 'Failed to unlock' ) > 0 ) {
2018-10-22 12:56:14 +00:00
self . logger . error ( '\n' + _ _ ( 'Development blockchain has changed to use the --dev option.' ) . yellow ) ;
self . logger . error ( _ _ ( 'You can reset your workspace to fix the problem with' ) . yellow + ' embark reset' . cyan ) ;
self . logger . error ( _ _ ( 'Otherwise, you can change your data directory in blockchain.json (datadir)' ) . yellow ) ;
2018-05-22 18:13:56 +00:00
}
} ) ;
2018-10-06 16:05:37 +00:00
// 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
2018-05-30 14:52:15 +00:00
self . child . stdout . on ( 'data' , ( data ) => {
2018-10-24 06:28:27 +00:00
self . logger . info ( ` ${ self . client . name } error: ${ data } ` ) ;
2018-05-28 15:54:31 +00:00
} ) ;
2018-10-06 16:05:37 +00:00
2018-09-20 01:11:36 +00:00
self . child . stderr . on ( 'data' , async ( data ) => {
2018-05-28 15:54:31 +00:00
data = data . toString ( ) ;
2018-10-06 16:05:37 +00:00
if ( ! self . readyCalled && self . client . isReady ( data ) ) {
2018-09-20 09:16:48 +00:00
self . readyCalled = true ;
2018-09-17 12:48:24 +00:00
if ( self . isDev ) {
2018-10-06 16:05:37 +00:00
self . fundAccounts ( ( err ) => {
2018-10-22 12:56:14 +00:00
if ( err ) this . logger . error ( 'Error funding accounts' , err ) ;
2018-09-17 12:48:24 +00:00
} ) ;
}
2018-09-20 09:16:48 +00:00
if ( self . config . proxy ) {
await self . setupProxy ( ) ;
}
2018-06-27 18:32:13 +00:00
self . readyCallback ( ) ;
2018-05-28 15:54:31 +00:00
}
2018-10-25 05:21:08 +00:00
self . logger . info ( ` ${ self . client . name } : ${ data } ` ) ;
2018-05-28 15:54:31 +00:00
} ) ;
2018-10-06 16:05:37 +00:00
2018-05-30 14:52:15 +00:00
self . child . on ( 'exit' , ( code ) => {
2018-06-26 02:59:14 +00:00
let strCode ;
2018-05-28 15:54:31 +00:00
if ( code ) {
2018-10-06 16:05:37 +00:00
strCode = 'with error code ' + code ;
2018-06-22 12:52:15 +00:00
} else {
2018-10-06 16:05:37 +00:00
strCode = 'with no error code (manually killed?)' ;
2018-06-22 12:52:15 +00:00
}
2018-10-22 12:56:14 +00:00
self . logger . error ( self . client . name + ' exited ' + strCode ) ;
2018-10-06 16:05:37 +00:00
if ( self . onExitCallback ) {
2018-06-22 12:52:15 +00:00
self . onExitCallback ( ) ;
}
} ) ;
self . child . on ( 'uncaughtException' , ( err ) => {
2018-10-22 12:56:14 +00:00
self . logger . error ( 'Uncaught ' + self . client . name + ' exception' , err ) ;
2018-10-06 16:05:37 +00:00
if ( self . onExitCallback ) {
2018-06-22 12:52:15 +00:00
self . onExitCallback ( ) ;
2018-05-28 15:54:31 +00:00
}
} ) ;
2017-03-31 11:34:43 +00:00
} ) ;
} ;
2016-08-21 14:42:42 +00:00
2018-10-06 16:05:37 +00:00
Blockchain . prototype . fundAccounts = function ( cb ) {
2018-08-01 01:35:42 +00:00
DevFunds . new ( { blockchainConfig : this . config } ) . then ( devFunds => {
2018-10-06 16:05:37 +00:00
devFunds . fundAccounts ( this . client . needKeepAlive ( ) , ( err ) => {
2018-08-01 01:35:42 +00:00
cb ( err ) ;
} ) ;
2018-07-13 12:56:59 +00:00
} ) ;
2018-08-21 20:12:57 +00:00
} ;
2018-06-27 18:32:13 +00:00
2018-10-22 12:56:14 +00:00
Blockchain . prototype . readyCallback = function ( ) {
2018-06-27 18:32:13 +00:00
if ( this . onReadyCallback ) {
this . onReadyCallback ( ) ;
}
2018-06-28 14:37:10 +00:00
if ( this . config . mineWhenNeeded && ! this . isDev ) {
2018-10-06 16:05:37 +00:00
this . miner = this . client . getMiner ( ) ;
2018-06-27 18:14:58 +00:00
}
2018-07-16 16:48:32 +00:00
} ;
2018-07-13 12:56:59 +00:00
2018-10-22 12:56:14 +00:00
Blockchain . prototype . kill = function ( ) {
2018-07-11 15:38:58 +00:00
this . shutdownProxy ( ) ;
2018-05-30 14:52:15 +00:00
if ( this . child ) {
this . child . kill ( ) ;
}
} ;
2018-10-22 12:56:14 +00:00
Blockchain . prototype . checkPathLength = function ( ) {
2018-05-23 15:08:32 +00:00
let dappPath = fs . dappPath ( '' ) ;
2018-05-25 03:42:18 +00:00
if ( dappPath . length > 66 ) {
2018-10-22 12:56:14 +00:00
// this.logger.error is captured and sent to the console output regardless of silent setting
this . logger . error ( "===============================================================================" . yellow ) ;
this . logger . error ( "===========> " . yellow + _ _ ( 'WARNING! ÐApp path length is too long: ' ) . yellow + dappPath . yellow ) ;
this . logger . 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 ) ;
this . logger . error ( "===============================================================================" . yellow ) ;
2018-05-23 15:08:32 +00:00
}
} ;
2018-10-22 12:56:14 +00:00
Blockchain . prototype . isClientInstalled = function ( callback ) {
2018-05-28 15:55:16 +00:00
let versionCmd = this . client . determineVersionCommand ( ) ;
2018-07-04 13:40:46 +00:00
this . runCommand ( versionCmd , { } , ( err , stdout , stderr ) => {
if ( err || ! stdout || stderr . indexOf ( "not found" ) >= 0 || stdout . indexOf ( "not found" ) >= 0 ) {
2018-10-06 16:05:37 +00:00
return callback ( _ _ ( 'Ethereum client bin not found:' ) + ' ' + this . client . getBinaryPath ( ) ) ;
2018-05-22 18:13:56 +00:00
}
callback ( ) ;
} ) ;
2017-12-13 22:58:07 +00:00
} ;
2018-10-06 16:05:37 +00:00
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 ( ) ;
} ) ;
} ) ;
} ;
2018-10-22 12:56:14 +00:00
Blockchain . prototype . initChainAndGetAddress = function ( callback ) {
2018-05-22 18:13:56 +00:00
const self = this ;
2018-05-22 19:36:31 +00:00
let address = null ;
2018-07-03 18:55:04 +00:00
const ALREADY _INITIALIZED = 'already' ;
2017-03-31 11:34:43 +00:00
// ensure datadir exists, bypassing the interactive liabilities prompt.
2018-05-22 18:13:56 +00:00
self . datadir = '.embark/' + self . env + '/datadir' ;
async . waterfall ( [
function makeDir ( next ) {
2018-05-22 19:36:31 +00:00
fs . mkdirp ( self . datadir , ( err , _result ) => {
next ( err ) ;
} ) ;
2018-05-22 18:13:56 +00:00
} ,
function listAccounts ( next ) {
2018-07-03 18:55:04 +00:00
self . runCommand ( self . client . listAccountsCommand ( ) , { } , ( err , stdout , _stderr ) => {
2018-10-06 16:05:37 +00:00
if ( err || stdout === undefined || stdout . indexOf ( "Fatal" ) >= 0 ) {
2018-10-22 12:56:14 +00:00
this . logger . info ( _ _ ( "no accounts found" ) . green ) ;
2018-10-06 16:05:37 +00:00
return next ( ) ;
}
let firstAccountFound = self . client . parseListAccountsCommandResultToAddress ( stdout ) ;
if ( firstAccountFound === undefined || firstAccountFound === "" ) {
2018-05-22 18:13:56 +00:00
console . log ( _ _ ( "no accounts found" ) . green ) ;
return next ( ) ;
}
2018-10-22 12:56:14 +00:00
this . logger . info ( _ _ ( "already initialized" ) . green ) ;
2018-10-06 16:05:37 +00:00
address = firstAccountFound ;
2018-07-03 18:55:04 +00:00
next ( ALREADY _INITIALIZED ) ;
2018-05-22 18:13:56 +00:00
} ) ;
} ,
function genesisBlock ( next ) {
2018-10-06 16:05:37 +00:00
//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' ) {
2018-05-22 18:13:56 +00:00
return next ( ) ;
}
2018-10-22 12:56:14 +00:00
this . logger . info ( _ _ ( "initializing genesis block" ) . green ) ;
2018-05-22 18:13:56 +00:00
self . runCommand ( self . client . initGenesisCommmand ( ) , { } , ( err , _stdout , _stderr ) => {
next ( err ) ;
} ) ;
} ,
function newAccount ( next ) {
2018-05-22 19:36:31 +00:00
self . runCommand ( self . client . newAccountCommand ( ) , { } , ( err , stdout , _stderr ) => {
2018-05-22 18:13:56 +00:00
if ( err ) {
return next ( err ) ;
}
2018-10-06 16:05:37 +00:00
address = self . client . parseNewAccountCommandResultToAddress ( stdout ) ;
2018-05-22 19:36:31 +00:00
next ( ) ;
2018-05-22 18:13:56 +00:00
} ) ;
2017-03-30 11:12:39 +00:00
}
2018-05-22 18:13:56 +00:00
] , ( err ) => {
2018-07-03 18:55:04 +00:00
if ( err === ALREADY _INITIALIZED ) {
err = null ;
}
2018-05-22 18:13:56 +00:00
callback ( err , address ) ;
} ) ;
2017-03-31 11:34:43 +00:00
} ;
2018-10-22 12:56:14 +00:00
var BlockchainClient = function ( userConfig , clientName , env , onReadyCallback , onExitCallback , logger , events , isStandalone ) {
2018-10-06 16:05:37 +00:00
if ( ( userConfig === { } || JSON . stringify ( userConfig ) === '{"enabled":true}' ) && env !== 'development' ) {
2018-10-22 12:56:14 +00:00
logger . info ( "===> " + _ _ ( "warning: running default config on a non-development environment" ) ) ;
2018-10-06 16:05:37 +00:00
}
// 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 ;
2018-10-22 12:56:14 +00:00
return new Blockchain ( { blockchainConfig , client : GethCommands , env , isDev , onReadyCallback , onExitCallback , logger , events , isStandalone } ) ;
2018-10-06 16:05:37 +00:00
default :
console . error ( _ _ ( 'Unknow client "%s". Please use one of the following: %s' , userConfig . ethereumClientName , 'geth, parity' ) ) ;
process . exit ( ) ;
2016-08-21 14:42:42 +00:00
}
2018-10-06 16:05:37 +00:00
userConfig . isDev = ( userConfig . isDev || userConfig . default ) ;
userConfig . env = env ;
userConfig . onReadyCallback = onReadyCallback ;
userConfig . onExitCallback = onExitCallback ;
return new Blockchain ( userConfig , clientClass ) ;
2017-03-31 11:34:43 +00:00
} ;
2016-08-21 14:42:42 +00:00
module . exports = BlockchainClient ;