This commit is contained in:
Chris Kleeschulte 2017-07-19 10:35:25 -04:00
parent aceddb12d9
commit 861a80d678
5 changed files with 260 additions and 18 deletions

View File

@ -31,8 +31,8 @@ Encoding.prototype.encodeAddressIndexKey = function(address, height, txid, index
inputBuffer.writeUInt8(input || 0);
buffers.push(inputBuffer);
var timestampBuffer = new Buffer(8);
timestampBuffer.writeDoubleBE(timestamp || 0)
var timestampBuffer = new Buffer(4);
timestampBuffer.writeUInt32BE(timestamp || 0);
buffers.push(timestampBuffer);
return Buffer.concat(buffers);
@ -46,7 +46,7 @@ Encoding.prototype.decodeAddressIndexKey = function(buffer) {
var txid = buffer.slice(addressSize + 8, addressSize + 40).toString('hex');
var index = buffer.readUInt32BE(addressSize + 40);
var input = buffer.readUInt8(addressSize + 44);
var timestamp = buffer.readDoubleBE(addressSize + 45);
var timestamp = buffer.readUInt32BE(addressSize + 45);
return {
address: address,
height: height,
@ -57,7 +57,7 @@ Encoding.prototype.decodeAddressIndexKey = function(buffer) {
};
};
Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex, timestamp) {
Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) {
var prefix = new Buffer('01', 'hex');
var buffers = [this.servicePrefix, prefix];
@ -97,15 +97,15 @@ Encoding.prototype.encodeUtxoIndexValue = function(height, satoshis, timestamp,
var satoshisBuffer = new Buffer(8);
satoshisBuffer.writeDoubleBE(satoshis);
var timestampBuffer = new Buffer(8);
timestampBuffer.writeDoubleBE(timestamp || 0)
timestampBuffer.writeUInt32BE(timestamp || 0)
return Buffer.concat([heightBuffer, satoshisBuffer, timestampBuffer, scriptBuffer]);
};
Encoding.prototype.decodeUtxoIndexValue = function(buffer) {
var height = buffer.readUInt32BE();
var satoshis = buffer.readDoubleBE(4);
var timestamp = buffer.readDoubleBE(12);
var scriptBuffer = buffer.slice(20);
var timestamp = buffer.readDoubleBE(8);
var scriptBuffer = buffer.slice(12);
return {
height: height,
satoshis: satoshis,

View File

@ -0,0 +1,50 @@
'use strict';
function Encoding(servicePrefix) {
this._servicePrefix = servicePrefix;
}
// ---- hash --> height
Encoding.prototype.encodeHeaderKey = function(hash) {
return Buffer.concat([ this._servicePrefix, new Buffer(hash, 'hex') ]);
};
Encoding.prototype.decodeHeaderKey = function(buffer) {
return buffer.slice(3).toString('hex');
};
Encoding.prototype.encodeHeaderValue = function(header) {
var versionBuf = new Buffer(4);
versionBuf.writeInt32BE(header.version);
var prevHash = new Buffer(header.prevHash, 'hex');
var merkleRoot = new Buffer(header.merkleRoot, 'hex');
var tsBuf = new Buffer(4);
tsBuf.writeUInt32BE(header.timestamp);
var bitsBuf = new Buffer(4);
bitsBuf.writeUInt32BE(header.bits);
var nonceBuf = new Buffer(4);
nonceBuf.writeUInt32BE(header.nonce);
return Buffer.concat([ versionBuf, prevHash, merkleRoot, tsBuf, bitsBuf, nonceBuf ]);
};
Encoding.prototype.decodeHeaderValue = function(buffer) {
var version = buffer.readInt32BE();
var prevHash = buffer.slice(4, 36).toString('hex');
var merkleRoot = buffer.slice(36, 68).toString('hex');
var ts = buffer.readUInt32BE(68);
var bits = buffer.readUInt32BE(72);
var nonce = buffer.readUInt32BE(76);
return {
version: version,
prevHash: prevHash,
merkleRoot: merkleRoot,
timestakmp: ts,
bits: bits,
nonce: nonce
};
};
module.exports = Encoding;

View File

@ -0,0 +1,192 @@
'use strict';
var BaseService = require('../../service');
var inherits = require('util').inherits;
var Encoding = require('./encoding');
var index = require('../../');
var log = index.log;
var utils = require('../../utils');
var constants = require('../../constants');
var HeaderService = function(options) {
BaseService.call(this, options);
this._tip = null;
this._p2p = this.node.services.p2p;
this._db = this.node.services.db;
};
inherits(HeaderService, BaseService);
HeaderService.dependencies = [ 'p2p', 'db' ];
// --- public prototype functions
HeaderService.prototype.getAPIMethods = function() {
var methods = [
['getAllHeaders', this, this.getHeaders, 0]
];
return methods;
};
HeaderService.prototype.start = function(callback) {
var self = this;
self._db.getPrefix(self.name, function(err, prefix) {
if(err) {
return callback(err);
}
self._db.getServiceTip(self.name, function(err, tip) {
if(err) {
return callback(err);
}
self._tip = tip;
self._encoding = new Encoding(prefix);
self._setListeners();
self._startSubscriptions();
callback();
});
});
};
HeaderService.prototype.stop = function(callback) {
callback();
};
HeaderService.prototype._startSubscriptions = function() {
if (this._subscribed) {
return;
}
this._subscribed = true;
if (!this._bus) {
this._bus = this.node.openBus({remoteAddress: 'localhost'});
}
this._bus.on('p2p/headers', this._onHeaders.bind(this));
this._bus.subscribe('p2p/headers');
};
HeaderService.prototype._onHeaders = function(headers) {
if (!headers || headers.length < 1) {
return;
}
this._tip.hash = headers[headers.length - 1].hash;
this._tip.height = this._tip.height + headers.length;
var operations = this._getHeaderOperations(headers);
var tipOps = utils.encodeTip(this._tip, this.name);
operations.push({
type: 'put',
key: tipOps.key,
value: tipOps.value
});
this._db.batch(operations);
if (this._tip.height >= this._bestHeight) {
log.info('Header download complete.');
this.emit('headers');
return;
}
this._sync();
};
HeaderService.prototype._getHeaderOperations = function(headers) {
var self = this;
return headers.map(function(header) {
return {
type: 'put',
key: self._encoding.encodeHeaderKey(header.hash),
value: self._encoding.encodeHeaderValue(header)
};
});
};
HeaderService.prototype._setListeners = function() {
this._p2p.once('bestHeight', this._onBestHeight.bind(this));
};
HeaderService.prototype._onBestHeight = function(height) {
this._bestHeight = height;
this._startSync();
};
HeaderService.prototype._startSync = function() {
this._numNeeded = this._bestHeight - this._tip.height;
if (this._numNeeded <= 0) {
return;
}
log.info('Gathering: ' + this._numNeeded + ' ' + 'header(s) from the peer-to-peer network.');
this._p2pHeaderCallsNeeded = Math.ceil(this._numNeeded / 500);
this._sync();
};
HeaderService.prototype._sync = function() {
if (--this._p2pHeaderCallsNeeded > 0) {
log.info('Headers download progress: ' + this._tip.height + '/' +
this._numNeeded + ' (' + (this._tip.height / this._numNeeded*100).toFixed(2) + '%)');
this._p2p.getHeaders({ startHash: this._tip.hash });
return;
}
};
HeaderService.prototype.getHeaders = function(callback) {
var self = this;
var results = [];
var start = self._encoding.encodeHeaderKey(0);
var stream = self._db.createReadStream(criteria);
var streamErr;
stream.on('error', function(error) {
streamErr = error;
});
stream.on('data', function(data) {
results.push({
hash: self.__encoding.decodeHeaderKey(data.key),
header: self._encoding.decodeHeaderValue(data.value)
});
});
stream.on('end', function() {
if (streamErr) {
return streamErr;
}
callback(null, results);
});
};
module.exports = HeaderService;

View File

@ -16,25 +16,25 @@ Encoding.prototype.decodeBlockTimestampKey = function(buffer) {
};
Encoding.prototype.encodeBlockTimestampValue = function(timestamp) {
var timestampBuffer = new Buffer(new Array(8));
timestampBuffer.writeDoubleBE(timestamp);
var timestampBuffer = new Buffer(4);
timestampBuffer.writeUInt32BE(timestamp);
return timestampBuffer;
};
Encoding.prototype.decodeBlockTimestampValue = function(buffer) {
return buffer.readDoubleBE();
return buffer.readUInt32BE();
};
// ---- timestamp -> block hash
Encoding.prototype.encodeTimestampBlockKey = function(timestamp) {
var timestampBuffer = new Buffer(new Array(8));
timestampBuffer.writeDoubleBE(timestamp);
var timestampBuffer = new Buffer(4);
timestampBuffer.writeUInt32BE(timestamp);
return Buffer.concat([this._servicePrefix, this._timestampPrefix, timestampBuffer]);
};
Encoding.prototype.decodeTimestampBlockKey = function(buffer) {
return buffer.readDoubleBE(3);
return buffer.readUInt32BE(3);
};
Encoding.prototype.encodeTimestampBlockValue = function(hash) {

View File

@ -18,8 +18,8 @@ Encoding.prototype.encodeTransactionValue = function(transaction) {
var heightBuffer = new Buffer(4);
heightBuffer.writeUInt32BE(transaction.__height);
var timestampBuffer = new Buffer(8);
timestampBuffer.writeDoubleBE(transaction.__timestamp);
var timestampBuffer = new Buffer(4);
timestampBuffer.writeUInt32BE(transaction.__timestamp);
var inputValues = transaction.__inputValues;
var inputValuesBuffer = new Buffer(8 * inputValues.length);
@ -31,14 +31,14 @@ Encoding.prototype.encodeTransactionValue = function(transaction) {
inputValuesLengthBuffer.writeUInt16BE(inputValues.length);
return new Buffer.concat([heightBuffer, timestampBuffer,
inputValuesLengthBuffer, inputValuesBuffer, transaction.toBuffer()]);
inputValuesLengthBuffer, inputValuesBuffer, transaction.toRaw()]);
};
Encoding.prototype.decodeTransactionValue = function(buffer) {
var height = buffer.readUInt32BE();
var timestamp = buffer.readDoubleBE(4);
var timestamp = buffer.readUInt32BE(4);
var inputValuesLength = buffer.readUInt16BE(12);
var inputValuesLength = buffer.readUInt16BE(8);
var inputValues = [];
for(var i = 0; i < inputValuesLength; i++) {
inputValues.push(buffer.readDoubleBE(i * 8 + 14));