Added fixes for reorg and added time since last block.

This commit is contained in:
Chris Kleeschulte 2017-09-26 11:05:24 -04:00
parent f5ad8b89fb
commit ee97cb5b12
No known key found for this signature in database
GPG Key ID: 33195D27EF6BDB7F
8 changed files with 60 additions and 147 deletions

135
:
View File

@ -1,135 +0,0 @@
'use strict';
var BaseService = require('../../service');
var util = require('util');
var Encoding = require('./encoding');
var log = require('../..').log;
var MempoolService = function(options) {
BaseService.call(this, options);
this._subscriptions = {};
this._subscriptions.transaction = [];
this._db = this.node.services.db;
this._p2p = this.node.services.p2p;
};
util.inherits(MempoolService, BaseService);
MempoolService.dependencies = ['db'];
MempoolService.prototype.getAPIMethods = function() {
var methods = [
['getMempoolTransaction', this, this.getMempoolTransaction, 1]
];
return methods;
};
MempoolService.prototype.start = function(callback) {
var self = this;
self._db.getPrefix(self.name, function(err, prefix) {
if(err) {
return callback(err);
}
self._encoding = new Encoding(prefix);
self._startSubscriptions();
callback();
});
};
MempoolService.prototype.onReorg = function(args, callback) {
var oldBlockList = args[1];
var removalOps = [];
for(var i = 0; i < oldBlockList.length; i++) {
var block = oldBlockList[i];
for(var j = 0; j < block.txs.length; j++) {
var tx = block.txs[j];
var key = this._encoding.encodeMempoolTransactionKey(tx.txid());
var value = this._encoding.encodeMempoolTransactionValue(tx);
removalOps.push({
type: 'put',
key: key,
value: value
});
}
}
setImmediate(function() {
callback(null, removalOps);
});
};
MempoolService.prototype._startSubscriptions = function() {
var self = this;
if (self._subscribed) {
return;
}
self._subscribed = true;
if (!self._bus) {
self._bus = self.node.openBus({remoteAddress: 'localhost-mempool'});
}
self._bus.on('p2p/transaction', self._onTransaction.bind(self));
self._bus.subscribe('p2p/transaction');
self._p2p.on('bestHeight', function() {
log.info('Mempool Service: Geting mempool from peer.');
self._p2p.getMempool();
});
};
MempoolService.prototype.onBlock = function(block, callback) {
// remove this block's txs from mempool
var self = this;
var ops = block.txs.map(function(tx) {
return {
type: 'del',
key: self._encoding.encodeMempoolTransactionKey(tx.txid())
};
});
callback(null, ops);
};
MempoolService.prototype._onTransaction = function(tx) {
this._db.put(this._encoding.encodeMempoolTransactionKey(tx.txid()),
this._encoding.encodeMempoolTransactionValue(tx));
};
MempoolService.prototype.getMempoolTransaction = function(txid, callback) {
var self = this;
self._db.get(self._encoding.encodeMempoolTransactionKey(txid), function(err, tx) {
if (err) {
return callback(err);
}
if (!tx) {
return callback();
}
callback(null, self._encoding.decodeMempoolTransactionValue(tx));
});
};
MempoolService.prototype.stop = function(callback) {
callback();
};
module.exports = MempoolService;

View File

@ -188,6 +188,7 @@ BlockService.prototype._checkTip = function(callback) {
return callback();
}
log.warn('Block Service: reorganization spotted...');
self._findCommonAncestor(function(err, commonAncestorHash) {
if(err) {
return callback(err);
@ -366,11 +367,9 @@ BlockService.prototype._queueBlock = function(block) {
return self._handleError(err);
}
if (Date.now() - self._timeOfLastBlockReport > 30000) { // 30 seconds
self._timeOfLastBlockReport = Date.now();
log.info('Block Service: The best block hash is: ' + self._tip.hash +
' at height: ' + self._tip.height);
}
log.info('Block Service: The best block hash is: ' + self._tip.hash +
' at height: ' + self._tip.height + ' Time since last block: ' + utils.convertMillisecondsToHumanReadable(Date.now() - self._timeOfLastBlockReport));
self._timeOfLastBlockReport = Date.now();
log.debug('Block Service: completed processing block: ' + block.rhash() +
' prev hash: ' + bcoin.util.revHex(block.prevBlock) + ' height: ' + self._tip.height);

View File

@ -67,7 +67,7 @@ Encoding.prototype.decodeHeaderValue = function(buffer) {
var bits = buffer.readUInt32BE(104);
var nonce = buffer.readUInt32BE(108);
var height = buffer.readUInt32BE(112);
var chainwork = buffer.slice(116).toString('hex');
var chainwork = buffer.slice(116, 116 + 32).toString('hex');
var nextHash = buffer.slice(116 + 32).toString('hex');
return {
hash: hash,

View File

@ -395,7 +395,10 @@ HeaderService.prototype._getDBOpForLastHeader = function(nextHeader) {
// then put operation for the updated last header (with the next hash)
this._lastHeader.nextHash = nextHeader.hash;
var keyHash = this._encoding.encodeHeaderHashKey(this._lastHeader.hash);
var keyHeight = this._encoding.encodeHeaderHeightKey(this._lastHeader.hash);
assert(this._lastHeader.height >= 0, 'Trying to save a header with incorrect height.');
var keyHeight = this._encoding.encodeHeaderHeightKey(this._lastHeader.height);
var value = this._encoding.encodeHeaderValue(this._lastHeader);
return [
{
@ -596,7 +599,7 @@ HeaderService.prototype._detectReorg = function(block, callback) {
return callback(null, header);
}
log.warn('Block: ' + block.rhash() + 'references: ' + prevHash +
log.warn('Block: ' + block.rhash() + ' references: ' + prevHash +
' as its previous block, yet we have not stored this block in our data set, thus ignoring this block.');
callback(null, false);

View File

@ -103,4 +103,34 @@ utils.SimpleMap = function SimpleMap() {
};
};
utils.convertMillisecondsToHumanReadable = function(ms) {
var ret = '';
if (!ms && ms !== 0) {
return 'invalid number of ms.';
}
if (ms >= 60000) {
var minutes = Math.floor(ms / 60000);
var ms = ms % 60000;
}
if (ms >= 1000) {
var seconds = Math.floor(ms / 1000);
var ms = ms % 1000;
}
if (minutes) {
ret = minutes + ' minute(s). ';
}
if (seconds) {
ret += seconds + ' second(s). ';
}
ret += ms + ' millisecond(s).';
return ret;
};
module.exports = utils;

View File

@ -22,10 +22,12 @@ describe('Header service encoding', function() {
bits: 400000,
nonce: 123456,
height: 123,
chainwork: '0000000000000000000000000000000000000000000000000000000200020002'
chainwork: '0000000000000000000000000000000000000000000000000000000200020002',
nextHash: '91b58f19b6eecba94ed0f6e463e8e334ec0bcda7880e2985c82a8f32e4d03ade'
};
var versionBuf = new Buffer(4);
var prevHashBuf = new Buffer(header.prevHash, 'hex');
var nextHashBuf = new Buffer(header.nextHash, 'hex');
var merkleRootBuf = new Buffer(header.merkleRoot, 'hex');
var tsBuf = new Buffer(4);
var bitsBuf = new Buffer(4);
@ -67,7 +69,8 @@ describe('Header service encoding', function() {
bitsBuf,
nonceBuf,
heightBuf,
chainBuf
chainBuf,
nextHashBuf
]));
});
@ -81,7 +84,8 @@ describe('Header service encoding', function() {
bitsBuf,
nonceBuf,
heightBuf,
chainBuf
chainBuf,
nextHashBuf
])).should.deep.equal(header);
});
});

View File

@ -134,7 +134,8 @@ describe('Header Service', function() {
var saveHeaders = sandbox.stub(headerService, '_saveHeaders');
headerService._tip = { height: 123, hash: 'aa' };
headerService._lastHeader = { hash: header.prevHash };
var lastHeader = Object.assign({ height: 1, chainwork: new Array(65).join('0') }, prevHeader);
headerService._lastHeader = lastHeader;
headerService._onHeaders(headers);

View File

@ -122,4 +122,15 @@ describe('Utils', function() {
map.getLastIndex().should.equal('last value');
});
});
describe('#convertMillisecondsToHumanReadable', function() {
it('should convert a number of milliseconds to human readable format', function() {
var actual1 = utils.convertMillisecondsToHumanReadable(164532);
actual1.should.equal('2 minute(s). 44 second(s). 532 millisecond(s).');
var actual2 = utils.convertMillisecondsToHumanReadable(1);
actual2.should.equal('1 millisecond(s).');
var actual3 = utils.convertMillisecondsToHumanReadable(null);
actual3.should.equal('invalid number of ms.');
});
});
});