Review Fixes

This commit is contained in:
William Wolf 2015-02-23 08:46:33 -08:00
parent a67084d176
commit a478e39524
2 changed files with 57 additions and 53 deletions

View File

@ -57,10 +57,12 @@ function MerkleBlock(arg) {
flags: arg.flags
};
} else {
throw new TypeError('Unrecognized argument for Block');
throw new TypeError('Unrecognized argument for MerkleBlock');
}
_.extend(this,info);
this._validMerkleTree = null;
this._flagBitsUsed = 0;
this._hashesUsed = 0;
return this;
}
@ -140,13 +142,10 @@ MerkleBlock.prototype.toJSON = function toJSON() {
* @returns {Bool} - True/False whether this MerkleBlock is Valid
*/
MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
$.checkState(this.flags instanceof Array, 'MerkleBlock flags is not an array');
$.checkState(this.hashes instanceof Array, 'MerkleBlock flags is not an array');
var self = this;
if(this._validMerkleTree === true) {
return true;
} else if (this._validMerkleTree === false) {
return false;
$.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array');
$.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array');
if(_.isBoolean(this._validMerkleTree)) {
return this._validMerkleTree;
}
// Can't have more hashes than numTransactions
@ -159,50 +158,58 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
return this._setValidMerkleTree(false);
}
// Calculate height of tree
// From Bitcoin Core merkleblock.h CalcTreeWidth() + CPartialMerkleTree
var height = 0;
while (calcTreeWidth(height) > 1) {
while (this._calcTreeWidth(height) > 1) {
height++;
}
var flagBitsUsed = 0;
var hashesUsed = 0;
// Modeled after Bitcoin Core merkleblock.h CalcTreeWidth()
function calcTreeWidth(height) {
return (self.numTransactions + (1 << height) - 1) >> height;
this._flagBitsUsed = 0;
this._hashesUsed = 0;
var root = this._traverseMerkleTree(height, 0);
if(this._hashesUsed !== this.hashes.length) {
return this._setValidMerkleTree(false);
}
return this._setValidMerkleTree(BufferUtil.equals(root, this.header.merkleRoot));
}
// Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
function traverse(depth, pos) {
if(flagBitsUsed > self.flags.length * 8) {
/** 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
* @returns {Buffer|null} - Buffer containing the Merkle Hash far that height
* @private
*/
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos) {
if(this._flagBitsUsed > this.flags.length * 8) {
return null;
}
var isParentOfMatch = (self.flags[flagBitsUsed >> 3] >>> (flagBitsUsed++ & 7)) & 1;
var isParentOfMatch = (this.flags[this._flagBitsUsed >> 3] >>> (this._flagBitsUsed++ & 7)) & 1;
if(depth === 0 || !isParentOfMatch) {
if(hashesUsed >= self.hashes.length) {
if(this._hashesUsed >= this.hashes.length) {
return null;
}
var hash = self.hashes[hashesUsed++];
var hash = this.hashes[this._hashesUsed++];
return new Buffer(hash, 'hex');
} else {
var left = traverse(depth-1, pos*2);
var left = this._traverseMerkleTree(depth-1, pos*2);
var right;
if(pos*2+1 < calcTreeWidth(depth-1)) {
right = traverse(depth-1, pos*2+1);
if(pos*2+1 < this._calcTreeWidth(depth-1)) {
right = this._traverseMerkleTree(depth-1, pos*2+1);
} else {
right = left;
}
return Hash.sha256sha256(new Buffer.concat([left, right]));
}
}
}
var root = traverse(height, 0);
if(hashesUsed !== this.hashes.length) {
return this._setValidMerkleTree(false);
}
return this._setValidMerkleTree(BufferUtil.equals(root, this.header.merkleRoot));
/** Calculates the width of a merkle tree at a given height.
* Modeled after Bitcoin Core merkleblock.h CalcTreeWidth()
* @param {Number} - Height at which we want the tree width
* @returns {Number} - Width of the tree at a given height
* @private
*/
MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) {
return (this.numTransactions + (1 << height) - 1) >> height;
}
/**
@ -211,14 +218,11 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
* @private
*/
MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
$.checkArgument(!_.isUndefined(tx), 'No transaction given');
$.checkArgument(tx instanceof Transaction
|| typeof tx === 'string', 'No transaction given');
$.checkArgument(!_.isUndefined(tx), 'tx cannot be undefined');
$.checkArgument(tx instanceof Transaction || typeof tx === 'string',
'Invalid tx given, tx must be a "string" or "Transaction"');
var hash = tx;
if(tx instanceof Transaction) {
hash = tx.id;
}
var hash = tx.id || tx;
var revHash = BufferUtil.reverse(new Buffer(hash,'hex')).toString('hex');
return (this.hashes.indexOf(hash) !== -1

View File

@ -34,7 +34,7 @@ describe('MerkleBlock', function() {
it('should not make an empty block', function() {
(function() {
return new MerkleBlock();
}).should.throw('Unrecognized argument for Block');
}).should.throw('Unrecognized argument for MerkleBlock');
});
});