config: update configuration options for exec path
- config options for bitcoind to specify exec path of bitcoind - config options to connect to multiple bitcoind processes - systemd and upstart preferred methods to daemonize
This commit is contained in:
parent
5932b34a1f
commit
0f24dd5f49
|
@ -28,7 +28,6 @@ var errors = require('./errors');
|
||||||
*
|
*
|
||||||
* @param {Object} config - The configuration of the node
|
* @param {Object} config - The configuration of the node
|
||||||
* @param {Array} config.services - The array of services
|
* @param {Array} config.services - The array of services
|
||||||
* @param {String} config.datadir - The directory for data (e.g. bitcoind datadir)
|
|
||||||
* @param {Number} config.port - The HTTP port for services
|
* @param {Number} config.port - The HTTP port for services
|
||||||
* @param {Boolean} config.https - Enable https
|
* @param {Boolean} config.https - Enable https
|
||||||
* @param {Object} config.httpsOptions - Options for https
|
* @param {Object} config.httpsOptions - Options for https
|
||||||
|
@ -52,8 +51,6 @@ function Node(config) {
|
||||||
$.checkArgument(Array.isArray(config.services));
|
$.checkArgument(Array.isArray(config.services));
|
||||||
this._unloadedServices = config.services;
|
this._unloadedServices = config.services;
|
||||||
}
|
}
|
||||||
$.checkState(config.datadir, 'Node config expects "datadir"');
|
|
||||||
this.datadir = config.datadir;
|
|
||||||
this.port = config.port;
|
this.port = config.port;
|
||||||
this.https = config.https;
|
this.https = config.https;
|
||||||
this.httpsOptions = config.httpsOptions;
|
this.httpsOptions = config.httpsOptions;
|
||||||
|
|
|
@ -15,10 +15,15 @@ function getDefaultBaseConfig(options) {
|
||||||
return {
|
return {
|
||||||
path: process.cwd(),
|
path: process.cwd(),
|
||||||
config: {
|
config: {
|
||||||
datadir: options.datadir || path.resolve(process.env.HOME, '.bitcoin'),
|
|
||||||
network: options.network || 'livenet',
|
network: options.network || 'livenet',
|
||||||
port: 3001,
|
port: 3001,
|
||||||
services: ['bitcoind', 'db', 'address', 'web']
|
services: ['bitcoind', 'web'],
|
||||||
|
servicesConfig: {
|
||||||
|
bitcoind: {
|
||||||
|
datadir: options.datadir || path.resolve(process.env.HOME, '.bitcoin'),
|
||||||
|
exec: path.resolve(__dirname, '../../dist/bitcoind')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,17 +24,22 @@ function getDefaultConfig(options) {
|
||||||
mkdirp.sync(defaultPath);
|
mkdirp.sync(defaultPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultServices = ['bitcoind', 'db', 'address', 'web'];
|
var defaultServices = ['bitcoind', 'web'];
|
||||||
if (options.additionalServices) {
|
if (options.additionalServices) {
|
||||||
defaultServices = defaultServices.concat(options.additionalServices);
|
defaultServices = defaultServices.concat(options.additionalServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(defaultConfigFile)) {
|
if (!fs.existsSync(defaultConfigFile)) {
|
||||||
var defaultConfig = {
|
var defaultConfig = {
|
||||||
datadir: path.resolve(defaultPath, './data'),
|
|
||||||
network: 'livenet',
|
network: 'livenet',
|
||||||
port: 3001,
|
port: 3001,
|
||||||
services: defaultServices
|
services: defaultServices,
|
||||||
|
servicesConfig: {
|
||||||
|
bitcoind: {
|
||||||
|
datadir: path.resolve(defaultPath, './data'),
|
||||||
|
exec: path.resolve(__dirname, '../../dist/bitcoind')
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
fs.writeFileSync(defaultConfigFile, JSON.stringify(defaultConfig, null, 2));
|
fs.writeFileSync(defaultConfigFile, JSON.stringify(defaultConfig, null, 2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,11 +201,6 @@ function start(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fullConfig.services = start.setupServices(require, servicesPath, options.config);
|
fullConfig.services = start.setupServices(require, servicesPath, options.config);
|
||||||
fullConfig.datadir = path.resolve(options.path, options.config.datadir);
|
|
||||||
|
|
||||||
if (fullConfig.daemon) {
|
|
||||||
start.spawnChildProcess(fullConfig.datadir, process);
|
|
||||||
}
|
|
||||||
|
|
||||||
var node = new BitcoreNode(fullConfig);
|
var node = new BitcoreNode(fullConfig);
|
||||||
|
|
||||||
|
@ -237,46 +232,9 @@ function start(options) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function will fork the passed in process and exit the parent process
|
|
||||||
* in order to daemonize the process. If there is already a daemon for this pid (process),
|
|
||||||
* then the function just returns. Stdout and stderr both append to one file, 'bitcore-node.log'
|
|
||||||
* located in the datadir.
|
|
||||||
* @param {String} datadir - The data directory where the bitcoin blockchain and config live.
|
|
||||||
* @param {Object} _process - The process that needs to fork a child and then, itself, exit.
|
|
||||||
*/
|
|
||||||
function spawnChildProcess(datadir, _process) {
|
|
||||||
|
|
||||||
if (_process.env.__bitcore_node) {
|
|
||||||
return _process.pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
var args = [].concat(_process.argv);
|
|
||||||
args.shift();
|
|
||||||
var script = args.shift();
|
|
||||||
var env = _process.env;
|
|
||||||
var cwd = _process.cwd();
|
|
||||||
env.__bitcore_node = true;
|
|
||||||
|
|
||||||
var stderr = fs.openSync(datadir + '/bitcore-node.log', 'a+');
|
|
||||||
var stdout = stderr;
|
|
||||||
|
|
||||||
var cp_opt = {
|
|
||||||
stdio: ['ignore', stdout, stderr],
|
|
||||||
env: env,
|
|
||||||
cwd: cwd,
|
|
||||||
detached: true
|
|
||||||
};
|
|
||||||
|
|
||||||
var child = child_process.spawn(_process.execPath, [script].concat(args), cp_opt);
|
|
||||||
child.unref();
|
|
||||||
return _process.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = start;
|
module.exports = start;
|
||||||
module.exports.registerExitHandlers = registerExitHandlers;
|
module.exports.registerExitHandlers = registerExitHandlers;
|
||||||
module.exports.exitHandler = exitHandler;
|
module.exports.exitHandler = exitHandler;
|
||||||
module.exports.registerSyncHandlers = registerSyncHandlers;
|
module.exports.registerSyncHandlers = registerSyncHandlers;
|
||||||
module.exports.setupServices = setupServices;
|
module.exports.setupServices = setupServices;
|
||||||
module.exports.spawnChildProcess = spawnChildProcess;
|
|
||||||
module.exports.cleanShutdown = cleanShutdown;
|
module.exports.cleanShutdown = cleanShutdown;
|
||||||
|
|
|
@ -6,7 +6,6 @@ var spawn = require('child_process').spawn;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp');
|
||||||
var bitcore = require('bitcore-lib');
|
var bitcore = require('bitcore-lib');
|
||||||
var Address = bitcore.Address;
|
|
||||||
var zmq = require('zmq');
|
var zmq = require('zmq');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var LRU = require('lru-cache');
|
var LRU = require('lru-cache');
|
||||||
|
@ -27,12 +26,11 @@ var Transaction = require('../transaction');
|
||||||
* @param {Node} options.node - A reference to the node
|
* @param {Node} options.node - A reference to the node
|
||||||
*/
|
*/
|
||||||
function Bitcoin(options) {
|
function Bitcoin(options) {
|
||||||
|
/* jshint maxstatements: 20 */
|
||||||
if (!(this instanceof Bitcoin)) {
|
if (!(this instanceof Bitcoin)) {
|
||||||
return new Bitcoin(options);
|
return new Bitcoin(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._reindex = false;
|
|
||||||
this._reindexWait = 1000;
|
|
||||||
Service.call(this, options);
|
Service.call(this, options);
|
||||||
|
|
||||||
// caches valid until there is a new block
|
// caches valid until there is a new block
|
||||||
|
@ -41,15 +39,32 @@ function Bitcoin(options) {
|
||||||
this.balanceCache = LRU(50000);
|
this.balanceCache = LRU(50000);
|
||||||
this.summaryCache = LRU(50000);
|
this.summaryCache = LRU(50000);
|
||||||
|
|
||||||
// caches valid indefinetly
|
// caches valid indefinitely
|
||||||
this.transactionCache = LRU(100000);
|
this.transactionCache = LRU(100000);
|
||||||
this.transactionInfoCache = LRU(100000);
|
this.transactionInfoCache = LRU(100000);
|
||||||
this.blockCache = LRU(144);
|
this.blockCache = LRU(144);
|
||||||
this.blockHeaderCache = LRU(288);
|
this.blockHeaderCache = LRU(288);
|
||||||
|
this.zmqKnownTransactions = LRU(50);
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
|
||||||
|
// bitcoind child process
|
||||||
|
this.spawn = false;
|
||||||
|
|
||||||
|
// available bitcoind nodes
|
||||||
|
this.nodes = [];
|
||||||
|
this.nodesIndex = 0;
|
||||||
|
Object.defineProperty(this, 'client', {
|
||||||
|
get: function() {
|
||||||
|
var client = this.nodes[this.nodesIndex].client;
|
||||||
|
this.nodesIndex = (this.nodesIndex + 1) % this.nodes.length;
|
||||||
|
return client;
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
configurable: false
|
||||||
|
});
|
||||||
|
|
||||||
$.checkState(this.node.datadir, 'Node is missing datadir property');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(Bitcoin, Service);
|
util.inherits(Bitcoin, Service);
|
||||||
|
|
||||||
Bitcoin.dependencies = [];
|
Bitcoin.dependencies = [];
|
||||||
|
@ -77,15 +92,24 @@ Bitcoin.prototype.getAPIMethods = function() {
|
||||||
return methods;
|
return methods;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._loadConfiguration = function() {
|
Bitcoin.prototype._loadSpawnConfiguration = function(node) {
|
||||||
/* jshint maxstatements: 25 */
|
/* jshint maxstatements: 25 */
|
||||||
|
|
||||||
$.checkArgument(this.node.datadir, 'Please specify "datadir" in configuration options');
|
$.checkArgument(this.options.spawn, 'Please specify "spawn" in bitcoind config options');
|
||||||
var configPath = this.node.datadir + '/bitcoin.conf';
|
$.checkArgument(this.options.spawn.datadir, 'Please specify "spawn.datadir" in bitcoind config options');
|
||||||
this.configuration = {};
|
$.checkArgument(this.options.spawn.exec, 'Please specify "spawn.exec" in bitcoind config options');
|
||||||
|
|
||||||
if (!fs.existsSync(this.node.datadir)) {
|
var spawnOptions = this.options.spawn;
|
||||||
mkdirp.sync(this.node.datadir);
|
var configPath = spawnOptions.datadir + '/bitcoin.conf';
|
||||||
|
|
||||||
|
this.spawn = {};
|
||||||
|
this.spawn.datadir = this.options.spawn.datadir;
|
||||||
|
this.spawn.exec = this.options.spawn.exec;
|
||||||
|
this.spawn.configPath = configPath;
|
||||||
|
this.spawn.config = {};
|
||||||
|
|
||||||
|
if (!fs.existsSync(spawnOptions.datadir)) {
|
||||||
|
mkdirp.sync(spawnOptions.datadir);
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = fs.readFileSync(configPath);
|
var file = fs.readFileSync(configPath);
|
||||||
|
@ -100,48 +124,50 @@ Bitcoin.prototype._loadConfiguration = function() {
|
||||||
} else {
|
} else {
|
||||||
value = option[1];
|
value = option[1];
|
||||||
}
|
}
|
||||||
this.configuration[option[0]] = value;
|
this.spawn.config[option[0]] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var spawnConfig = this.spawn.config;
|
||||||
|
|
||||||
$.checkState(
|
$.checkState(
|
||||||
this.configuration.txindex && this.configuration.txindex === 1,
|
spawnConfig.txindex && spawnConfig.txindex === 1,
|
||||||
'"txindex" option is required in order to use transaction query features of bitcore-node. ' +
|
'"txindex" option is required in order to use transaction query features of bitcore-node. ' +
|
||||||
'Please add "txindex=1" to your configuration and reindex an existing database if ' +
|
'Please add "txindex=1" to your configuration and reindex an existing database if ' +
|
||||||
'necessary with reindex=1'
|
'necessary with reindex=1'
|
||||||
);
|
);
|
||||||
|
|
||||||
$.checkState(
|
$.checkState(
|
||||||
this.configuration.addressindex && this.configuration.addressindex === 1,
|
spawnConfig.addressindex && spawnConfig.addressindex === 1,
|
||||||
'"addressindex" option is required in order to use address query features of bitcore-node. ' +
|
'"addressindex" option is required in order to use address query features of bitcore-node. ' +
|
||||||
'Please add "addressindex=1" to your configuration and reindex an existing database if ' +
|
'Please add "addressindex=1" to your configuration and reindex an existing database if ' +
|
||||||
'necessary with reindex=1'
|
'necessary with reindex=1'
|
||||||
);
|
);
|
||||||
|
|
||||||
$.checkState(
|
$.checkState(
|
||||||
this.configuration.server && this.configuration.server === 1,
|
spawnConfig.server && spawnConfig.server === 1,
|
||||||
'"server" option is required to communicate to bitcoind from bitcore. ' +
|
'"server" option is required to communicate to bitcoind from bitcore. ' +
|
||||||
'Please add "server=1" to your configuration and restart'
|
'Please add "server=1" to your configuration and restart'
|
||||||
);
|
);
|
||||||
|
|
||||||
$.checkState(
|
$.checkState(
|
||||||
this.configuration.zmqpubrawtx,
|
spawnConfig.zmqpubrawtx,
|
||||||
'"zmqpubrawtx" option is required to get event updates from bitcoind. ' +
|
'"zmqpubrawtx" option is required to get event updates from bitcoind. ' +
|
||||||
'Please add "zmqpubrawtx=tcp://127.0.0.1:<port>" to your configuration and restart'
|
'Please add "zmqpubrawtx=tcp://127.0.0.1:<port>" to your configuration and restart'
|
||||||
);
|
);
|
||||||
|
|
||||||
$.checkState(
|
$.checkState(
|
||||||
this.configuration.zmqpubhashblock,
|
spawnConfig.zmqpubhashblock,
|
||||||
'"zmqpubhashblock" option is required to get event updates from bitcoind. ' +
|
'"zmqpubhashblock" option is required to get event updates from bitcoind. ' +
|
||||||
'Please add "zmqpubhashblock=tcp://127.0.0.1:<port>" to your configuration and restart'
|
'Please add "zmqpubhashblock=tcp://127.0.0.1:<port>" to your configuration and restart'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.configuration.reindex && this.configuration.reindex === 1) {
|
if (spawnConfig.reindex && spawnConfig.reindex === 1) {
|
||||||
log.warn('Reindex option is currently enabled. This means that bitcoind is undergoing a reindex. ' +
|
log.warn('Reindex option is currently enabled. This means that bitcoind is undergoing a reindex. ' +
|
||||||
'The reindex flag will start the index from beginning every time the node is started, so it ' +
|
'The reindex flag will start the index from beginning every time the node is started, so it ' +
|
||||||
'should be removed after the reindex has been initiated. Once the reindex is complete, the rest ' +
|
'should be removed after the reindex has been initiated. Once the reindex is complete, the rest ' +
|
||||||
'of bitcore-node services will start.');
|
'of bitcore-node services will start.');
|
||||||
this._reindex = true;
|
node._reindex = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -153,67 +179,37 @@ Bitcoin.prototype._resetCaches = function() {
|
||||||
this.summaryCache.reset();
|
this.summaryCache.reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._registerEventHandlers = function() {
|
Bitcoin.prototype._initChain = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.zmqSubSocket.subscribe('hashblock');
|
self.client.getBestBlockHash(function(err, response) {
|
||||||
this.zmqSubSocket.subscribe('rawtx');
|
|
||||||
|
|
||||||
this.zmqSubSocket.on('message', function(topic, message) {
|
|
||||||
var topicString = topic.toString('utf8');
|
|
||||||
if (topicString === 'rawtx') {
|
|
||||||
self.emit('tx', message);
|
|
||||||
} else if (topicString === 'hashblock') {
|
|
||||||
self._resetCaches();
|
|
||||||
self.tiphash = message.toString('hex');
|
|
||||||
self.client.getBlock(self.tiphash, function(err, response) {
|
|
||||||
if (err) {
|
|
||||||
return log.error(err);
|
|
||||||
}
|
|
||||||
self.height = response.result.height;
|
|
||||||
$.checkState(self.height >= 0);
|
|
||||||
self.emit('tip', self.height);
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!self.node.stopping) {
|
|
||||||
self.syncPercentage(function(err, percentage) {
|
|
||||||
if (err) {
|
|
||||||
return log.error(err);
|
|
||||||
}
|
|
||||||
log.info('Bitcoin Height:', self.height, 'Percentage:', percentage.toFixed(2));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Bitcoin.prototype._onReady = function(result, callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self._registerEventHandlers();
|
|
||||||
|
|
||||||
self.client.getInfo(function(err, response) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
self.height = response.result.blocks;
|
|
||||||
|
|
||||||
self.client.getBlockHash(0, function(err, response) {
|
self.client.getBlock(response.result, function(err, response) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var blockhash = response.result;
|
|
||||||
self.getBlock(blockhash, function(err, block) {
|
self.height = response.result.height;
|
||||||
|
|
||||||
|
self.client.getBlockHash(0, function(err, response) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
self.tiphash = block.hash;
|
var blockhash = response.result;
|
||||||
self.genesisBuffer = block.toBuffer();
|
self.getBlock(blockhash, function(err, block) {
|
||||||
self.emit('ready', result);
|
if (err) {
|
||||||
log.info('Bitcoin Daemon Ready');
|
return callback(err);
|
||||||
callback();
|
}
|
||||||
|
self.genesisBuffer = block.toBuffer();
|
||||||
|
self.emit('ready');
|
||||||
|
log.info('Bitcoin Daemon Ready');
|
||||||
|
callback();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -229,27 +225,139 @@ Bitcoin.prototype._getNetworkOption = function() {
|
||||||
return networkOption;
|
return networkOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
Bitcoin.prototype._zmqBlockHandler = function(node, message) {
|
||||||
* Called by Node to start the service
|
var self = this;
|
||||||
* @param {Function} callback
|
var hex = message.toString('hex');
|
||||||
*/
|
if (hex !== self.tiphash) {
|
||||||
Bitcoin.prototype.start = function(callback) {
|
self._resetCaches();
|
||||||
|
self.tiphash = message.toString('hex');
|
||||||
|
node.client.getBlock(self.tiphash, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
return log.error(err);
|
||||||
|
}
|
||||||
|
self.height = response.result.height;
|
||||||
|
$.checkState(self.height >= 0);
|
||||||
|
self.emit('tip', self.height);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!self.node.stopping) {
|
||||||
|
self.syncPercentage(function(err, percentage) {
|
||||||
|
if (err) {
|
||||||
|
return log.error(err);
|
||||||
|
}
|
||||||
|
log.info('Bitcoin Height:', self.height, 'Percentage:', percentage.toFixed(2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype._zmqTransactionHandler = function(node, message) {
|
||||||
|
var self = this;
|
||||||
|
var id = message.toString('binary');
|
||||||
|
if (!self.zmqKnownTransactions[id]) {
|
||||||
|
self.zmqKnownTransactions[id] = true;
|
||||||
|
self.emit('tx', message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype._subscribeZmqEvents = function(node) {
|
||||||
|
var self = this;
|
||||||
|
node.zmqSubSocket.subscribe('hashblock');
|
||||||
|
node.zmqSubSocket.subscribe('rawtx');
|
||||||
|
node.zmqSubSocket.on('message', function(topic, message) {
|
||||||
|
var topicString = topic.toString('utf8');
|
||||||
|
if (topicString === 'rawtx') {
|
||||||
|
self._zmqTransactionHandler(node, message);
|
||||||
|
} else if (topicString === 'hashblock') {
|
||||||
|
self._zmqBlockHandler(node, message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype._initZmqSubSocket = function(node, zmqUrl) {
|
||||||
|
var self = this;
|
||||||
|
node.zmqSubSocket = zmq.socket('sub');
|
||||||
|
|
||||||
|
node.zmqSubSocket.on('monitor_error', function(err) {
|
||||||
|
log.error('Error in monitoring: %s, will restart monitoring in 5 seconds', err);
|
||||||
|
setTimeout(function() {
|
||||||
|
self.zmqSubSocket.monitor(500, 0);
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
node.zmqSubSocket.monitor(500, 0);
|
||||||
|
node.zmqSubSocket.connect(zmqUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype._checkReindex = function(node, callback) {
|
||||||
|
var self = this;
|
||||||
|
if (node._reindex) {
|
||||||
|
var interval = setInterval(function() {
|
||||||
|
node.client.syncPercentage(function(err, percentSynced) {
|
||||||
|
if (err) {
|
||||||
|
return log.error(err);
|
||||||
|
}
|
||||||
|
log.info('Bitcoin Core Daemon Reindex Percentage: ' + percentSynced.toFixed(2));
|
||||||
|
if (Math.round(percentSynced) >= 100) {
|
||||||
|
node._reindex = false;
|
||||||
|
self._subscribeZmqEvents(node);
|
||||||
|
callback();
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, self._reindexWait);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
self._subscribeZmqEvents(node);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype._loadTipFromNode = function(node, callback) {
|
||||||
|
var self = this;
|
||||||
|
node.client.getBestBlockHash(function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
if (!(err instanceof Error)) {
|
||||||
|
log.warn(err.message);
|
||||||
|
}
|
||||||
|
return callback(new Error('Could not connect to bitcoind RPC'));
|
||||||
|
}
|
||||||
|
node.client.getBlock(response.result, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
self.height = response.result.height;
|
||||||
|
$.checkState(self.height >= 0);
|
||||||
|
self.emit('tip', self.height);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype._spawnChildProcess = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self._loadConfiguration();
|
var node = {};
|
||||||
|
node._reindex = false;
|
||||||
|
node._reindexWait = 1000;
|
||||||
|
|
||||||
|
try {
|
||||||
|
self._loadSpawnConfiguration(node);
|
||||||
|
} catch(e) {
|
||||||
|
return callback(e);
|
||||||
|
}
|
||||||
|
|
||||||
var options = [
|
var options = [
|
||||||
'--conf=' + path.resolve(this.node.datadir, './bitcoin.conf'),
|
'--conf=' + path.resolve(this.spawn.configPath),
|
||||||
'--datadir=' + this.node.datadir,
|
'--datadir=' + this.spawn.datadir,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (self._getNetworkOption()) {
|
if (self._getNetworkOption()) {
|
||||||
options.push(self._getNetworkOption());
|
options.push(self._getNetworkOption());
|
||||||
}
|
}
|
||||||
|
self.spawn.process = spawn(this.spawn.exec, options, {stdio: 'inherit'});
|
||||||
|
|
||||||
self.process = spawn('bitcoind', options, {stdio: 'inherit'});
|
self.spawn.process.on('error', function(err) {
|
||||||
|
|
||||||
self.process.on('error', function(err) {
|
|
||||||
log.error(err);
|
log.error(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -258,67 +366,104 @@ Bitcoin.prototype.start = function(callback) {
|
||||||
return done(new Error('Stopping while trying to connect to bitcoind.'));
|
return done(new Error('Stopping while trying to connect to bitcoind.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.client = new BitcoinRPC({
|
node.client = new BitcoinRPC({
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: self.configuration.rpcport,
|
port: self.spawn.config.rpcport,
|
||||||
user: self.configuration.rpcuser,
|
user: self.spawn.config.rpcuser,
|
||||||
pass: self.configuration.rpcpassword
|
pass: self.spawn.config.rpcpassword
|
||||||
});
|
});
|
||||||
|
|
||||||
self.client.getBestBlockHash(function(err, response) {
|
self._loadTipFromNode(node, done);
|
||||||
if (err) {
|
|
||||||
if (!(err instanceof Error)) {
|
|
||||||
log.warn(err.message);
|
|
||||||
}
|
|
||||||
return done(new Error('Could not connect to bitcoind RPC'));
|
|
||||||
}
|
|
||||||
self.client.getBlock(response.result, function(err, response) {
|
|
||||||
if (err) {
|
|
||||||
return done(err);
|
|
||||||
}
|
|
||||||
self.height = response.result.height;
|
|
||||||
$.checkState(self.height >= 0);
|
|
||||||
self.emit('tip', self.height);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
}, function ready(err, result) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.zmqSubSocket = zmq.socket('sub');
|
self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx);
|
||||||
|
|
||||||
self.zmqSubSocket.on('monitor_error', function(err) {
|
self._checkReindex(node, function() {
|
||||||
log.error('Error in monitoring: %s, will restart monitoring in 5 seconds', err);
|
if (err) {
|
||||||
setTimeout(function() {
|
return callback(err);
|
||||||
self.zmqSubSocket.monitor(500, 0);
|
}
|
||||||
}, 5000);
|
callback(null, node);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.zmqSubSocket.monitor(500, 0);
|
});
|
||||||
self.zmqSubSocket.connect(self.configuration.zmqpubrawtx);
|
};
|
||||||
|
|
||||||
if (self._reindex) {
|
Bitcoin.prototype._connectProcess = function(config, callback) {
|
||||||
var interval = setInterval(function() {
|
var self = this;
|
||||||
self.syncPercentage(function(err, percentSynced) {
|
var node = {};
|
||||||
if (err) {
|
|
||||||
return log.error(err);
|
|
||||||
}
|
|
||||||
log.info('Bitcoin Core Daemon Reindex Percentage: ' + percentSynced.toFixed(2));
|
|
||||||
if (Math.round(percentSynced) >= 100) {
|
|
||||||
self._reindex = false;
|
|
||||||
self._onReady(result, callback);
|
|
||||||
clearInterval(interval);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, self._reindexWait);
|
|
||||||
|
|
||||||
} else {
|
async.retry({times: 60, interval: 5000}, function(done) {
|
||||||
self._onReady(result, callback);
|
if (self.node.stopping) {
|
||||||
|
return done(new Error('Stopping while trying to connect to bitcoind.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.client = new BitcoinRPC({
|
||||||
|
protocol: config.rpcprotocol || 'http',
|
||||||
|
host: config.rpchost || '127.0.0.1',
|
||||||
|
port: config.rpcport,
|
||||||
|
user: config.rpcuser,
|
||||||
|
pass: config.rpcpassword
|
||||||
|
});
|
||||||
|
|
||||||
|
self._loadTipFromNode(node, done);
|
||||||
|
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
self._initZmqSubSocket(node, config.zmqpubrawtx);
|
||||||
|
|
||||||
|
callback(null, node);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by Node to start the service
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
Bitcoin.prototype.start = function(callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
function(next) {
|
||||||
|
if (self.options.spawn) {
|
||||||
|
self._spawnChildProcess(function(err, node) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
self.nodes.push(node);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(next) {
|
||||||
|
if (self.options.connect) {
|
||||||
|
async.map(self.options.connect, self._connectProcess.bind(self), function(err, nodes) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
for(var i = 0; i < nodes.length; i++) {
|
||||||
|
self.nodes.push(nodes[i]);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], function(err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
self._initChain(callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -950,15 +1095,15 @@ Bitcoin.prototype.getInfo = function(callback) {
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
Bitcoin.prototype.stop = function(callback) {
|
Bitcoin.prototype.stop = function(callback) {
|
||||||
if (this.process) {
|
if (this.spawn && this.spawn.process) {
|
||||||
this.process.once('exit', function(err, status) {
|
this.spawn.process.once('exit', function(err, status) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
} else {
|
} else {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.process.kill('SIGHUP');
|
this.spawn.process.kill('SIGHUP');
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^1.3.0",
|
"async": "^1.3.0",
|
||||||
"bindings": "^1.2.1",
|
|
||||||
"bitcoind-rpc": "^0.3.0",
|
"bitcoind-rpc": "^0.3.0",
|
||||||
"bitcore-lib": "^0.13.13",
|
"bitcore-lib": "^0.13.13",
|
||||||
"body-parser": "^1.13.3",
|
"body-parser": "^1.13.3",
|
||||||
|
@ -50,7 +49,6 @@
|
||||||
"express": "^4.13.3",
|
"express": "^4.13.3",
|
||||||
"liftoff": "^2.2.0",
|
"liftoff": "^2.2.0",
|
||||||
"lru-cache": "^4.0.1",
|
"lru-cache": "^4.0.1",
|
||||||
"memdown": "^1.0.0",
|
|
||||||
"mkdirp": "0.5.0",
|
"mkdirp": "0.5.0",
|
||||||
"npm": "^2.14.1",
|
"npm": "^2.14.1",
|
||||||
"semver": "^5.0.1",
|
"semver": "^5.0.1",
|
||||||
|
|
Loading…
Reference in New Issue