wip
This commit is contained in:
parent
861a80d678
commit
de4c59f958
@ -96,16 +96,16 @@ Encoding.prototype.encodeUtxoIndexValue = function(height, satoshis, timestamp,
|
||||
heightBuffer.writeUInt32BE(height);
|
||||
var satoshisBuffer = new Buffer(8);
|
||||
satoshisBuffer.writeDoubleBE(satoshis);
|
||||
var timestampBuffer = new Buffer(8);
|
||||
timestampBuffer.writeUInt32BE(timestamp || 0)
|
||||
var timestampBuffer = new Buffer(4);
|
||||
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(8);
|
||||
var scriptBuffer = buffer.slice(12);
|
||||
var timestamp = buffer.readUInt32BE(12);
|
||||
var scriptBuffer = buffer.slice(16);
|
||||
return {
|
||||
height: height,
|
||||
satoshis: satoshis,
|
||||
|
||||
@ -6,13 +6,13 @@ function Encoding(servicePrefix) {
|
||||
}
|
||||
|
||||
|
||||
// ---- hash --> height
|
||||
// ---- hash --> header
|
||||
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');
|
||||
return buffer.slice(2).toString('hex');
|
||||
};
|
||||
|
||||
Encoding.prototype.encodeHeaderValue = function(header) {
|
||||
@ -26,7 +26,9 @@ Encoding.prototype.encodeHeaderValue = function(header) {
|
||||
bitsBuf.writeUInt32BE(header.bits);
|
||||
var nonceBuf = new Buffer(4);
|
||||
nonceBuf.writeUInt32BE(header.nonce);
|
||||
return Buffer.concat([ versionBuf, prevHash, merkleRoot, tsBuf, bitsBuf, nonceBuf ]);
|
||||
var heightBuf = new Buffer(4);
|
||||
heightBuf.writeUInt32BE(header.height);
|
||||
return Buffer.concat([ versionBuf, prevHash, merkleRoot, tsBuf, bitsBuf, nonceBuf, heightBuf ]);
|
||||
};
|
||||
|
||||
Encoding.prototype.decodeHeaderValue = function(buffer) {
|
||||
@ -36,13 +38,15 @@ Encoding.prototype.decodeHeaderValue = function(buffer) {
|
||||
var ts = buffer.readUInt32BE(68);
|
||||
var bits = buffer.readUInt32BE(72);
|
||||
var nonce = buffer.readUInt32BE(76);
|
||||
var height = buffer.readUInt32BE(80);
|
||||
return {
|
||||
version: version,
|
||||
prevHash: prevHash,
|
||||
merkleRoot: merkleRoot,
|
||||
timestakmp: ts,
|
||||
timestamp: ts,
|
||||
bits: bits,
|
||||
nonce: nonce
|
||||
nonce: nonce,
|
||||
height: height
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@ var Encoding = require('./encoding');
|
||||
var index = require('../../');
|
||||
var log = index.log;
|
||||
var utils = require('../../utils');
|
||||
var constants = require('../../constants');
|
||||
|
||||
var HeaderService = function(options) {
|
||||
|
||||
@ -26,7 +25,7 @@ HeaderService.dependencies = [ 'p2p', 'db' ];
|
||||
HeaderService.prototype.getAPIMethods = function() {
|
||||
|
||||
var methods = [
|
||||
['getAllHeaders', this, this.getHeaders, 0]
|
||||
['getAllHeaders', this, this.getAllHeaders, 0]
|
||||
];
|
||||
|
||||
return methods;
|
||||
@ -112,7 +111,9 @@ HeaderService.prototype._onHeaders = function(headers) {
|
||||
HeaderService.prototype._getHeaderOperations = function(headers) {
|
||||
|
||||
var self = this;
|
||||
var runningHeight = this._tip.height;
|
||||
return headers.map(function(header) {
|
||||
header.height = ++runningHeight;
|
||||
return {
|
||||
type: 'put',
|
||||
key: self._encoding.encodeHeaderKey(header.hash),
|
||||
@ -153,18 +154,26 @@ HeaderService.prototype._sync = function() {
|
||||
|
||||
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) {
|
||||
HeaderService.prototype.getAllHeaders = function(callback) {
|
||||
|
||||
var self = this;
|
||||
var results = [];
|
||||
var start = self._encoding.encodeHeaderKey(0);
|
||||
var end = self._encoding.encodeHeaderKey(0xffffffff);
|
||||
var criteria = {
|
||||
gte: start,
|
||||
lte: end
|
||||
};
|
||||
|
||||
var stream = self._db.createReadStream(criteria);
|
||||
|
||||
var streamErr;
|
||||
@ -173,10 +182,9 @@ HeaderService.prototype.getHeaders = function(callback) {
|
||||
});
|
||||
|
||||
stream.on('data', function(data) {
|
||||
results.push({
|
||||
hash: self.__encoding.decodeHeaderKey(data.key),
|
||||
header: self._encoding.decodeHeaderValue(data.value)
|
||||
});
|
||||
var res = {};
|
||||
res[self._encoding.decodeHeaderKey(data.key)] = self._encoding.decodeHeaderValue(data.value);
|
||||
results.push(res);
|
||||
});
|
||||
|
||||
stream.on('end', function() {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var tx = require('bcoin').tx;
|
||||
var Tx = require('bcoin').tx;
|
||||
|
||||
function Encoding(servicePrefix) {
|
||||
this.servicePrefix = servicePrefix;
|
||||
@ -41,9 +41,11 @@ Encoding.prototype.decodeTransactionValue = function(buffer) {
|
||||
var inputValuesLength = buffer.readUInt16BE(8);
|
||||
var inputValues = [];
|
||||
for(var i = 0; i < inputValuesLength; i++) {
|
||||
inputValues.push(buffer.readDoubleBE(i * 8 + 14));
|
||||
inputValues.push(buffer.readDoubleBE(i * 8 + 10));
|
||||
}
|
||||
var transaction = tx.fromRaw(buffer.slice(inputValues.length * 8 + 14));
|
||||
|
||||
var txBuf = buffer.slice(inputValues.length * 8 + 10);
|
||||
var transaction = Tx.fromRaw(txBuf);
|
||||
|
||||
transaction.__height = height;
|
||||
transaction.__inputValues = inputValues;
|
||||
|
||||
@ -15,8 +15,8 @@ describe('Address service encoding', function() {
|
||||
var prefix0 = new Buffer('00', 'hex');
|
||||
var prefix1 = new Buffer('01', 'hex');
|
||||
var ts = Math.floor(new Date('2017-02-28').getTime() / 1000);
|
||||
var tsBuf = new Buffer(8);
|
||||
tsBuf.writeDoubleBE(ts);
|
||||
var tsBuf = new Buffer(4);
|
||||
tsBuf.writeUInt32BE(ts);
|
||||
addressSizeBuf.writeUInt8(address.length);
|
||||
var addressIndexKeyBuf = Buffer.concat([
|
||||
servicePrefix,
|
||||
|
||||
70
test/services/header/encoding.unit.js
Normal file
70
test/services/header/encoding.unit.js
Normal file
@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
|
||||
var Encoding = require('../../../lib/services/header/encoding');
|
||||
|
||||
describe('Header service encoding', function() {
|
||||
|
||||
var servicePrefix = new Buffer('0000', 'hex');
|
||||
var encoding = new Encoding(servicePrefix);
|
||||
var hash = '91b58f19b6eecba94ed0f6e463e8e334ec0bcda7880e2985c82a8f32e4d03add';
|
||||
var header = {
|
||||
prevHash: '91b58f19b6eecba94ed0f6e463e8e334ec0bcda7880e2985c82a8f32e4d03ade',
|
||||
version: 0x2000012,
|
||||
merkleRoot: '91b58f19b6eecba94ed0f6e463e8e334ec0bcda7880e2985c82a8f32e4d03adf',
|
||||
timestamp: 1E9,
|
||||
bits: 400000,
|
||||
nonce: 123456,
|
||||
height: 123
|
||||
};
|
||||
var versionBuf = new Buffer(4);
|
||||
var prevHash = new Buffer(header.prevHash, 'hex');
|
||||
var merkleRoot = new Buffer(header.merkleRoot, 'hex');
|
||||
var tsBuf = new Buffer(4);
|
||||
var bitsBuf = new Buffer(4);
|
||||
var nonceBuf = new Buffer(4);
|
||||
var heightBuf = new Buffer(4);
|
||||
|
||||
it('should encode header key' , function() {
|
||||
var hashBuf = new Buffer(hash, 'hex');
|
||||
encoding.encodeHeaderKey(hash).should.deep.equal(Buffer.concat([servicePrefix, hashBuf]));
|
||||
});
|
||||
|
||||
it('should decode header key', function() {
|
||||
var hashBuf = new Buffer(hash, 'hex');
|
||||
encoding.decodeHeaderKey(Buffer.concat([servicePrefix, hashBuf]))
|
||||
.should.equal(hash);
|
||||
});
|
||||
|
||||
it('should encode header value', function() {
|
||||
versionBuf.writeInt32BE(header.version); // signed
|
||||
tsBuf.writeUInt32BE(header.timestamp);
|
||||
bitsBuf.writeUInt32BE(header.bits);
|
||||
nonceBuf.writeUInt32BE(header.nonce);
|
||||
heightBuf.writeUInt32BE(header.height);
|
||||
encoding.encodeHeaderValue(header).should.deep.equal(Buffer.concat([
|
||||
versionBuf,
|
||||
prevHash,
|
||||
merkleRoot,
|
||||
tsBuf,
|
||||
bitsBuf,
|
||||
nonceBuf,
|
||||
heightBuf
|
||||
]));
|
||||
|
||||
});
|
||||
|
||||
it('should decode header value', function() {
|
||||
encoding.decodeHeaderValue(Buffer.concat([
|
||||
versionBuf,
|
||||
prevHash,
|
||||
merkleRoot,
|
||||
tsBuf,
|
||||
bitsBuf,
|
||||
nonceBuf,
|
||||
heightBuf
|
||||
])).should.deep.equal(header);
|
||||
});
|
||||
});
|
||||
|
||||
137
test/services/header/index.unit.js
Normal file
137
test/services/header/index.unit.js
Normal file
@ -0,0 +1,137 @@
|
||||
'use strict';
|
||||
|
||||
var sinon = require('sinon');
|
||||
var HeaderService = require('../../../lib/services/header');
|
||||
var Tx = require('bcoin').tx;
|
||||
var expect = require('chai').expect;
|
||||
var Encoding = require('../../../lib/services/header/encoding');
|
||||
var utils = require('../../../lib/utils');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
describe('Header Service', function() {
|
||||
|
||||
var headerService;
|
||||
var sandbox;
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
headerService = new HeaderService({
|
||||
node: {
|
||||
getNetworkName: function() { return 'regtest'; },
|
||||
services: []
|
||||
}
|
||||
});
|
||||
headerService._encoding = new Encoding(new Buffer('0000', 'hex'));
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('#start', function() {
|
||||
|
||||
|
||||
it('should get prefix for database', function(done) {
|
||||
|
||||
var getServiceTip = sandbox.stub().callsArgWith(1, null, { height: 123, hash: 'a' });
|
||||
var startSubs = sandbox.stub(headerService, '_startSubscriptions');
|
||||
var setListeners = sandbox.stub(headerService, '_setListeners');
|
||||
var getPrefix = sandbox.stub().callsArgWith(1, null, new Buffer('ffee', 'hex'));
|
||||
|
||||
headerService._db = { getPrefix: getPrefix, getServiceTip: getServiceTip };
|
||||
|
||||
headerService.start(function() {
|
||||
expect(startSubs.calledOnce).to.be.true;
|
||||
expect(setListeners.calledOnce).to.be.true;
|
||||
expect(headerService._tip).to.be.deep.equal({ height: 123, hash: 'a' });
|
||||
expect(headerService._encoding).to.be.instanceOf(Encoding);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#stop', function() {
|
||||
it('should stop the service', function(done) {
|
||||
headerService.stop(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAllHeaders', function() {
|
||||
it('should get all the headers', function(done) {
|
||||
|
||||
var stream = new EventEmitter();
|
||||
var createReadStream = sandbox.stub().returns(stream);
|
||||
var hash = sandbox.stub().returns('a');
|
||||
var header = sandbox.stub().returns({});
|
||||
var hashKey = sandbox.stub();
|
||||
var headerVal = sandbox.stub();
|
||||
|
||||
headerService._db = { createReadStream: createReadStream };
|
||||
headerService._encoding = { decodeHeaderKey: hash, decodeHeaderValue: header, encodeHeaderKey: hashKey, encodeHeaderValue: headerVal };
|
||||
|
||||
headerService.getAllHeaders(function(err, headers) {
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
expect(headers).to.be.deep.equal([ { a: {} } ]);
|
||||
done();
|
||||
|
||||
});
|
||||
|
||||
stream.emit('data', { key: 'a', value: 'a' });
|
||||
stream.emit('end');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_startSync', function() {
|
||||
|
||||
it('should start the sync process', function() {
|
||||
headerService._bestHeight = 123;
|
||||
headerService._tip = { height: 121, hash: 'a' };
|
||||
var sync = sandbox.stub(headerService, '_sync');
|
||||
headerService._startSync();
|
||||
expect(sync.calledOnce).to.be.true;
|
||||
expect(headerService._numNeeded).to.equal(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#_sync', function() {
|
||||
it('should sync header', function() {
|
||||
headerService._p2pHeaderCallsNeeded = 10;
|
||||
headerService._numNeeded = 1000;
|
||||
headerService._tip = { height: 121, hash: 'a' };
|
||||
var getHeaders = sandbox.stub();
|
||||
headerService._p2p = { getHeaders: getHeaders };
|
||||
headerService._sync();
|
||||
expect(getHeaders.calledOnce).to.be.true;
|
||||
expect(headerService._p2pHeaderCallsNeeded).to.equal(9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_onHeaders', function() {
|
||||
|
||||
it('should handle new headers received', function() {
|
||||
var headers = [ { hash: 'b' } ];
|
||||
headerService._tip = { height: 123, hash: 'a' };
|
||||
headerService._bestHeight = 123;
|
||||
var getHeaderOps = sandbox.stub(headerService, '_getHeaderOperations').returns([]);
|
||||
var encodeTip = sandbox.stub().returns({ key: 'b', value: 'b' });
|
||||
var batch = sandbox.stub();
|
||||
var sync = sandbox.stub(headerService, '_sync');
|
||||
utils.encodeTip = encodeTip;
|
||||
headerService._db = { batch: batch };
|
||||
headerService._onHeaders(headers);
|
||||
expect(getHeaderOps.calledOnce).to.be.true;
|
||||
expect(encodeTip.calledOnce).to.be.true;
|
||||
expect(batch.calledOnce).to.be.true;
|
||||
expect(sync.calledOnce).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@ -11,8 +11,8 @@ describe('Timestamp service encoding', function() {
|
||||
var encoding = new Encoding(servicePrefix);
|
||||
var blockhash = '00000000000000000115b92b1ff4377441049bff75c6c48b626eb99e8b744297';
|
||||
var timestamp = 5;
|
||||
var timestampBuf = new Buffer(8);
|
||||
timestampBuf.writeDoubleBE(timestamp);
|
||||
var timestampBuf = new Buffer(4);
|
||||
timestampBuf.writeUInt32BE(timestamp);
|
||||
|
||||
it('should encode block timestamp key' , function() {
|
||||
encoding.encodeBlockTimestampKey(blockhash).should.deep.equal(Buffer.concat([servicePrefix, blockPrefix, new Buffer(blockhash, 'hex')]));
|
||||
@ -47,5 +47,3 @@ describe('Timestamp service encoding', function() {
|
||||
encoding.decodeTimestampBlockValue(new Buffer(blockhash, 'hex')).should.equal(blockhash);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
var bitcore = require('bitcore-lib');
|
||||
var Tx = require('bcoin').tx;
|
||||
|
||||
var Encoding = require('../../../lib/services/transaction/encoding');
|
||||
|
||||
@ -11,8 +11,8 @@ describe('Transaction service encoding', function() {
|
||||
var encoding = new Encoding(servicePrefix);
|
||||
var txid = '91b58f19b6eecba94ed0f6e463e8e334ec0bcda7880e2985c82a8f32e4d03add';
|
||||
var txHex = '0100000001cc3ffe0638792c8b39328bb490caaefe2cf418f2ce0144956e0c22515f29724d010000006a473044022030ce9fa68d1a32abf0cd4adecf90fb998375b64fe887c6987278452b068ae74c022036a7d00d1c8af19e298e04f14294c807ebda51a20389ad751b4ff3c032cf8990012103acfcb348abb526526a9f63214639d79183871311c05b2eebc727adfdd016514fffffffff02f6ae7d04000000001976a9144455183e407ee4d3423858c8a3275918aedcd18e88aca99b9b08010000001976a9140beceae2c29bfde08d2b6d80b33067451c5887be88ac00000000';
|
||||
var tx = new bitcore.Transaction(txHex);
|
||||
var txEncoded = Buffer.concat([new Buffer('00000002', 'hex'), new Buffer('3ff0000000000000', 'hex'), new Buffer('0002', 'hex'), new Buffer('40000000000000004008000000000000', 'hex'), tx.toBuffer()]);
|
||||
var tx = Tx.fromRaw(txHex, 'hex');
|
||||
var txEncoded = Buffer.concat([new Buffer('00000002', 'hex'), new Buffer('00000001', 'hex'), new Buffer('0002', 'hex'), new Buffer('40000000000000004008000000000000', 'hex'), tx.toRaw()]);
|
||||
|
||||
it('should encode transaction key' , function() {
|
||||
var txBuf = new Buffer(txid, 'hex');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user