Merge pull request #1029 from maraoz/fix/block

add BufferReader.readVarLengthBuffer
This commit is contained in:
Esteban Ordano 2015-02-04 13:27:13 -03:00
commit 8baf7650a9
6 changed files with 99 additions and 44 deletions

View File

@ -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 = [];

View File

@ -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);
}
@ -28,6 +29,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);
@ -80,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;
@ -107,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) {

View File

@ -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;

View File

@ -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;
};

View File

@ -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();

View File

@ -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,17 @@ 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);
});
});
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 +55,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 +105,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 +116,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 +127,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 +138,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 +149,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 +161,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 +180,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 +188,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 +212,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 +241,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 +268,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 +280,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');
});