Fixed progress bar and added tests for getTransaction in

TransactionService.
This commit is contained in:
Chris Kleeschulte 2017-05-15 15:05:41 -04:00
parent 6d95cd0302
commit b6f56fb02b
6 changed files with 130 additions and 43 deletions

View File

@ -320,7 +320,7 @@ DB.prototype.loadTips = function(callback) {
} }
self[tip] = block; self[tip] = block;
log.info('loaded tip, hash: ' + block.hash + ' height: ' + block.__height); log.info('loaded ' + tip + ', hash: ' + block.hash + ' height: ' + block.__height);
next(); next();
}); });

View File

@ -7,7 +7,6 @@ var EventEmitter = require('events').EventEmitter;
var async = require('async'); var async = require('async');
var bitcore = require('bitcore-lib'); var bitcore = require('bitcore-lib');
var Block = bitcore.Block; var Block = bitcore.Block;
var ProgressBar = require('progress');
var index = require('../../index'); var index = require('../../index');
var log = index.log; var log = index.log;
@ -66,8 +65,7 @@ function Sync(node, db) {
this.syncing = false; this.syncing = false;
this.paused = false; //we can't sync while one of our indexes is reading/writing separate from us this.paused = false; //we can't sync while one of our indexes is reading/writing separate from us
this.highWaterMark = 10; this.highWaterMark = 10;
this.progressBar = null; this._lastReportedTime = Date.now();
this.lastReportedBlock = 0;
} }
inherits(Sync, EventEmitter); inherits(Sync, EventEmitter);
@ -98,16 +96,6 @@ Sync.prototype.sync = function() {
blockStream blockStream
.pipe(processSerial); .pipe(processSerial);
self.lastReportedBlock = self.db.tip.__height;
self.progressBar = new ProgressBar('[:bar] :percent :current blks, :blockspersec blks/sec', {
curr: self.lastReportedBlock,
total: self.node.services.bitcoind.height,
clear: true
});
self.progressBarTimer = setInterval(self.reportStatus.bind(self), 1000);
processSerial.on('finish', self._onFinish.bind(self)); processSerial.on('finish', self._onFinish.bind(self));
}; };
@ -117,14 +105,6 @@ Sync.prototype._onFinish = function() {
var self = this; var self = this;
self.syncing = false; self.syncing = false;
if (self.progressBar) {
self.progressBar.terminate();
}
if (self.progressBarTimer) {
clearInterval(self.progressBarTimer);
}
if (self.forkBlock) { if (self.forkBlock) {
self.db.handleReorg(self.forkBlock, function() { self.db.handleReorg(self.forkBlock, function() {
self.forkBlock = null; self.forkBlock = null;
@ -134,6 +114,7 @@ Sync.prototype._onFinish = function() {
} }
self._startSubscriptions(); self._startSubscriptions();
self._reportStatus(true);
self.emit('synced'); self.emit('synced');
}; };
@ -148,6 +129,7 @@ Sync.prototype._startSubscriptions = function() {
self.bus = self.node.openBus({remoteAddress: 'localhost'}); self.bus = self.node.openBus({remoteAddress: 'localhost'});
self.bus.on('bitcoind/hashblock', function() { self.bus.on('bitcoind/hashblock', function() {
self._reportStatus();
self.sync(); self.sync();
}); });
@ -156,12 +138,9 @@ Sync.prototype._startSubscriptions = function() {
}; };
Sync.prototype.reportStatus = function() { Sync.prototype._reportStatus = function(override) {
if (process.stderr.isTTY) { if (((Date.now() - this._lastReportedTime) > 1000) || override) {
var tick = this.db.tip.__height - this.lastReportedBlock; this._lastReportedTime = Date.now();
this.progressBar.tick(tick, { blockspersec: tick });
this.lastReportedBlock = this.db.tip.__height;
} else {
log.info('Sync: current height is: ' + this.db.tip.__height); log.info('Sync: current height is: ' + this.db.tip.__height);
} }
}; };

View File

@ -160,6 +160,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
}); });
} }
txid = txid.toString('hex');
var key = self.encoding.encodeTransactionKey(txid); var key = self.encoding.encodeTransactionKey(txid);
async.waterfall([ async.waterfall([
@ -178,22 +179,16 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
return next(null, tx); return next(null, tx);
} }
if (!options || !options.queryMempool) { if (!options || !options.queryMempool) {
return next(); return next(new Error('Transaction: ' + txid + ' not found in index'));
} }
self.node.services.mempool.getTransaction(txid, function(err, tx) { self.node.services.mempool.getTransaction(txid, function(err, tx) {
if(err) { if (err instanceof levelup.errors.NotFoundError) {
return next(err); return callback(new Error('Transaction: ' + txid + ' not found in index or mempool'));
} } else if (err) {
if (!tx) { return callback(err);
return next(); }
} self._getMissingInputValues(tx, next);
self._getMissingInputValues(tx, next);
}); });
}, function(tx, next) {
if (tx) {
return next(null, tx);
}
self.node.services.bitcoind.getTransaction(txid, next);
}], callback); }], callback);
}; };

View File

@ -60,7 +60,6 @@
"mkdirp": "0.5.0", "mkdirp": "0.5.0",
"multer": "^1.2.1", "multer": "^1.2.1",
"path-is-absolute": "^1.0.0", "path-is-absolute": "^1.0.0",
"progress": "kleetus/node-progress#master",
"semver": "^5.0.1", "semver": "^5.0.1",
"socket.io": "^1.4.5", "socket.io": "^1.4.5",
"socket.io-client": "^1.4.5", "socket.io-client": "^1.4.5",

View File

@ -8,7 +8,7 @@ var path = require('path');
var utils = require('./utils'); var utils = require('./utils');
var crypto = require('crypto'); var crypto = require('crypto');
var debug = false; var debug = true;
var bitcoreDataDir = '/tmp/bitcore'; var bitcoreDataDir = '/tmp/bitcore';
var bitcoinDataDir = '/tmp/bitcoin'; var bitcoinDataDir = '/tmp/bitcoin';

View File

@ -0,0 +1,114 @@
'use strict';
var should = require('chai').should();
var sinon = require('sinon');
var TransactionService = require('../../../lib/services/transaction');
var levelup = require('levelup');
describe('Transaction Index', function() {
describe('Failures', function() {
//if we miss indexing a tx, then this is very bad news. We have no good way of
//recursively retrieving inputValues, timestamp of its block, and block's height
it('should throw error if a transaction is not in the index', function(done) {
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError())
}
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = { encodeTransactionKey: function() { return 'key'; }};
var tx = service.getTransaction('1234', {}, function(err, res) {
err.should.be.an.instanceof(Error);
err.message.should.equal('Transaction: 1234 not found in index');
done();
});
});
it('should search the mempool if opted for', function(done) {
var getTransaction = sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError());
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError())
}
},
mempool: {
getTransaction: getTransaction
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = { encodeTransactionKey: function() { return 'key'; }};
var tx = service.getTransaction('1234', { queryMempool: true }, function(err, res) {
err.should.be.an.instanceof(Error);
err.message.should.equal('Transaction: 1234 not found in index or mempool');
done();
});
});
});
describe('Success', function() {
it('should search main index', function(done) {
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, null, 'tx')
}
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = {
encodeTransactionKey: function() { return 'key'; },
decodeTransactionValue: function() { return 'value'; }
};
var tx = service.getTransaction('1234', {}, function(err, res) {
if(err) {
return done(err);
}
res.should.equal('value');
done();
});
});
it('should search mempool', function(done) {
var missingInputs = sinon.stub().callsArgWith(1, null, 'tx');
var getTransaction = sinon.stub().callsArgWith(1, null, 'tx');
var services = {
db: {
store: {
get: sinon.stub().callsArgWith(1, new levelup.errors.NotFoundError())
}
},
mempool: {
getTransaction: getTransaction
}
};
var node = { node: { services: services }};
var service = new TransactionService(node);
service.encoding = {
encodeTransactionKey: function() { return 'key'; }
};
service._getMissingInputValues = missingInputs;
var tx = service.getTransaction('1234', { queryMempool: true }, function(err, res) {
if(err) {
return done(err);
}
missingInputs.callCount.should.equal(1);
res.should.equal('tx');
done();
});
});
});
});