diff --git a/benchmark/serialization.js b/benchmark/serialization.js index 7b45cc761..ee948a60e 100644 --- a/benchmark/serialization.js +++ b/benchmark/serialization.js @@ -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; diff --git a/lib/encoding/bufferreader.js b/lib/encoding/bufferreader.js index bb881fb76..d7ca1575c 100644 --- a/lib/encoding/bufferreader.js +++ b/lib/encoding/bufferreader.js @@ -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; + // 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; }; diff --git a/lib/util/buffer.js b/lib/util/buffer.js index 332b4be80..c78b9396e 100644 --- a/lib/util/buffer.js +++ b/lib/util/buffer.js @@ -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]; diff --git a/test/encoding/bufferreader.js b/test/encoding/bufferreader.js index e3b66c146..78e4c764c 100644 --- a/test/encoding/bufferreader.js +++ b/test/encoding/bufferreader.js @@ -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); @@ -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); diff --git a/test/util/buffer.js b/test/util/buffer.js index 04e058270..bbc1e2609 100644 --- a/test/util/buffer.js +++ b/test/util/buffer.js @@ -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); - }); }); });