2018-05-22 18:13:56 +00:00
const async = require ( 'async' ) ;
const shelljs = require ( 'shelljs' ) ;
2016-08-21 14:42:42 +00:00
2018-05-22 18:13:56 +00:00
const fs = require ( '../../core/fs.js' ) ;
2017-02-19 17:51:32 +00:00
2018-05-22 18:13:56 +00:00
const GethCommands = require ( './geth_commands.js' ) ;
2017-02-19 17:51:32 +00:00
2018-01-24 00:36:02 +00:00
/*eslint complexity: ["error", 35]*/
2017-03-31 11:34:43 +00:00
var Blockchain = function ( options ) {
this . blockchainConfig = options . blockchainConfig ;
this . env = options . env || 'development' ;
this . client = options . client ;
2018-05-14 18:32:19 +00:00
this . isDev = options . isDev ;
2018-05-22 18:13:56 +00:00
this . onReadyCallback = options . onReadyCallback ;
2017-03-31 11:34:43 +00:00
2018-01-12 22:16:46 +00:00
if ( ( this . blockchainConfig === { } || JSON . stringify ( this . blockchainConfig ) === '{"enabled":true}' ) && this . env !== 'development' ) {
2018-05-08 21:49:46 +00:00
console . log ( "===> " + _ _ ( "warning: running default config on a non-development environment" ) ) ;
2018-01-12 22:16:46 +00:00
}
2017-03-31 11:34:43 +00:00
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 : this . blockchainConfig . rpcHost || 'localhost' ,
rpcPort : this . blockchainConfig . rpcPort || 8545 ,
rpcCorsDomain : this . blockchainConfig . rpcCorsDomain || false ,
2018-05-11 14:23:52 +00:00
networkId : this . blockchainConfig . networkId || 1337 ,
2017-03-31 11:34:43 +00:00
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' ] ) ,
2018-01-11 13:55:28 +00:00
wsRPC : ( this . blockchainConfig . wsRPC === undefined ) || this . blockchainConfig . wsRPC ,
2017-10-19 22:55:49 +00:00
wsHost : this . blockchainConfig . wsHost || 'localhost' ,
wsPort : this . blockchainConfig . wsPort || 8546 ,
wsOrigins : this . blockchainConfig . wsOrigins || false ,
wsApi : ( this . blockchainConfig . wsApi || [ 'eth' , 'web3' , 'net' , 'shh' ] ) ,
2018-01-17 16:23:32 +00:00
vmdebug : this . blockchainConfig . vmdebug || false ,
2018-01-22 07:54:49 +00:00
targetGasLimit : this . blockchainConfig . targetGasLimit || false ,
light : this . blockchainConfig . light || false ,
2018-05-22 13:11:38 +00:00
fast : this . blockchainConfig . fast || false ,
verbosity : this . blockchainConfig . verbosity
2017-03-31 11:34:43 +00:00
} ;
2018-01-12 22:16:46 +00:00
if ( this . blockchainConfig === { } || JSON . stringify ( this . blockchainConfig ) === '{"enabled":true}' ) {
this . config . account = { } ;
2018-03-29 23:23:24 +00:00
this . config . account . password = fs . embarkPath ( "templates/boilerplate/config/development/password" ) ;
this . config . genesisBlock = fs . embarkPath ( "templates/boilerplate/config/development/genesis.json" ) ;
2018-01-12 22:16:46 +00:00
this . config . datadir = fs . embarkPath ( ".embark/development/datadir" ) ;
}
2018-05-09 13:17:48 +00:00
this . client = new options . client ( { config : this . config , env : this . env , isDev : this . isDev } ) ;
2016-08-21 14:42:42 +00:00
} ;
2018-05-22 18:13:56 +00:00
Blockchain . prototype . runCommand = function ( cmd , options , callback ) {
2018-05-08 21:49:46 +00:00
console . log ( _ _ ( "running: %s" , cmd . underline ) . green ) ;
2018-05-22 18:13:56 +00:00
if ( this . blockchainConfig . silent ) {
options . silent = true ;
}
return shelljs . exec ( cmd , options , callback ) ;
2017-03-31 11:34:43 +00:00
} ;
2016-08-21 14:42:42 +00:00
2017-03-31 11:34:43 +00:00
Blockchain . prototype . run = function ( ) {
var self = this ;
console . log ( "===============================================================================" . magenta ) ;
console . log ( "===============================================================================" . magenta ) ;
2018-05-08 21:49:46 +00:00
console . log ( _ _ ( "Embark Blockchain Using: %s" , this . client . name . underline ) . magenta ) ;
2017-03-31 11:34:43 +00:00
console . log ( "===============================================================================" . magenta ) ;
console . log ( "===============================================================================" . magenta ) ;
2018-05-22 18:13:56 +00:00
2018-05-23 16:04:00 +00:00
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 ) {
console . log ( _ _ ( "could not find {{geth_bin}} command; is {{client_name}} installed or in the PATH?" , { geth _bin : this . config . geth _bin , client _name : this . client . name } ) . green ) ;
return next ( err ) ;
}
next ( ) ;
} ) ;
} ,
function init ( next ) {
if ( ! self . isDev ) {
return self . initChainAndGetAddress ( ( err , addr ) => {
address = addr ;
next ( err ) ;
} ) ;
}
next ( ) ;
} ,
function getMainCommand ( next ) {
self . client . mainCommand ( address , function ( cmd ) {
next ( null , cmd ) ;
} ) ;
}
] , function ( err , cmd ) {
if ( err ) {
console . error ( err ) ;
return ;
}
const child = self . runCommand ( cmd , { } , ( err , stdout , _stderr ) => {
if ( err && self . env === 'development' && stdout . indexOf ( 'Failed to unlock' ) > 0 ) {
console . warn ( '\n' + _ _ ( 'Development blockchain has changed to use the --dev option.' ) . yellow ) ;
console . warn ( _ _ ( 'You can reset your workspace to fix the problem with' ) . yellow + ' embark reset' . cyan ) ;
console . warn ( _ _ ( 'Otherwise, you can change your data directory in blockchain.json (datadir)' ) . yellow ) ;
}
} ) ;
if ( self . onReadyCallback ) {
// Geth logs appear in stderr somehow
2018-05-23 14:51:42 +00:00
let lastMessage ;
2018-05-22 18:13:56 +00:00
child . stderr . on ( 'data' , ( data ) => {
if ( ! self . readyCalled && data . indexOf ( 'Mapped network port' ) > - 1 ) {
self . readyCalled = true ;
2018-05-23 14:51:42 +00:00
self . onReadyCallback ( ) ;
}
lastMessage = data ;
console . log ( 'Geth: ' + data ) ;
} ) ;
child . on ( 'exit' , ( code ) => {
if ( code ) {
console . error ( 'Geth exited with error code ' + 1 ) ;
console . error ( lastMessage ) ;
2018-05-22 18:13:56 +00:00
}
} ) ;
}
2017-03-31 11:34:43 +00:00
} ) ;
} ;
2016-08-21 14:42:42 +00:00
2018-05-23 16:04:00 +00:00
Blockchain . prototype . checkPathLength = function ( ) {
2018-05-23 15:08:32 +00:00
let dappPath = fs . dappPath ( '' ) ;
if ( dappPath . split ( '/' ) . length > 5 ) {
console . log ( "===============================================================================" . yellow ) ;
console . log ( "===========> Path depth is too long " . yellow + dappPath ) ;
console . log ( "===========> This is known to cause issues with some applications, please consider putting your dapp in a different path" . yellow ) ;
}
} ;
2018-05-22 18:13:56 +00:00
Blockchain . prototype . isClientInstalled = function ( callback ) {
2017-12-13 22:58:07 +00:00
let versionCmd = this . client . determineVersion ( ) ;
2018-05-22 18:13:56 +00:00
this . runCommand ( versionCmd , { } , ( err , stdout , stderr ) => {
if ( err || stderr || ! stdout || stdout . indexOf ( "not found" ) >= 0 ) {
return callback ( 'Geth not found' ) ;
}
callback ( ) ;
} ) ;
2017-12-13 22:58:07 +00:00
} ;
2018-05-22 18:13:56 +00:00
Blockchain . prototype . initChainAndGetAddress = function ( callback ) {
const self = this ;
2018-05-22 19:36:31 +00:00
let address = null ;
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 copy ( next ) {
// copy mining script
fs . copy ( fs . embarkPath ( "js" ) , ".embark/" + self . env + "/js" , { overwrite : true } , next ) ;
} ,
function listAccounts ( next ) {
self . runCommand ( self . client . listAccountsCommand ( ) , { } , ( err , stdout , stderr ) => {
if ( err || stderr || stdout === undefined || stdout . match ( /{(\w+)}/ ) === null || stdout . indexOf ( "Fatal" ) >= 0 ) {
console . log ( _ _ ( "no accounts found" ) . green ) ;
return next ( ) ;
}
2018-05-22 19:36:31 +00:00
console . log ( _ _ ( "already initialized" ) . green ) ;
address = stdout . match ( /{(\w+)}/ ) [ 1 ] ;
next ( ) ;
2018-05-22 18:13:56 +00:00
} ) ;
} ,
function genesisBlock ( next ) {
if ( ! self . config . genesisBlock ) {
return next ( ) ;
}
2018-05-08 21:49:46 +00:00
console . log ( _ _ ( "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 ) ;
}
address = stdout . match ( /{(\w+)}/ ) [ 1 ] ;
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 ) => {
callback ( err , address ) ;
} ) ;
2017-03-31 11:34:43 +00:00
} ;
2018-05-22 18:13:56 +00:00
var BlockchainClient = function ( blockchainConfig , client , env , isDev , onReadyCallback ) {
2018-05-18 17:27:01 +00:00
// TODO add other clients at some point
2017-03-31 11:34:43 +00:00
if ( client === 'geth' ) {
2018-05-22 18:13:56 +00:00
return new Blockchain ( { blockchainConfig , client : GethCommands , env , isDev , onReadyCallback } ) ;
2017-03-31 11:34:43 +00:00
} else {
throw new Error ( 'unknown client' ) ;
2016-08-21 14:42:42 +00:00
}
2017-03-31 11:34:43 +00:00
} ;
2016-08-21 14:42:42 +00:00
module . exports = BlockchainClient ;