Browse Source

block serialization: Add option skip magic numbers

patch-2
Esteban Ordano 10 years ago
committed by Braydon Fuller
parent
commit
b416655222
  1. 68
      lib/block.js
  2. 15
      lib/blockheader.js
  3. 28
      test/block.js
  4. 3
      test/data/blk86756-testnet.json

68
lib/block.js

@ -59,12 +59,11 @@ Block._from = function _from(arg) {
* @type {BlockHeader} * @type {BlockHeader}
*/ */
header: arg.header, header: arg.header,
txsvi: arg.txsvi,
/** /**
* @name Block#txs * @name Block#transactions
* @type {Transaction[]} * @type {Transaction[]}
*/ */
txs: arg.txs transactions: arg.transactions
}; };
} else { } else {
throw new TypeError('Unrecognized argument for Block'); throw new TypeError('Unrecognized argument for Block');
@ -81,16 +80,15 @@ Block._fromJSON = function _fromJSON(data) {
if (JSUtil.isValidJSON(data)) { if (JSUtil.isValidJSON(data)) {
data = JSON.parse(data); data = JSON.parse(data);
} }
var txs = []; var transactions = [];
data.txs.forEach(function(tx) { data.transactions.forEach(function(data) {
txs.push(Transaction().fromJSON(tx)); transactions.push(Transaction().fromJSON(data));
}); });
var info = { var info = {
magicnum: data.magicnum, magicnum: data.magicnum,
size: data.size, size: data.size,
header: BlockHeader.fromJSON(data.header), header: BlockHeader.fromJSON(data.header),
txsvi: Varint().fromString(data.txsvi), transactions: transactions
txs: txs
}; };
return info; return info;
}; };
@ -109,16 +107,22 @@ Block.fromJSON = function fromJSON(json) {
* @returns {Object} - An object representing the block data * @returns {Object} - An object representing the block data
* @private * @private
*/ */
Block._fromBufferReader = function _fromBufferReader(br) { Block._fromBufferReader = function _fromBufferReader(br, options) {
options = options || {};
var info = {}; var info = {};
info.magicnum = br.readUInt32LE(); if (!options.skipMagic) {
info.size = br.readUInt32LE(); info.magicnum = br.readUInt32LE();
info.size = br.readUInt32LE();
}
info.header = BlockHeader.fromBufferReader(br); info.header = BlockHeader.fromBufferReader(br);
info.txsvi = Varint(br.readVarintBuf()); if (options.skipMagic) {
var txslen = info.txsvi.toNumber(); info.magicnum = 0;
info.txs = []; info.size = info.header.bits;
for (var i = 0; i < txslen; i++) { }
info.txs.push(Transaction().fromBufferReader(br)); var transactions = br.readVarintNum();
info.transactions = [];
for (var i = 0; i < transactions; i++) {
info.transactions.push(Transaction().fromBufferReader(br));
} }
return info; return info;
}; };
@ -127,8 +131,8 @@ Block._fromBufferReader = function _fromBufferReader(br) {
* @param {BufferReader} - A buffer reader of the block * @param {BufferReader} - A buffer reader of the block
* @returns {Block} - An instance of block * @returns {Block} - An instance of block
*/ */
Block.fromBufferReader = function fromBufferReader(br) { Block.fromBufferReader = function fromBufferReader(br, opts) {
var info = Block._fromBufferReader(br); var info = Block._fromBufferReader(br, opts);
return new Block(info); return new Block(info);
}; };
@ -136,8 +140,8 @@ Block.fromBufferReader = function fromBufferReader(br) {
* @param {Buffer} - A buffer of the block * @param {Buffer} - A buffer of the block
* @returns {Block} - An instance of block * @returns {Block} - An instance of block
*/ */
Block.fromBuffer = function fromBuffer(buf) { Block.fromBuffer = function fromBuffer(buf, opts) {
return Block.fromBufferReader(BufferReader(buf)); return Block.fromBufferReader(BufferReader(buf), opts);
}; };
/** /**
@ -166,16 +170,15 @@ Block.fromRawBlock = function fromRawBlock(data) {
* @returns {Object} - A plain object with the block properties * @returns {Object} - A plain object with the block properties
*/ */
Block.prototype.toObject = function toObject() { Block.prototype.toObject = function toObject() {
var txs = []; var transactions = [];
this.txs.forEach(function(tx) { this.transactions.forEach(function(tx) {
txs.push(tx.toObject()); transactions.push(tx.toObject());
}); });
return { return {
magicnum: this.magicnum, magicnum: this.magicnum,
size: this.size, size: this.size,
header: this.header.toObject(), header: this.header.toObject(),
txsvi: this.txsvi.toString(), transactions: transactions
txs: txs
}; };
}; };
@ -211,10 +214,9 @@ Block.prototype.toBufferWriter = function toBufferWriter(bw) {
bw.writeUInt32LE(this.magicnum); bw.writeUInt32LE(this.magicnum);
bw.writeUInt32LE(this.size); bw.writeUInt32LE(this.size);
bw.write(this.header.toBuffer()); bw.write(this.header.toBuffer());
bw.write(this.txsvi.buf); bw.writeVarintNum(this.transactions.length);
var txslen = this.txsvi.toNumber(); for (var i = 0; i < this.transactions.length; i++) {
for (var i = 0; i < txslen; i++) { this.transactions[i].toBufferWriter(bw);
this.txs[i].toBufferWriter(bw);
} }
return bw; return bw;
}; };
@ -225,11 +227,11 @@ Block.prototype.toBufferWriter = function toBufferWriter(bw) {
*/ */
Block.prototype.getTransactionHashes = function getTransactionHashes() { Block.prototype.getTransactionHashes = function getTransactionHashes() {
var hashes = []; var hashes = [];
if (this.txs.length === 0) { if (this.transactions.length === 0) {
return [Block.Values.NULL_HASH]; return [Block.Values.NULL_HASH];
} }
for (var t = 0; t < this.txs.length; t++) { for (var t = 0; t < this.transactions.length; t++) {
hashes.push(this.txs[t]._getHash()); hashes.push(this.transactions[t]._getHash());
} }
return hashes; return hashes;
}; };
@ -245,7 +247,7 @@ Block.prototype.getMerkleTree = function getMerkleTree() {
var tree = this.getTransactionHashes(); var tree = this.getTransactionHashes();
var j = 0; var j = 0;
for (var size = this.txs.length; size > 1; size = Math.floor((size + 1) / 2)) { for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) {
for (var i = 0; i < size; i += 2) { for (var i = 0; i < size; i += 2) {
var i2 = Math.min(i + 1, size - 1); var i2 = Math.min(i + 1, size - 1);
var buf = Buffer.concat([tree[j + i], tree[j + i2]]); var buf = Buffer.concat([tree[j + i], tree[j + i2]]);

15
lib/blockheader.js

@ -119,14 +119,13 @@ BlockHeader.fromString = function fromString(str) {
* @private * @private
*/ */
BlockHeader._fromBufferReader = function _fromBufferReader(br) { BlockHeader._fromBufferReader = function _fromBufferReader(br) {
var info = { var info = {};
version: br.readUInt32LE(), info.version = br.readUInt32LE();
prevHash: br.read(32), info.prevHash = br.read(32);
merkleRoot: br.read(32), info.merkleRoot = br.read(32);
time: br.readUInt32LE(), info.time = br.readUInt32LE();
bits: br.readUInt32LE(), info.bits = br.readUInt32LE();
nonce: br.readUInt32LE() info.nonce = br.readUInt32LE();
};
return info; return info;
}; };

28
test/block.js

@ -27,9 +27,8 @@ describe('Block', function() {
var blockbuf = new Buffer(blockhex, 'hex'); var blockbuf = new Buffer(blockhex, 'hex');
var size = data.blocksize; var size = data.blocksize;
var bh = BlockHeader.fromBuffer(new Buffer(data.blockheaderhex, 'hex')); var bh = BlockHeader.fromBuffer(new Buffer(data.blockheaderhex, 'hex'));
var txsvi = Varint().fromNumber(data.txsvi);
var txs = []; var txs = [];
JSON.parse(dataJson).txs.forEach(function(tx){ JSON.parse(dataJson).transactions.forEach(function(tx){
txs.push(new Transaction().fromJSON(tx)); txs.push(new Transaction().fromJSON(tx));
}); });
var json = dataJson; var json = dataJson;
@ -45,7 +44,7 @@ describe('Block', function() {
it('should not make an empty block', function() { it('should not make an empty block', function() {
(function() { (function() {
var b = new Block(); return new Block();
}).should.throw('Unrecognized argument for Block'); }).should.throw('Unrecognized argument for Block');
}); });
@ -56,20 +55,18 @@ describe('Block', function() {
magicnum: magicnum, magicnum: magicnum,
size: size, size: size,
header: bh, header: bh,
txsvi: txsvi, transactions: txs
txs: txs
}); });
should.exist(b.magicnum); should.exist(b.magicnum);
should.exist(b.size); should.exist(b.size);
should.exist(b.txsvi);
should.exist(b.header); should.exist(b.header);
should.exist(b.txs); should.exist(b.transactions);
}); });
it('should properly deserialize blocks', function() { it('should properly deserialize blocks', function() {
dataBlocks.forEach(function(block){ dataBlocks.forEach(function(block){
var b = Block.fromBuffer(new Buffer(block.data, 'hex')); var b = Block.fromBuffer(new Buffer(block.data, 'hex'), {skipMagic: true});
b.txs.length.should.equal(block.transactions); b.transactions.length.should.equal(block.transactions);
}); });
}); });
@ -98,8 +95,7 @@ describe('Block', function() {
should.exist(block.magicnum); should.exist(block.magicnum);
should.exist(block.size); should.exist(block.size);
should.exist(block.header); should.exist(block.header);
should.exist(block.txsvi); should.exist(block.transactions);
should.exist(block.txs);
}); });
it('should set these known values', function() { it('should set these known values', function() {
@ -108,8 +104,7 @@ describe('Block', function() {
should.exist(block.magicnum); should.exist(block.magicnum);
should.exist(block.size); should.exist(block.size);
should.exist(block.header); should.exist(block.header);
should.exist(block.txsvi); should.exist(block.transactions);
should.exist(block.txs);
}); });
it('accepts an object as argument', function() { it('accepts an object as argument', function() {
@ -127,8 +122,7 @@ describe('Block', function() {
should.exist(b.magicnum); should.exist(b.magicnum);
should.exist(b.size); should.exist(b.size);
should.exist(b.header); should.exist(b.header);
should.exist(b.txsvi); should.exist(b.transactions);
should.exist(b.txs);
}); });
}); });
@ -225,14 +219,14 @@ describe('Block', function() {
it('should describe as invalid merkle root', function() { it('should describe as invalid merkle root', function() {
var x = Block.fromRawBlock(dataRawBlockBinary); var x = Block.fromRawBlock(dataRawBlockBinary);
x.txs.push(new Transaction()); x.transactions.push(new Transaction());
var valid = x.validMerkleRoot(); var valid = x.validMerkleRoot();
valid.should.equal(false); valid.should.equal(false);
}); });
it('should get a null hash merkle root', function() { it('should get a null hash merkle root', function() {
var x = Block.fromRawBlock(dataRawBlockBinary); var x = Block.fromRawBlock(dataRawBlockBinary);
x.txs = []; // empty the txs x.transactions = []; // empty the txs
var mr = x.getMerkleRoot(); var mr = x.getMerkleRoot();
mr.should.deep.equal(Block.Values.NULL_HASH); mr.should.deep.equal(Block.Values.NULL_HASH);
}); });

3
test/data/blk86756-testnet.json

@ -9,8 +9,7 @@
"bits": 473956288, "bits": 473956288,
"nonce": 3594009557 "nonce": 3594009557
}, },
"txsvi": "16", "transactions": [{
"txs": [{
"version": 1, "version": 1,
"txinsvi": "01", "txinsvi": "01",
"txins": [{ "txins": [{

Loading…
Cancel
Save