From fb01bc09e45ae08ce301eedcf19d6db6ecfe0bbe Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 24 Feb 2015 11:37:08 -0500 Subject: [PATCH] Added test to check that merkle nodes do not match, and misc jshint fixes. --- lib/block/merkleblock.js | 49 +++++++++++++++++++++++----------------- test/merkleblock.js | 21 ++++++++++++++++- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/lib/block/merkleblock.js b/lib/block/merkleblock.js index a95d64e..331d8c1 100644 --- a/lib/block/merkleblock.js +++ b/lib/block/merkleblock.js @@ -1,4 +1,5 @@ 'use strict'; + var _ = require('lodash'); var BlockHeader = require('./blockheader'); var BufferUtil = require('../util/buffer'); @@ -18,6 +19,8 @@ var $ = require('../util/preconditions'); * @constructor */ function MerkleBlock(arg) { + /* jshint maxstatements: 18 */ + if (!(this instanceof MerkleBlock)) { return new MerkleBlock(arg); } @@ -30,7 +33,7 @@ function MerkleBlock(arg) { } else if (_.isObject(arg)) { var header; if(arg.header instanceof BlockHeader) { - header = arg.header + header = arg.header; } else { header = BlockHeader.fromJSON(JSON.stringify(arg.header)); } @@ -71,7 +74,7 @@ function MerkleBlock(arg) { */ MerkleBlock.fromBuffer = function fromBuffer(buf) { return MerkleBlock.fromBufferReader(BufferReader(buf)); -} +}; /** * @param {BufferReader} - MerkleBlock data in a BufferReader object @@ -79,7 +82,7 @@ MerkleBlock.fromBuffer = function fromBuffer(buf) { */ MerkleBlock.fromBufferReader = function fromBufferReader(br) { return new MerkleBlock(MerkleBlock._fromBufferReader(br)); -} +}; /** * @param {String|Object} - A JSON String or Object @@ -87,7 +90,7 @@ MerkleBlock.fromBufferReader = function fromBufferReader(br) { */ MerkleBlock.fromJSON = function fromJSON(buf) { return new MerkleBlock(MerkleBlock._fromJSON(buf)); -} +}; /** * @returns {Buffer} - A buffer of the block @@ -138,7 +141,7 @@ MerkleBlock.prototype.toJSON = function toJSON() { /** * Verify that the MerkleBlock is valid - * @returns {Bool} - True/False whether this MerkleBlock is Valid + * @returns {Boolean} - True/False whether this MerkleBlock is Valid */ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() { $.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array'); @@ -161,20 +164,24 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() { return false; } return BufferUtil.equals(root, this.header.merkleRoot); -} +}; -/** Traverse a the tree in this MerkleBlock, validating it along the way - * Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract() - * @param {Number} - Current height - * @param {Number} - Current position in the tree - * @param {Object} - Object with values that need to be mutated throughout the traversal - * @param {flagBitsUsed} - Number of flag bits used, should start at 0 - * @param {hashesUsed} - Number of hashes used, should start at 0 - * @param {tx} - Will finish populated by transactions found during traversal +/** + * Traverse a the tree in this MerkleBlock, validating it along the way + * Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract() + * @param {Number} - depth - Current height + * @param {Number} - pos - Current position in the tree + * @param {Object} - opts - Object with values that need to be mutated throughout the traversal + * @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0 + * @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0 + * @param {Array} - opts.txs - Will finish populated by transactions found during traversal * @returns {Buffer|null} - Buffer containing the Merkle Hash for that height * @private */ MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) { + /* jshint maxcomplexity: 12*/ + /* jshint maxstatements: 20 */ + opts = opts || {}; opts.txs = opts.txs || []; opts.flagBitsUsed = opts.flagBitsUsed || 0; @@ -195,13 +202,13 @@ MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, p return new Buffer(hash, 'hex'); } else { var left = this._traverseMerkleTree(depth-1, pos*2, opts); - var right = left;; + var right = left; if(pos*2+1 < this._calcTreeWidth(depth-1)) { right = this._traverseMerkleTree(depth-1, pos*2+1, opts); } return Hash.sha256sha256(new Buffer.concat([left, right])); } -} +}; /** Calculates the width of a merkle tree at a given height. * Modeled after Bitcoin Core merkleblock.h CalcTreeWidth() @@ -211,7 +218,7 @@ MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, p */ MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) { return (this.numTransactions + (1 << height) - 1) >> height; -} +}; /** Calculates the height of the merkle tree in this MerkleBlock * @param {Number} - Height at which we want the tree width @@ -224,11 +231,11 @@ MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() { height++; } return height; -} +}; /** * @param {Transaction|String} - Transaction or Transaction ID Hash - * @returns {Bool} - return true/false if this MerkleBlock has the TX or not + * @returns {Boolean} - return true/false if this MerkleBlock has the TX or not * @private */ MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) { @@ -245,8 +252,8 @@ MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) { var txs = []; var height = this._calcTreeHeight(); this._traverseMerkleTree(height, 0, { txs: txs }); - return txs.indexOf(hash) !== -1 -} + return txs.indexOf(hash) !== -1; +}; /** * @param {Buffer} - MerkleBlock data diff --git a/test/merkleblock.js b/test/merkleblock.js index ed020f3..f2e95ca 100644 --- a/test/merkleblock.js +++ b/test/merkleblock.js @@ -1,4 +1,7 @@ 'use strict'; + +var should = require('chai').should(); + var bitcore = require('..'); var MerkleBlock = bitcore.MerkleBlock; var BufferReader = bitcore.encoding.BufferReader; @@ -143,7 +146,7 @@ describe('MerkleBlock', function() { it('should not validate merkleblocks with too few bit flags', function() { var b = MerkleBlock(blockJSON); - b.flags.pop() + b.flags.pop(); b.validMerkleTree().should.equal(false); }); @@ -175,6 +178,22 @@ describe('MerkleBlock', function() { b.hasTransaction(tx).should.equal(false); }); + it('should not match with merkle nodes', function() { + var b = MerkleBlock(JSON.stringify(data.JSON[0])); + + var hashData = [ + ['3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2', false], + ['019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65', true], + ['41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068', false], + ['20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf', false] + ]; + + hashData.forEach(function check(d){ + b.hasTransaction(d[0]).should.equal(d[1]); + }); + + }); + }); });