From b9be679e099b5fc4e74ccf0b5b61e26dda653e55 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 2 Feb 2015 16:48:13 -0300 Subject: [PATCH 1/3] add some checks --- lib/block.js | 2 ++ lib/encoding/bufferreader.js | 2 ++ lib/transaction/transaction.js | 1 + 3 files changed, 5 insertions(+) diff --git a/lib/block.js b/lib/block.js index 81248ffb9..52d4e7384 100644 --- a/lib/block.js +++ b/lib/block.js @@ -9,6 +9,7 @@ var BufferWriter = require('./encoding/bufferwriter'); var Hash = require('./crypto/hash'); var JSUtil = require('./util/js'); var Transaction = require('./transaction'); +var $ = require('./util/preconditions'); /** * Instantiate a Block from a Buffer, JSON object, or Object with @@ -96,6 +97,7 @@ Block.fromJSON = function fromJSON(json) { */ Block._fromBufferReader = function _fromBufferReader(br) { var info = {}; + $.checkState(!br.finished(), 'No block data received'); info.header = BlockHeader.fromBufferReader(br); var transactions = br.readVarintNum(); info.transactions = []; diff --git a/lib/encoding/bufferreader.js b/lib/encoding/bufferreader.js index 89f46452d..84509dd0c 100644 --- a/lib/encoding/bufferreader.js +++ b/lib/encoding/bufferreader.js @@ -28,6 +28,8 @@ BufferReader.prototype.eof = function() { return this.pos >= this.buf.length; }; +BufferReader.prototype.finished = BufferReader.prototype.eof; + BufferReader.prototype.read = function(len) { $.checkArgument(!_.isUndefined(len), 'Must specify a length'); var buf = this.buf.slice(this.pos, this.pos + len); diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 45ed523b6..1f0b8ae0c 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -189,6 +189,7 @@ Transaction.prototype.fromBuffer = function(buffer) { }; Transaction.prototype.fromBufferReader = function(reader) { + $.checkArgument(!reader.finished(), 'No transaction data received'); var i, sizeTxIns, sizeTxOuts; this.version = reader.readUInt32LE(); From c664f211d2e2c39e3d2dd663e1ae81807d005abc Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 4 Feb 2015 13:04:55 -0300 Subject: [PATCH 2/3] add BufferReader.readVarLengthBuffer --- lib/encoding/bufferreader.js | 22 +++++-- lib/script/script.js | 2 +- lib/transaction/input/input.js | 7 +-- test/encoding/bufferreader.js | 107 +++++++++++++++++++++++---------- 4 files changed, 95 insertions(+), 43 deletions(-) diff --git a/lib/encoding/bufferreader.js b/lib/encoding/bufferreader.js index 84509dd0c..c94bd5e5c 100644 --- a/lib/encoding/bufferreader.js +++ b/lib/encoding/bufferreader.js @@ -10,9 +10,10 @@ var BufferReader = function BufferReader(buf) { return new BufferReader(buf); } if (Buffer.isBuffer(buf)) { - this.set({buf: buf}); - } - else if (buf) { + this.set({ + buf: buf + }); + } else if (buf) { var obj = buf; this.set(obj); } @@ -82,7 +83,9 @@ 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 reversebuf = BufferReader({ + buf: buf + }).readReverse(); var bn = BN.fromBuffer(reversebuf); this.pos = this.pos + 8; return bn; @@ -109,6 +112,17 @@ BufferReader.prototype.readVarintNum = function() { } }; +/** + * reads a length prepended buffer + */ +BufferReader.prototype.readVarLengthBuffer = function() { + var len = this.readVarintNum(); + var buf = this.read(len); + $.checkState(buf.length === len, 'Invalid length while reading varlength buffer. ' + + 'Expected to read: ' + len + ' and read ' + buf.length); + return buf; +}; + BufferReader.prototype.readVarintBuf = function() { var first = this.buf.readUInt8(this.pos); switch (first) { diff --git a/lib/script/script.js b/lib/script/script.js index 8b28786ca..321ffc0b8 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -56,7 +56,7 @@ Script.fromBuffer = function(buffer) { script.chunks = []; var br = new BufferReader(buffer); - while (!br.eof()) { + while (!br.finished()) { var opcodenum = br.readUInt8(); var len, buf; diff --git a/lib/transaction/input/input.js b/lib/transaction/input/input.js index 915f71807..366a3f777 100644 --- a/lib/transaction/input/input.js +++ b/lib/transaction/input/input.js @@ -79,12 +79,7 @@ Input.fromBufferReader = function(br) { var input = new Input(); input.prevTxId = br.readReverse(32); input.outputIndex = br.readUInt32LE(); - var scriptSize = br.readVarintNum(); - if (scriptSize) { - input._scriptBuffer = br.read(scriptSize); - } else { - input._scriptBuffer = new buffer.Buffer([]); - } + input._scriptBuffer = br.readVarLengthBuffer(); input.sequenceNumber = br.readUInt32LE(); return input; }; diff --git a/test/encoding/bufferreader.js b/test/encoding/bufferreader.js index ffc8600d3..5dfce57f3 100644 --- a/test/encoding/bufferreader.js +++ b/test/encoding/bufferreader.js @@ -7,7 +7,7 @@ var BufferReader = bitcore.encoding.BufferReader; var BN = bitcore.crypto.BN; describe('BufferReader', function() { - + it('should make a new BufferReader', function() { var br = new BufferReader(); should.exist(br); @@ -25,7 +25,9 @@ describe('BufferReader', function() { describe('#set', function() { it('should set pos', function() { - should.exist(BufferReader().set({pos: 1}).pos); + should.exist(BufferReader().set({ + pos: 1 + }).pos); }); }); @@ -33,17 +35,19 @@ describe('BufferReader', function() { describe('#eof', function() { it('should return true for a blank br', function() { - var br = new BufferReader({buf: new Buffer([])}); + var br = new BufferReader({ + buf: new Buffer([]) + }); br.eof().should.equal(true); }); }); describe('read', function() { - + it('should return the same buffer', function() { var buf = new Buffer([0]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readAll().toString('hex').should.equal(buf.toString('hex')); }); @@ -53,10 +57,49 @@ describe('BufferReader', function() { var br = new BufferReader(buf); var buf2 = br.read(2); buf2.length.should.equal(2); - br.eof().should.equal(false); + br.finished().should.equal(false); br.pos.should.equal(2); }); + it('should work with 0 length', function() { + var buf = new Buffer(10); + buf.fill(1); + var br = new BufferReader(buf); + var buf2 = br.read(0); + buf2.length.should.equal(0); + br.finished().should.equal(false); + buf2.toString('hex').should.equal(''); + }); + + }); + + describe('readVarLengthBuffer', function() { + + it('returns correct buffer', function() { + var buf = new Buffer('73010000003766404f00000000b305434f00000000f203' + + '0000f1030000001027000048ee00000064000000004653656520626974636f696' + + 'e2e6f72672f666562323020696620796f7520686176652074726f75626c652063' + + '6f6e6e656374696e6720616674657220323020466562727561727900473045022' + + '1008389df45f0703f39ec8c1cc42c13810ffcae14995bb648340219e353b63b53' + + 'eb022009ec65e1c1aaeec1fd334c6b684bde2b3f573060d5b70c3a46723326e4e' + + '8a4f1', 'hex'); + var br = new BufferReader(buf); + var b1 = br.readVarLengthBuffer(); + b1.toString('hex').should.equal('010000003766404f00000000b305434f000' + + '00000f2030000f1030000001027000048ee000000640000000046536565206269' + + '74636f696e2e6f72672f666562323020696620796f7520686176652074726f756' + + '26c6520636f6e6e656374696e6720616674657220323020466562727561727900'); + var b2 = br.readVarLengthBuffer(); + b2.toString('hex').should.equal('30450221008389df45f0703f39ec8c1cc42' + + 'c13810ffcae14995bb648340219e353b63b53eb022009ec65e1c1aaeec1fd334c' + + '6b684bde2b3f573060d5b70c3a46723326e4e8a4f1'); + }); + it('fails on length too big', function() { + var buf = new Buffer('0a00', 'hex'); + var br = new BufferReader(buf); + br.readVarLengthBuffer.bind(br).should.throw('Invalid length while reading varlength buffer'); + }); + }); describe('#readUInt8', function() { @@ -64,7 +107,7 @@ describe('BufferReader', function() { it('should return 1', function() { var buf = new Buffer(1); buf.writeUInt8(1, 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt8().should.equal(1); }); @@ -75,7 +118,7 @@ describe('BufferReader', function() { it('should return 1', function() { var buf = new Buffer(2); buf.writeUInt16BE(1, 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt16BE().should.equal(1); }); @@ -86,7 +129,7 @@ describe('BufferReader', function() { it('should return 1', function() { var buf = new Buffer(2); buf.writeUInt16LE(1, 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt16LE().should.equal(1); }); @@ -97,7 +140,7 @@ describe('BufferReader', function() { it('should return 1', function() { var buf = new Buffer(4); buf.writeUInt32BE(1, 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt32BE().should.equal(1); }); @@ -108,7 +151,7 @@ describe('BufferReader', function() { it('should return 1', function() { var buf = new Buffer(4); buf.writeUInt32LE(1, 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt32LE().should.equal(1); }); @@ -120,14 +163,14 @@ describe('BufferReader', function() { var buf = new Buffer(8); buf.fill(0); buf.writeUInt32BE(1, 4); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt64BEBN().toNumber().should.equal(1); }); it('should return 2^64', function() { var buf = new Buffer(8); buf.fill(0xff); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt64BEBN().toNumber().should.equal(Math.pow(2, 64)); }); @@ -139,7 +182,7 @@ describe('BufferReader', function() { var buf = new Buffer(8); buf.fill(0); buf.writeUInt32LE(1, 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt64LEBN().toNumber().should.equal(1); }); @@ -147,21 +190,21 @@ describe('BufferReader', function() { var buf = new Buffer(8); buf.fill(0); buf.writeUInt32LE(Math.pow(2, 30), 0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt64LEBN().toNumber().should.equal(Math.pow(2, 30)); }); it('should return 0', function() { var buf = new Buffer(8); buf.fill(0); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt64LEBN().toNumber().should.equal(0); }); it('should return 2^64', function() { var buf = new Buffer(8); buf.fill(0xff); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readUInt64LEBN().toNumber().should.equal(Math.pow(2, 64)); }); @@ -171,26 +214,26 @@ describe('BufferReader', function() { it('should read a 1 byte varint', function() { var buf = new Buffer([50]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBuf().length.should.equal(1); }); it('should read a 3 byte varint', function() { var buf = new Buffer([253, 253, 0]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBuf().length.should.equal(3); }); it('should read a 5 byte varint', function() { var buf = new Buffer([254, 0, 0, 0, 0]); buf.writeUInt32LE(50000, 1); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBuf().length.should.equal(5); }); it('should read a 9 byte varint', function() { var buf = BufferWriter().writeVarintBN(BN(Math.pow(2, 54).toString())).concat(); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBuf().length.should.equal(9); }); @@ -200,26 +243,26 @@ describe('BufferReader', function() { it('should read a 1 byte varint', function() { var buf = new Buffer([50]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintNum().should.equal(50); }); it('should read a 3 byte varint', function() { var buf = new Buffer([253, 253, 0]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintNum().should.equal(253); }); it('should read a 5 byte varint', function() { var buf = new Buffer([254, 0, 0, 0, 0]); buf.writeUInt32LE(50000, 1); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintNum().should.equal(50000); }); it('should throw an error on a 9 byte varint over the javascript uint precision limit', function() { var buf = BufferWriter().writeVarintBN(BN(Math.pow(2, 54).toString())).concat(); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); (function() { br.readVarintNum(); }).should.throw('number too large to retain precision - use readVarintBN'); @@ -227,7 +270,7 @@ describe('BufferReader', function() { it('should not throw an error on a 9 byte varint not over the javascript uint precision limit', function() { var buf = BufferWriter().writeVarintBN(BN(Math.pow(2, 53).toString())).concat(); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); (function() { br.readVarintNum(); }).should.not.throw('number too large to retain precision - use readVarintBN'); @@ -239,36 +282,36 @@ describe('BufferReader', function() { it('should read a 1 byte varint', function() { var buf = new Buffer([50]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBN().toNumber().should.equal(50); }); it('should read a 3 byte varint', function() { var buf = new Buffer([253, 253, 0]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBN().toNumber().should.equal(253); }); it('should read a 5 byte varint', function() { var buf = new Buffer([254, 0, 0, 0, 0]); buf.writeUInt32LE(50000, 1); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBN().toNumber().should.equal(50000); }); it('should read a 9 byte varint', function() { var buf = Buffer.concat([new Buffer([255]), new Buffer('ffffffffffffffff', 'hex')]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.readVarintBN().toNumber().should.equal(Math.pow(2, 64)); }); }); describe('#reverse', function() { - + it('should reverse this [0, 1]', function() { var buf = new Buffer([0, 1]); - var br = new BufferReader({buf: buf}); + var br = new BufferReader(buf); br.reverse().readAll().toString('hex').should.equal('0100'); }); From a80dddf45e706fc0c33ca9444cd92c573e4e9b94 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 4 Feb 2015 13:11:49 -0300 Subject: [PATCH 3/3] style fix --- test/encoding/bufferreader.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/encoding/bufferreader.js b/test/encoding/bufferreader.js index 5dfce57f3..f3e053267 100644 --- a/test/encoding/bufferreader.js +++ b/test/encoding/bufferreader.js @@ -35,10 +35,8 @@ describe('BufferReader', function() { describe('#eof', function() { it('should return true for a blank br', function() { - var br = new BufferReader({ - buf: new Buffer([]) - }); - br.eof().should.equal(true); + var br = new BufferReader(new Buffer([])); + br.finished().should.equal(true); }); });