Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions benchmark/serialization.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,65 @@ console.log('Benchmarking Block/Transaction Serialization');
console.log('---------------------------------------');

async.series([
function(next) {

var buffers = [];
var hashBuffers = [];
console.log('Generating Random Test Data...');
for (var i = 0; i < 100; i++) {

// uint64le
var br = new bitcore.encoding.BufferWriter();
var num = Math.round(Math.random() * 10000000000000);
br.writeUInt64LEBN(new bitcore.crypto.BN(num));
buffers.push(br.toBuffer());

// hashes
var data = bitcore.crypto.Hash.sha256sha256(new Buffer(32));
hashBuffers.push(data);
}

var c = 0;
var bn;

function readUInt64LEBN() {
if (c >= buffers.length) {
c = 0;
}
var buf = buffers[c];
var br = new bitcore.encoding.BufferReader(buf);
bn = br.readUInt64LEBN();
c++;
}

var reversed;

function readReverse() {
if (c >= hashBuffers.length) {
c = 0;
}
var buf = hashBuffers[c];
var br = new bitcore.encoding.BufferReader(buf);
reversed = br.readReverse();
c++;
}

console.log('Starting benchmark...');

var suite = new benchmark.Suite();
suite.add('bufferReader.readUInt64LEBN()', readUInt64LEBN, {maxTime: maxTime});
suite.add('bufferReader.readReverse()', readReverse, {maxTime: maxTime});
suite
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Done');
console.log('----------------------------------------------------------------------');
next();
})
.run();
},
function(next) {

var block1;
Expand Down
21 changes: 16 additions & 5 deletions lib/encoding/bufferreader.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,22 @@ BufferReader.prototype.readUInt64BEBN = function() {
};

BufferReader.prototype.readUInt64LEBN = function() {
var buf = this.buf.slice(this.pos, this.pos + 8);
var reversebuf = BufferReader({
buf: buf
}).readReverse();
var bn = BN.fromBuffer(reversebuf);
var second = this.buf.readUInt32LE(this.pos);
var first = this.buf.readUInt32LE(this.pos + 4);
var combined = (first * 0x100000000) + second;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this lose precision? See:

> 0x100000000 * 0x10000000 
1152921504606847000
> 0x100000000 * 0x10000000 + 1
1152921504606847000

Both answers give the same value. Does this mean that if second is 0 or 1 and first is 0x10000000, this would return the same value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can lose precision with numbers equal or above 2 ^ 53.

> 0x1fffffffffffff === Math.pow(2, 53) - 1
// true
> 1152921504606847000 < 0x1fffffffffffff
// false

And in that case the number will be read directly into BN and not a JavaScript Number first: https://github.com/bitpay/bitcore/pull/1279/files#diff-17000cc0d07e4a49ab9cbafe33ca7231R101

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh, gotcha. I didn't understand the < 0x1fffffffffffff part. LGTM

// Instantiating an instance of BN with a number is faster than with an
// array or string. However, the maximum safe number for a double precision
// floating point is 2 ^ 52 - 1 (0x1fffffffffffff), thus we can safely use
// non-floating point numbers less than this amount (52 bits). And in the case
// that the number is larger, we can instatiate an instance of BN by passing
// an array from the buffer (slower) and specifying the endianness.
var bn;
if (combined <= 0x1fffffffffffff) {
bn = new BN(combined);
} else {
var data = Array.prototype.slice.call(this.buf, this.pos, this.pos + 8);
bn = new BN(data, 10, 'le');
}
this.pos = this.pos + 8;
return bn;
};
Expand Down
1 change: 0 additions & 1 deletion lib/util/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ module.exports = {
* @return {Buffer}
*/
reverse: function reverse(param) {
$.checkArgumentType(param, 'Buffer', 'param');
var ret = new buffer.Buffer(param.length);
for (var i = 0; i < param.length; i++) {
ret[i] = param[param.length - i - 1];
Expand Down
36 changes: 36 additions & 0 deletions test/encoding/bufferreader.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,13 @@ describe('BufferReader', function() {
br.readUInt64LEBN().toNumber().should.equal(1);
});

it('should return 10BTC', function() {
var tenbtc = 10 * 1e8;
var tenbtcBuffer = new Buffer('00ca9a3b00000000', 'hex');
var br = new BufferReader(tenbtcBuffer);
br.readUInt64LEBN().toNumber().should.equal(tenbtc);
});

it('should return 2^30', function() {
var buf = new Buffer(8);
buf.fill(0);
Expand All @@ -198,6 +205,35 @@ describe('BufferReader', function() {
br.readUInt64LEBN().toNumber().should.equal(Math.pow(2, 30));
});

it('should return 2^32 + 1', function() {
var num = Math.pow(2, 32) + 1;
var numBuffer = new Buffer('0100000001000000', 'hex');
var br = new BufferReader(numBuffer);
br.readUInt64LEBN().toNumber().should.equal(num);
});

it('should return max number of satoshis', function() {
var maxSatoshis = 21000000 * 1e8;
var maxSatoshisBuffer = new Buffer('0040075af0750700', 'hex');
var br = new BufferReader(maxSatoshisBuffer);
br.readUInt64LEBN().toNumber().should.equal(maxSatoshis);
});

it('should return 2^53 - 1', function() {
var maxSafe = Math.pow(2, 53) - 1;
var maxSafeBuffer = new Buffer('ffffffffffff1f00', 'hex');
var br = new BufferReader(maxSafeBuffer);
br.readUInt64LEBN().toNumber().should.equal(maxSafe);
});

it('should return 2^53', function() {
var bn = new BN('20000000000000', 16);
var bnBuffer = new Buffer('0000000000002000', 'hex');
var br = new BufferReader(bnBuffer);
var readbn = br.readUInt64LEBN();
readbn.cmp(bn).should.equal(0);
});

it('should return 0', function() {
var buf = new Buffer(8);
buf.fill(0);
Expand Down
5 changes: 0 additions & 5 deletions test/util/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,5 @@ describe('buffer utils', function() {
original[1].should.equal(reversed[1]);
original[2].should.equal(reversed[0]);
});
it('checks the argument type', function() {
expect(function() {
BufferUtil.reverse('invalid');
}).to.throw(errors.InvalidArgumentType);
});
});
});