Refactored onHeaders.
This commit is contained in:
parent
c7ee57f224
commit
a1fbf20317
@ -1,22 +0,0 @@
|
||||
{
|
||||
"network": "regtest",
|
||||
"port": 3001,
|
||||
"datadir": "/Users/chrisk",
|
||||
"services": [
|
||||
"p2p",
|
||||
"db",
|
||||
"transaction",
|
||||
"timestamp",
|
||||
"address",
|
||||
"mempool",
|
||||
"wallet-api",
|
||||
"web"
|
||||
],
|
||||
"servicesConfig": {
|
||||
"p2p": {
|
||||
"connect": [
|
||||
{ "rpchost": "127.0.0.1", "rpcport": 58332, "rpcuser": "bitcoin", "rpcpassword": "local321", "zmqpubrawtx": "tcp://127.0.0.1:28332" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,6 @@ var BN = require('bn.js');
|
||||
var consensus = require('bcoin').consensus;
|
||||
var assert = require('assert');
|
||||
var constants = require('../../constants');
|
||||
var Header = require('bitcore-lib').BlockHeader;
|
||||
|
||||
var HeaderService = function(options) {
|
||||
|
||||
@ -26,6 +25,7 @@ var HeaderService = function(options) {
|
||||
this.subscriptions.block = [];
|
||||
this._checkpoint = options.checkpoint || 2000;
|
||||
this.GENESIS_HASH = constants.BITCOIN_GENESIS_HASH[this.node.network];
|
||||
this._initiallySynced = false;
|
||||
};
|
||||
|
||||
inherits(HeaderService, BaseService);
|
||||
@ -97,7 +97,7 @@ HeaderService.prototype.start = function(callback) {
|
||||
log.debug('Header Service: original tip height is: ' + self._tip.height);
|
||||
log.debug('Header Service: original tip hash is: ' + self._tip.hash);
|
||||
|
||||
self._originalTip = Object.assign(self._tip, {});
|
||||
self._originalTip = { height: self._tip.height, hash: self._tip.hash };
|
||||
|
||||
if (self._tip.height === 0) {
|
||||
|
||||
@ -134,7 +134,8 @@ HeaderService.prototype.start = function(callback) {
|
||||
}
|
||||
|
||||
self._setListeners();
|
||||
self._startSubscriptions();
|
||||
self._bus = self.node.openBus({remoteAddress: 'localhost-header'});
|
||||
self._startHeaderSubscription();
|
||||
callback();
|
||||
|
||||
});
|
||||
@ -145,23 +146,11 @@ HeaderService.prototype.stop = function(callback) {
|
||||
setImmediate(callback);
|
||||
};
|
||||
|
||||
HeaderService.prototype._startSubscriptions = function() {
|
||||
HeaderService.prototype._startHeaderSubscription = function() {
|
||||
|
||||
if (this._subscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._subscribed = true;
|
||||
|
||||
if (!this._bus) {
|
||||
this._bus = this.node.openBus({remoteAddress: 'localhost-header'});
|
||||
}
|
||||
|
||||
this._bus.on('p2p/headers', this._onHeaders.bind(this));
|
||||
this._bus.on('p2p/block', this._onBlock.bind(this));
|
||||
|
||||
this._bus.subscribe('p2p/headers');
|
||||
this._bus.subscribe('p2p/block');
|
||||
|
||||
};
|
||||
|
||||
@ -184,13 +173,10 @@ HeaderService.prototype._onBlock = function(block) {
|
||||
|
||||
log.debug('Header Service: new block: ' + hash);
|
||||
|
||||
var header = this._headers.get(hash);
|
||||
if (!header) {
|
||||
header = block.toHeaders().toJSON();
|
||||
header.timestamp = header.ts;
|
||||
header.prevHash = header.prevBlock;
|
||||
this._onHeaders([header]);
|
||||
}
|
||||
var header = block.toHeaders().toJSON();
|
||||
header.timestamp = header.ts;
|
||||
header.prevHash = header.prevBlock;
|
||||
this._saveHeaders([this._onHeader(header)]);
|
||||
|
||||
for (var i = 0; i < this.subscriptions.block.length; i++) {
|
||||
var prevHeader = this._headers.get(header.prevHash);
|
||||
@ -198,54 +184,59 @@ HeaderService.prototype._onBlock = function(block) {
|
||||
block.height = prevHeader.height + 1;
|
||||
this.subscriptions.block[i].emit('header/block', block, header);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
HeaderService.prototype._onHeader = function(header) {
|
||||
|
||||
var prevHeader = this._headers.get(header.prevHash);
|
||||
assert(prevHeader, 'We must have a previous header in order to calculate this header\'s data, current header is: ' + header.hash);
|
||||
|
||||
header.height = prevHeader.height + 1;
|
||||
header.chainwork = this._getChainwork(header, prevHeader).toString(16, 64);
|
||||
|
||||
var newHdr = {
|
||||
hash: header.hash,
|
||||
prevHash: header.prevHash,
|
||||
height: header.height,
|
||||
chainwork: header.chainwork
|
||||
};
|
||||
|
||||
this._headers.set(header.hash, newHdr, header.height);
|
||||
|
||||
return {
|
||||
type: 'put',
|
||||
key: this._encoding.encodeHeaderKey(header.height, header.hash),
|
||||
value: this._encoding.encodeHeaderValue(header)
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
HeaderService.prototype._onHeaders = function(headers) {
|
||||
|
||||
var self = this;
|
||||
|
||||
log.debug('Header Service: Received: ' + headers.length + ' header(s).');
|
||||
|
||||
var dbOps = [];
|
||||
var headerListLength = 0;
|
||||
|
||||
for(var i = 0; i < headers.length; i++) {
|
||||
|
||||
var header = headers[i];
|
||||
|
||||
// headers that come from a call to getheaders and not a new block comoing in
|
||||
if (header instanceof Header) {
|
||||
header = header.toObject();
|
||||
self._tip.height++;
|
||||
self._tip.hash = header.hash;
|
||||
headerListLength = headers.length;
|
||||
}
|
||||
header = header.toObject();
|
||||
|
||||
var prevHeader = self._headers.get(header.prevHash);
|
||||
assert(prevHeader, 'We must have a previous header in order to calculate this header\'s data.');
|
||||
dbOps.push(this._onHeader(header));
|
||||
|
||||
header.height = prevHeader.height + 1;
|
||||
header.chainwork = self._getChainwork(header, prevHeader).toString(16, 64);
|
||||
|
||||
var newHdr = {
|
||||
hash: header.hash,
|
||||
prevHash: header.prevHash,
|
||||
height: header.height,
|
||||
chainwork: header.chainwork
|
||||
};
|
||||
|
||||
// note: this could lead to nulls in positions we don't yet have headers for
|
||||
// that should be ok because eventually all the missing headers will fill in
|
||||
self._headers.set(header.hash, newHdr, header.height);
|
||||
|
||||
dbOps.push({
|
||||
type: 'put',
|
||||
key: self._encoding.encodeHeaderKey(header.height, header.hash),
|
||||
value: self._encoding.encodeHeaderValue(header)
|
||||
});
|
||||
this._tip.height = header.height;
|
||||
this._tip.hash = header.hash;
|
||||
}
|
||||
|
||||
var tipOps = utils.encodeTip(self._tip, self.name);
|
||||
this._saveHeaders(dbOps);
|
||||
|
||||
};
|
||||
|
||||
HeaderService.prototype._saveHeaders = function(dbOps) {
|
||||
|
||||
var tipOps = utils.encodeTip(this._tip, this.name);
|
||||
|
||||
dbOps.push({
|
||||
type: 'put',
|
||||
@ -253,47 +244,71 @@ HeaderService.prototype._onHeaders = function(headers) {
|
||||
value: tipOps.value
|
||||
});
|
||||
|
||||
self._db.batch(dbOps, function(err) {
|
||||
this._db.batch(dbOps, this._onHeadersSave.bind(this));
|
||||
};
|
||||
|
||||
HeaderService.prototype._onHeadersSave = function(err) {
|
||||
|
||||
if(err) {
|
||||
log.error(err);
|
||||
self.node.stop();
|
||||
this.node.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// once we've received less than 2000 headers, we know we are fully sync as far as headers
|
||||
// if we reveive 2000 headers and there are no more after that, (the best height is a multiple of 2000),
|
||||
// then we'll just wait for the next block to come in. This should be pretty rare occurrence
|
||||
if (!this._syncComplete()) {
|
||||
|
||||
if (headerListLength === 2000) {
|
||||
self._sync();
|
||||
this._sync();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
assert(!this._headers.hasNullItems(), 'Header list is not complete yet peer has sent all available headers.');
|
||||
|
||||
this._startBlockSubscription();
|
||||
|
||||
this._setBestHeader();
|
||||
|
||||
if (this._detectReorg()) {
|
||||
this._handleReorg();
|
||||
return;
|
||||
}
|
||||
|
||||
// at this point, we should have no empty items in this._headers, everything should be filled in
|
||||
assert(!self._headers.hasNullItems(), 'Header list is not complete yet peer has sent all available headers.');
|
||||
|
||||
var bestHeader = self._headers.getLastIndex();
|
||||
self._tip.height = bestHeader.height;
|
||||
self._tip.hash = bestHeader.hash;
|
||||
|
||||
log.debug('Header Service: ' + bestHeader.hash + ' is the best block hash.');
|
||||
|
||||
// at this point, we can check our header list to see if our starting tip diverged from the tip
|
||||
// that we have now
|
||||
if (self._detectReorg()) {
|
||||
self._handleReorg();
|
||||
return;
|
||||
}
|
||||
this._populateNextHashes();
|
||||
|
||||
log.debug('Header Service: emitting headers to block service.');
|
||||
// populate next hash fields on each header
|
||||
self._populateNextHashes();
|
||||
this._populateNextHashes();
|
||||
|
||||
self.emit('headers', self._headers);
|
||||
this.emit('headers', this._headers);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
HeaderService.prototype._startBlockSubscription = function() {
|
||||
|
||||
if (this._subscribedBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._subscribedBlock = true;
|
||||
|
||||
this._bus.on('p2p/block', this._onBlock.bind(this));
|
||||
this._bus.subscribe('p2p/block');
|
||||
|
||||
};
|
||||
|
||||
HeaderService.prototype._syncComplete = function() {
|
||||
|
||||
return this._tip.height >= this._bestHeight;
|
||||
|
||||
};
|
||||
|
||||
|
||||
HeaderService.prototype._setBestHeader = function() {
|
||||
|
||||
var bestHeader = this._headers.getLastIndex();
|
||||
this._tip.height = bestHeader.height;
|
||||
this._tip.hash = bestHeader.hash;
|
||||
|
||||
log.debug('Header Service: ' + bestHeader.hash + ' is the best block hash.');
|
||||
};
|
||||
|
||||
HeaderService.prototype._populateNextHashes = function() {
|
||||
|
||||
32
package-lock.json
generated
32
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bitcore-node",
|
||||
"version": "4.0.0",
|
||||
"version": "5.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -828,21 +828,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"deferred-leveldown": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.1.tgz",
|
||||
"integrity": "sha1-XSXDMQ9f6QmUb2JA3J+Q3RCace8=",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz",
|
||||
"integrity": "sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==",
|
||||
"requires": {
|
||||
"abstract-leveldown": "2.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"abstract-leveldown": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.4.1.tgz",
|
||||
"integrity": "sha1-s7/tuITraToSd18MVenwpCDM7mQ=",
|
||||
"requires": {
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
}
|
||||
"abstract-leveldown": "2.6.1"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
@ -2148,7 +2138,7 @@
|
||||
"resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz",
|
||||
"integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==",
|
||||
"requires": {
|
||||
"deferred-leveldown": "1.2.1",
|
||||
"deferred-leveldown": "1.2.2",
|
||||
"level-codec": "7.0.0",
|
||||
"level-errors": "1.0.4",
|
||||
"level-iterator-stream": "1.3.1",
|
||||
@ -2161,11 +2151,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
||||
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -3120,6 +3105,11 @@
|
||||
"prebuild-install": "2.2.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
||||
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.15.3.tgz",
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
var path = require('path');
|
||||
var defaultBaseConfig = require('../../lib/scaffold/default-base-config');
|
||||
|
||||
describe('#defaultBaseConfig', function() {
|
||||
it('will return expected configuration', function() {
|
||||
var cwd = process.cwd();
|
||||
var home = process.env.HOME;
|
||||
var info = defaultBaseConfig();
|
||||
info.path.should.equal(cwd);
|
||||
info.config.network.should.equal('livenet');
|
||||
info.config.port.should.equal(3001);
|
||||
info.config.services.should.deep.equal(['bitcoind', 'web']);
|
||||
var bitcoind = info.config.servicesConfig.bitcoind;
|
||||
bitcoind.spawn.datadir.should.equal(home + '/.bitcoin');
|
||||
bitcoind.spawn.exec.should.equal(path.resolve(__dirname, '../../bin/bitcoind'));
|
||||
});
|
||||
it('be able to specify a network', function() {
|
||||
var info = defaultBaseConfig({network: 'testnet'});
|
||||
info.config.network.should.equal('testnet');
|
||||
});
|
||||
it('be able to specify a datadir', function() {
|
||||
var info = defaultBaseConfig({datadir: './data2', network: 'testnet'});
|
||||
info.config.servicesConfig.bitcoind.spawn.datadir.should.equal('./data2');
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user