From 6216bcbd97a82629e74cad1131aa24162aef7a4a Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 17 Jun 2016 03:25:56 -0700 Subject: [PATCH] witsize. json. --- lib/bcoin/block.js | 60 ++++++++++++++++++-------------- lib/bcoin/input.js | 2 +- lib/bcoin/merkleblock.js | 74 ++++++++++++++++++++++++++++++++++------ lib/bcoin/output.js | 2 +- lib/bcoin/tx.js | 14 ++++---- lib/bcoin/utils.js | 17 +++++---- test/block-test.js | 7 ++++ 7 files changed, 124 insertions(+), 52 deletions(-) diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index cd1fa3b9..b822e5ad 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -42,12 +42,13 @@ function Block(data) { bcoin.abstractblock.call(this, data); - this.txs = null; + this.txs = []; this._cbHeight = null; this._commitmentHash = null; this._raw = null; this._size = null; this._witnessSize = null; + this._lastWitnessSize = 0; if (data) this.fromOptions(data); @@ -58,8 +59,6 @@ utils.inherits(Block, bcoin.abstractblock); Block.prototype.fromOptions = function fromOptions(data) { var i; - this.txs = []; - this._cbHeight = null; this._commitmentHash = null; @@ -86,7 +85,6 @@ Block.prototype.render = function render(writer) { var raw = this.getRaw(); if (writer) { writer.writeBytes(raw); - writer._witnessSize = raw._witnessSize; return writer; } return raw; @@ -103,7 +101,6 @@ Block.prototype.renderNormal = function renderNormal(writer) { raw = this.getRaw(); if (writer) { writer.writeBytes(raw); - writer._witnessSize = raw._witnessSize; return writer; } return raw; @@ -122,7 +119,6 @@ Block.prototype.renderWitness = function renderWitness(writer) { raw = this.getRaw(); if (writer) { writer.writeBytes(raw); - writer._witnessSize = raw._witnessSize; return writer; } return raw; @@ -142,6 +138,7 @@ Block.prototype.getRaw = function getRaw() { if (this._raw) { assert(this._size > 0); assert(this._witnessSize >= 0); + this._lastWitnessSize = this._witnessSize; return this._raw; } @@ -149,7 +146,7 @@ Block.prototype.getRaw = function getRaw() { if (!this.mutable) { this._size = raw.length; - this._witnessSize = raw._witnessSize; + this._witnessSize = this._lastWitnessSize; this._raw = raw; } @@ -172,6 +169,7 @@ Block.prototype.getSizes = function getSizes() { } if (!this.mutable) { + assert(!this._raw); this.getRaw(); return { size: this._size, @@ -184,7 +182,7 @@ Block.prototype.getSizes = function getSizes() { return { size: writer.written, - witnessSize: writer._witnessSize + witnessSize: this._lastWitnessSize }; }; @@ -635,7 +633,7 @@ Block.prototype.inspect = function inspect() { Block.prototype.toJSON = function toJSON() { return { type: 'block', - hash: utils.revHex(this.hash('hex')), + hash: this.rhash, height: this.height, version: this.version, prevBlock: utils.revHex(this.prevBlock), @@ -657,14 +655,24 @@ Block.prototype.toJSON = function toJSON() { * for passing to the Block constructor). */ -Block.parseJSON = function parseJSON(json) { +Block.prototype.fromJSON = function fromJSON(json) { + var i; + assert.equal(json.type, 'block'); - json.prevBlock = utils.revHex(json.prevBlock); - json.merkleRoot = utils.revHex(json.merkleRoot); - json.txs = json.txs.map(function(tx) { - return bcoin.tx.fromJSON(tx); - }); - return json; + + this.height = json.height; + this.version = json.version; + this.prevBlock = utils.revHex(json.prevBlock); + this.merkleRoot = utils.revHex(json.merkleRoot); + this.ts = json.ts; + this.bits = json.bits; + this.nonce = json.nonce; + this.totalTX = json.totalTX; + + for (i = 0; i < json.txs.length; i++) + this.txs.push(bcoin.tx.fromJSON(json.txs[i])); + + return this; }; /** @@ -674,7 +682,7 @@ Block.parseJSON = function parseJSON(json) { */ Block.fromJSON = function fromJSON(json) { - return new Block(Block.parseJSON(json)); + return new Block().fromJSON(json); }; /** @@ -711,8 +719,6 @@ Block.prototype.fromRaw = function fromRaw(data) { this._witnessSize = 0; - this.txs = []; - for (i = 0; i < this.totalTX; i++) { tx = bcoin.tx.fromRaw(p); this._witnessSize += tx._witnessSize; @@ -753,7 +759,7 @@ Block.prototype.toMerkle = function toMerkle(filter) { Block.prototype.frame = function frame(witness, writer) { var p = bcoin.writer(writer); var witnessSize = 0; - var i; + var i, tx; p.write32(this.version); p.writeHash(this.prevBlock); @@ -764,17 +770,19 @@ Block.prototype.frame = function frame(witness, writer) { p.writeVarint(this.txs.length); for (i = 0; i < this.txs.length; i++) { - if (witness) - this.txs[i].render(p); - else - this.txs[i].renderNormal(p); - witnessSize += p._witnessSize; + tx = this.txs[i]; + if (witness) { + tx.render(p); + witnessSize += tx._lastWitnessSize; + } else { + tx.renderNormal(p); + } } if (!writer) p = p.render(); - p._witnessSize = witnessSize; + this._lastWitnessSize = witnessSize; return p; }; diff --git a/lib/bcoin/input.js b/lib/bcoin/input.js index c90c2cbd..59728a38 100644 --- a/lib/bcoin/input.js +++ b/lib/bcoin/input.js @@ -17,7 +17,7 @@ function Outpoint(hash, index) { return new Outpoint(hash, index); this.hash = hash || null; - this.index = index || 0; + this.index = index != null ? index : null; } Outpoint.prototype.fromOptions = function fromOptions(data) { diff --git a/lib/bcoin/merkleblock.js b/lib/bcoin/merkleblock.js index 02d078c7..a0b2c1c9 100644 --- a/lib/bcoin/merkleblock.js +++ b/lib/bcoin/merkleblock.js @@ -62,20 +62,13 @@ function MerkleBlock(data) { utils.inherits(MerkleBlock, bcoin.abstractblock); MerkleBlock.prototype.fromOptions = function fromOptions(data) { + assert(data); assert(Array.isArray(data.hashes)); assert(Buffer.isBuffer(data.flags)); this.hashes = data.hashes; this.flags = data.flags; - // List of matched TXs - this.map = {}; - this.matches = []; - this._validPartial = null; - - // TXs that will be pushed on - this.txs = []; - return this; }; @@ -403,6 +396,67 @@ MerkleBlock.fromRaw = function fromRaw(data, enc) { return new MerkleBlock().fromRaw(data); }; +/** + * Convert the block to an object suitable + * for JSON serialization. Note that the hashes + * will be reversed to abide by bitcoind's legacy + * of little-endian uint256s. + * @returns {Object} + */ + +MerkleBlock.prototype.toJSON = function toJSON() { + return { + type: 'merkleblock', + hash: this.rhash, + height: this.height, + version: this.version, + prevBlock: utils.revHex(this.prevBlock), + merkleRoot: utils.revHex(this.merkleRoot), + ts: this.ts, + bits: this.bits, + nonce: this.nonce, + totalTX: this.totalTX, + hashes: this.hashes, + flags: this.flags.toString('hex') + }; +}; + +/** + * Handle a deserialized JSON transaction object. + * @returns {Object} A "naked" block (a + * plain javascript object which is suitable + * for passing to the Block constructor). + */ + +MerkleBlock.prototype.fromJSON = function fromJSON(json) { + var i; + + assert.equal(json.type, 'merkleblock'); + + this.height = json.height; + this.version = json.version; + this.prevBlock = utils.revHex(json.prevBlock); + this.merkleRoot = utils.revHex(json.merkleRoot); + this.ts = json.ts; + this.bits = json.bits; + this.nonce = json.nonce; + this.totalTX = json.totalTX; + this.hashes = json.hashes; + this.flags = new Buffer(json.flags, 'hex'); + + return this; +}; + +/** + * Instantiate a merkle block from a jsonified block object. + * @param {Object} json - The jsonified block object. + * @returns {MerkleBlock} + */ + +MerkleBlock.fromJSON = function fromJSON(json) { + return new MerkleBlock().fromJSON(json); +}; + /** * Create a merkleblock from a {@link Block} object, passing * it through a filter first. This will build the partial @@ -418,7 +472,7 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) { var leaves = []; var bits = []; var hashes = []; - var i, tx, totalTX, height, flags, p; + var i, tx, totalTX, height, flags, p, merkle; for (i = 0; i < block.txs.length; i++) { tx = block.txs[i]; @@ -485,7 +539,7 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) { for (p = 0; p < bits.length; p++) flags[p / 8 | 0] |= bits[p] << (p % 8); - var merkle = new MerkleBlock(); + merkle = new MerkleBlock(); merkle.version = block.version; merkle.prevBlock = block.prevBlock; merkle.merkleRoot = block.merkleRoot; diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index 2f450d00..78788341 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -31,7 +31,7 @@ function Output(options, mutable) { return new Output(options, mutable); this.mutable = false; - this.value = 0; + this.value = null; this.script = null; if (options) diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 0c2fe161..ff0bbb31 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -70,6 +70,7 @@ function TX(data) { this._raw = null; this._size = null; this._witnessSize = null; + this._lastWitnessSize = 0; this._outputValue = null; this._inputValue = null; @@ -246,7 +247,6 @@ TX.prototype.render = function render(writer) { var raw = this.getRaw(); if (writer) { writer.writeBytes(raw); - writer._witnessSize = raw._witnessSize; return writer; } return raw; @@ -264,7 +264,6 @@ TX.prototype.renderNormal = function renderNormal(writer) { if (!TX.isWitness(raw)) { if (writer) { writer.writeBytes(raw); - writer._witnessSize = raw._witnessSize; return writer; } return raw; @@ -284,7 +283,6 @@ TX.prototype.renderWitness = function renderWitness(writer) { if (TX.isWitness(raw)) { if (writer) { writer.writeBytes(raw); - writer._witnessSize = raw._witnessSize; return writer; } return raw; @@ -306,6 +304,7 @@ TX.prototype.getRaw = function getRaw() { if (this._raw) { assert(this._size > 0); assert(this._witnessSize >= 0); + this._lastWitnessSize = this._witnessSize; return this._raw; } @@ -317,7 +316,7 @@ TX.prototype.getRaw = function getRaw() { if (!this.mutable) { this._raw = raw; this._size = raw.length; - this._witnessSize = raw._witnessSize; + this._witnessSize = this._lastWitnessSize; } return raw; @@ -332,11 +331,12 @@ TX.prototype.getSizes = function getSizes() { var writer; if (this.mutable) { + assert(!this._raw); writer = new BufferWriter(); this.toRaw(writer); return { size: writer.written, - witnessSize: writer._witnessSize + witnessSize: this._lastWitnessSize }; } @@ -2084,7 +2084,7 @@ TX.prototype.frameNormal = function frameNormal(writer) { if (!writer) p = p.render(); - p._witnessSize = 0; + this._lastWitnessSize = 0; return p; }; @@ -2127,7 +2127,7 @@ TX.prototype.frameWitness = function frameWitness(writer) { if (!writer) p = p.render(); - p._witnessSize = witnessSize + 2; + this._lastWitnessSize = witnessSize + 2; return p; }; diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index 2bff8188..64c81c70 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -603,18 +603,21 @@ utils.ensure = function ensure(callback) { /** * Reverse a hex-string (used because of * bitcoind's affinity for uint256le). - * @param {String} s - Hex string. + * @param {String} data - Hex string. * @returns {String} Reversed hex string. */ -utils.revHex = function revHex(s) { - var r = ''; - var i = 0; +utils.revHex = function revHex(data) { + var out = ''; + var i; - for (; i < s.length; i += 2) - r = s.slice(i, i + 2) + r; + if (!data) + return data; - return r; + for (i = 0; i < data.length; i += 2) + out = data.slice(i, i + 2) + out; + + return out; }; /** diff --git a/test/block-test.js b/test/block-test.js index f4942964..27dc0855 100644 --- a/test/block-test.js +++ b/test/block-test.js @@ -86,6 +86,13 @@ describe('Block', function() { assert(b.verify()); }); + it('should be jsonified and unjsonified and still verify', function() { + var raw = mblock.toJSON(); + var b = bcoin.merkleblock.fromJSON(raw); + assert.deepEqual(b.toJSON(), raw); + assert(b.verify()); + }); + it('should calculate reward properly', function() { var height = 0; var total = 0;