diff --git a/integration/data/bitcoin.conf b/integration/data/bitcoin.conf index ac6a7812..84aafd8c 100644 --- a/integration/data/bitcoin.conf +++ b/integration/data/bitcoin.conf @@ -1,9 +1,11 @@ server=1 whitelist=127.0.0.1 -rpcssl=1 -rpcsslcertificatechainfile=../bitcoind.crt -rpcsslprivatekeyfile=../bitcoind_no_pass.key txindex=1 +addressindex=1 +timestampindex=1 +zmqpubrawtx=tcp://127.0.0.1:30332 +zmqpubhashblock=tcp://127.0.0.1:30332 rpcallowip=127.0.0.1 +rpcport=30331 rpcuser=bitcoin rpcpassword=local321 diff --git a/integration/p2p.js b/integration/p2p.js index b578b908..3e30e464 100644 --- a/integration/p2p.js +++ b/integration/p2p.js @@ -3,10 +3,6 @@ var index = require('..'); var log = index.log; -if (process.env.BITCORENODE_ENV !== 'test') { - log.info('Please set the environment variable BITCORENODE_ENV=test and make sure bindings are compiled for testing'); - process.exit(); -} var p2p = require('bitcore-p2p'); var Peer = p2p.Peer; var Messages = p2p.Messages; @@ -58,18 +54,20 @@ describe('P2P Functionality', function() { var regtestNetwork = bitcore.Networks.get('regtest'); var datadir = __dirname + '/data'; - rimraf(datadir + '/regtest', function(err) {; - + rimraf(datadir + '/regtest', function(err) { if (err) { throw err; } + // enable regtest + bitcore.Networks.enableRegtest(); bitcoind = require('../').services.Bitcoin({ - node: { + spawn: { datadir: datadir, - network: { - name: 'regtest' - } + exec: 'bitcoind' + }, + node: { + network: bitcore.Networks.testnet } }); @@ -79,13 +77,16 @@ describe('P2P Functionality', function() { log.info('Waiting for Bitcoin Core to initialize...'); - bitcoind.start(function() { + bitcoind.start(function(err) { + if (err) { + throw err; + } log.info('Bitcoind started'); client = new BitcoinRPC({ - protocol: 'https', + protocol: 'http', host: '127.0.0.1', - port: 18332, + port: 30331, user: 'bitcoin', pass: 'local321', rejectUnauthorized: false @@ -186,13 +187,11 @@ describe('P2P Functionality', function() { var usedTxs = {}; - bitcoind.on('tx', function(result) { - var txFromResult = new Transaction().fromBuffer(result.buffer); + bitcoind.on('tx', function(buffer) { + var txFromResult = new Transaction().fromBuffer(buffer); var tx = usedTxs[txFromResult.id]; should.exist(tx); - result.buffer.toString('hex').should.equal(tx.serialize()); - result.hash.should.equal(tx.hash); - result.mempool.should.equal(true); + buffer.toString('hex').should.equal(tx.serialize()); delete usedTxs[tx.id]; if (Object.keys(usedTxs).length === 0) { done(); diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 8a1e9edb..3803ffa6 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -27,6 +27,7 @@ var Transaction = require('../transaction'); */ function Bitcoin(options) { /* jshint maxstatements: 20 */ + var self = this; if (!(this instanceof Bitcoin)) { return new Bitcoin(options); } @@ -46,6 +47,8 @@ function Bitcoin(options) { this.blockCache = LRU(144); this.blockHeaderCache = LRU(288); this.zmqKnownTransactions = LRU(50); + this.zmqLastBlock = 0; + this.zmqUpdateTipTimeout = false; this.options = options; @@ -57,8 +60,8 @@ function Bitcoin(options) { this.nodesIndex = 0; Object.defineProperty(this, 'client', { get: function() { - var client = this.nodes[this.nodesIndex].client; - this.nodesIndex = (this.nodesIndex + 1) % this.nodes.length; + var client = self.nodes[self.nodesIndex].client; + self.nodesIndex = (self.nodesIndex + 1) % self.nodes.length; return client; }, enumerable: true, @@ -218,38 +221,57 @@ Bitcoin.prototype._initChain = function(callback) { Bitcoin.prototype._getNetworkOption = function() { var networkOption; if (this.node.network === bitcore.Networks.testnet) { + networkOption = '--testnet'; if (this.node.network.regtestEnabled) { networkOption = '--regtest'; } - networkOption = '--testnet'; } return networkOption; }; Bitcoin.prototype._zmqBlockHandler = function(node, message) { var self = this; - var hex = message.toString('hex'); - if (hex !== self.tiphash) { - 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) { + function updateChain() { + var hex = message.toString('hex'); + if (hex !== self.tiphash) { + self._resetCaches(); + self.tiphash = message.toString('hex'); + node.client.getBlock(self.tiphash, function(err, response) { if (err) { return log.error(err); } - log.info('Bitcoin Height:', self.height, 'Percentage:', percentage.toFixed(2)); + self.height = response.result.height; + self.zmqLastBlock = new Date(); + $.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)); + }); + } } } + + // Prevent a rapid succession of updates with regtest + if (self.node.network.regtestEnabled) { + if (new Date() - self.zmqLastBlock > 1000) { + updateChain(); + } else { + clearTimeout(self.zmqUpdateTipTimeout); + self.zmqUpdateTipTimeout = setTimeout(function() { + updateChain(); + }, 1000); + } + } else { + updateChain(); + } + }; Bitcoin.prototype._zmqTransactionHandler = function(node, message) { @@ -325,7 +347,7 @@ Bitcoin.prototype._loadTipFromNode = function(node, callback) { } node.client.getBlock(response.result, function(err, response) { if (err) { - return done(err); + return callback(err); } self.height = response.result.height; $.checkState(self.height >= 0); @@ -464,6 +486,9 @@ Bitcoin.prototype.start = function(callback) { if (err) { return callback(err); } + if (self.nodes.length === 0) { + return callback(new Error('Bitcoin configuration options "spawn" or "connect" are expected')); + } self._initChain(callback); }); @@ -1107,7 +1132,7 @@ Bitcoin.prototype.stop = function(callback) { return callback(); } }); - this.spawn.process.kill('SIGHUP'); + this.spawn.process.kill('SIGINT'); } else { callback(); }