Added fixes for reorg and added time since last block.
This commit is contained in:
parent
f5ad8b89fb
commit
ee97cb5b12
135
:
135
:
@ -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;
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
30
lib/utils.js
30
lib/utils.js
@ -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;
|
||||
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user