diff --git a/lib/cmds/blockchain/blockchain.js b/lib/cmds/blockchain/blockchain.js index f2e9cf99..2689ac47 100644 --- a/lib/cmds/blockchain/blockchain.js +++ b/lib/cmds/blockchain/blockchain.js @@ -14,6 +14,7 @@ var Blockchain = function(options) { this.client = options.client; this.isDev = options.isDev; this.onReadyCallback = options.onReadyCallback; + this.onExitCallback = options.onExitCallback; if ((this.blockchainConfig === {} || JSON.stringify(this.blockchainConfig) === '{"enabled":true}') && this.env !== 'development') { console.log("===> " + __("warning: running default config on a non-development environment")); @@ -167,8 +168,24 @@ Blockchain.prototype.run = function() { console.log('Geth: ' + data); }); self.child.on('exit', (code) => { + let strCode; if (code) { - console.error('Geth exited with error code ' + code); + strCode = ' with error code ' + code; + } else { + strCode = ' with no error code (manually killed?)'; + } + console.error('Geth exited' + strCode); + + if(self.onExitCallback){ + self.onExitCallback(); + } + }); + + self.child.on('uncaughtException', (err) => { + console.error('Uncaught geth exception', err); + + if(self.onExitCallback){ + self.onExitCallback(); } }); }); @@ -252,10 +269,10 @@ Blockchain.prototype.initChainAndGetAddress = function(callback) { }); }; -var BlockchainClient = function(blockchainConfig, client, env, isDev, onReadyCallback) { +var BlockchainClient = function(blockchainConfig, client, env, isDev, onReadyCallback, onExitCallback) { // TODO add other clients at some point if (client === 'geth') { - return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback}); + return new Blockchain({blockchainConfig, client: GethCommands, env, isDev, onReadyCallback, onExitCallback}); } else { throw new Error('unknown client'); } diff --git a/lib/cmds/blockchain/blockchainProcess.js b/lib/cmds/blockchain/blockchainProcess.js index e9d3724f..01317421 100644 --- a/lib/cmds/blockchain/blockchainProcess.js +++ b/lib/cmds/blockchain/blockchainProcess.js @@ -21,7 +21,8 @@ class BlockchainProcess extends ProcessWrapper { this.client, this.env, this.isDev, - this.blockchainReady.bind(this) + this.blockchainReady.bind(this), + this.blockchainExit.bind(this) ); this.blockchain.run(); @@ -31,6 +32,11 @@ class BlockchainProcess extends ProcessWrapper { blockchainProcess.send({result: constants.blockchain.blockchainReady}); } + blockchainExit() { + // tell our parent process that geth has exited + blockchainProcess.send({result: constants.blockchain.blockchainExit}); + } + kill() { this.blockchain.kill(); } diff --git a/lib/constants.json b/lib/constants.json index d8a0759b..caf92da9 100644 --- a/lib/constants.json +++ b/lib/constants.json @@ -34,6 +34,7 @@ }, "blockchain": { "blockchainReady": "blockchainReady", + "blockchainExit": "blockchainExit", "init": "init", "initiated": "initiated", "servicePortOnProxy": 10 diff --git a/lib/contracts/blockchain.js b/lib/contracts/blockchain.js index 6ae0c9c7..38cfe927 100644 --- a/lib/contracts/blockchain.js +++ b/lib/contracts/blockchain.js @@ -48,7 +48,7 @@ class Blockchain { } const protocol = (this.contractsConfig.deployment.type === "rpc") ? this.contractsConfig.deployment.protocol : 'ws'; - let provider; + this.web3Endpoint = utils.buildUrl(protocol, this.contractsConfig.deployment.host, this.contractsConfig.deployment.port);//`${protocol}://${this.contractsConfig.deployment.host}:${this.contractsConfig.deployment.port}`; const providerOptions = { @@ -60,7 +60,7 @@ class Blockchain { type: this.contractsConfig.deployment.type, web3Endpoint: self.web3Endpoint }; - provider = new Provider(providerOptions); + this.provider = new Provider(providerOptions); async.waterfall([ function checkNode(next) { @@ -73,21 +73,35 @@ class Blockchain { if (!err) { self.isWeb3Ready = true; self.events.emit(WEB3_READY); + // if the ethereum node goes offline, we need a check to ensure + // the provider is also stopped + self.events.on('check:wentOffline:Ethereum', () => { + self.logger.trace('Ethereum went offline: stopping web3 provider...'); + self.provider.stop(); + + // once the node goes back online, we can restart the provider + self.events.once('check:backOnline:Ethereum', () => { + self.logger.trace('Ethereum back online: starting web3 provider...'); + self.provider.startWeb3Provider(() => { + self.logger.trace('web3 provider restarted after ethereum node came back online'); + }); + }); + }); return next(); } self.web3StartedInProcess = true; self.startBlockchainNode(() => { // Need to re-initialize web3 to connect to the new blockchain node - provider.stop(); + self.provider.stop(); self.initWeb3(cb); }); }); }, function startProvider(next) { - provider.startWeb3Provider(next); + self.provider.startWeb3Provider(next); }, function fundAccountsIfNeeded(next) { - provider.fundAccounts(next); + self.provider.fundAccounts(next); } ], (err) => { self.registerWeb3Object(); @@ -120,6 +134,10 @@ class Blockchain { self.events.once(constants.blockchain.blockchainReady, () => { callback(); }); + self.events.once(constants.blockchain.blockchainExit, () => { + self.provider.stop(); + callback(); + }); } registerServiceCheck() { diff --git a/lib/contracts/provider.js b/lib/contracts/provider.js index 59e128fb..e7c5ce91 100644 --- a/lib/contracts/provider.js +++ b/lib/contracts/provider.js @@ -39,12 +39,16 @@ class Provider { // network connectivity error self.engine.on('error', (err) => { - // report connectivity errors - self.logger.error(err.stack); + // report connectivity errors as trace due to polling + self.logger.trace('web3 provider error: ', err); + self.logger.trace('stopping web3 provider due to error'); + + // prevent continuous polling errors + self.engine.stop(); }); self.engine.start(); - self.web3.setProvider(self); + self.web3.setProvider(self); self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger); self.addresses = []; diff --git a/lib/processes/blockchainProcessLauncher.js b/lib/processes/blockchainProcessLauncher.js index ba30dbd5..68c54eb8 100644 --- a/lib/processes/blockchainProcessLauncher.js +++ b/lib/processes/blockchainProcessLauncher.js @@ -44,6 +44,14 @@ class BlockchainProcessLauncher { this.events.emit(constants.blockchain.blockchainReady); }); + this.blockchainProcess.once('result', constants.blockchain.blockchainExit, () => { + // telle everyone that our blockchain process (ie geth) died + this.events.emit(constants.blockchain.blockchainExit); + + // then kill off the blockchain process + this.blockchainProcess.kill(); + }); + this.events.on('exit', () => { this.blockchainProcess.send('exit'); }); diff --git a/package.json b/package.json index e53e04bc..c5322a11 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "uuid": "^3.2.1", "viz.js": "^1.8.1", "web3": "1.0.0-beta.34", - "embark-web3-provider-engine": "14.0.6", + "embark-web3-provider-engine": "14.0.7", "webpack": "^3.10.0", "window-size": "^1.1.0" },