Merge pull request #1 from braydonf/merkleblock
Added test to check that merkle nodes do not match, and misc jshint fixes
This commit is contained in:
commit
ae5723515e
|
@ -1,4 +1,5 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var BlockHeader = require('./blockheader');
|
var BlockHeader = require('./blockheader');
|
||||||
var BufferUtil = require('../util/buffer');
|
var BufferUtil = require('../util/buffer');
|
||||||
|
@ -18,6 +19,8 @@ var $ = require('../util/preconditions');
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function MerkleBlock(arg) {
|
function MerkleBlock(arg) {
|
||||||
|
/* jshint maxstatements: 18 */
|
||||||
|
|
||||||
if (!(this instanceof MerkleBlock)) {
|
if (!(this instanceof MerkleBlock)) {
|
||||||
return new MerkleBlock(arg);
|
return new MerkleBlock(arg);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +33,7 @@ function MerkleBlock(arg) {
|
||||||
} else if (_.isObject(arg)) {
|
} else if (_.isObject(arg)) {
|
||||||
var header;
|
var header;
|
||||||
if(arg.header instanceof BlockHeader) {
|
if(arg.header instanceof BlockHeader) {
|
||||||
header = arg.header
|
header = arg.header;
|
||||||
} else {
|
} else {
|
||||||
header = BlockHeader.fromJSON(JSON.stringify(arg.header));
|
header = BlockHeader.fromJSON(JSON.stringify(arg.header));
|
||||||
}
|
}
|
||||||
|
@ -71,7 +74,7 @@ function MerkleBlock(arg) {
|
||||||
*/
|
*/
|
||||||
MerkleBlock.fromBuffer = function fromBuffer(buf) {
|
MerkleBlock.fromBuffer = function fromBuffer(buf) {
|
||||||
return MerkleBlock.fromBufferReader(BufferReader(buf));
|
return MerkleBlock.fromBufferReader(BufferReader(buf));
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {BufferReader} - MerkleBlock data in a BufferReader object
|
* @param {BufferReader} - MerkleBlock data in a BufferReader object
|
||||||
|
@ -79,7 +82,7 @@ MerkleBlock.fromBuffer = function fromBuffer(buf) {
|
||||||
*/
|
*/
|
||||||
MerkleBlock.fromBufferReader = function fromBufferReader(br) {
|
MerkleBlock.fromBufferReader = function fromBufferReader(br) {
|
||||||
return new MerkleBlock(MerkleBlock._fromBufferReader(br));
|
return new MerkleBlock(MerkleBlock._fromBufferReader(br));
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String|Object} - A JSON String or Object
|
* @param {String|Object} - A JSON String or Object
|
||||||
|
@ -87,7 +90,7 @@ MerkleBlock.fromBufferReader = function fromBufferReader(br) {
|
||||||
*/
|
*/
|
||||||
MerkleBlock.fromJSON = function fromJSON(buf) {
|
MerkleBlock.fromJSON = function fromJSON(buf) {
|
||||||
return new MerkleBlock(MerkleBlock._fromJSON(buf));
|
return new MerkleBlock(MerkleBlock._fromJSON(buf));
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Buffer} - A buffer of the block
|
* @returns {Buffer} - A buffer of the block
|
||||||
|
@ -138,7 +141,7 @@ MerkleBlock.prototype.toJSON = function toJSON() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that the MerkleBlock is valid
|
* 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() {
|
MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
|
||||||
$.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array');
|
$.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array');
|
||||||
|
@ -161,20 +164,24 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return BufferUtil.equals(root, this.header.merkleRoot);
|
return BufferUtil.equals(root, this.header.merkleRoot);
|
||||||
}
|
};
|
||||||
|
|
||||||
/** Traverse a the tree in this MerkleBlock, validating it along the way
|
/**
|
||||||
|
* Traverse a the tree in this MerkleBlock, validating it along the way
|
||||||
* Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
|
* Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
|
||||||
* @param {Number} - Current height
|
* @param {Number} - depth - Current height
|
||||||
* @param {Number} - Current position in the tree
|
* @param {Number} - pos - Current position in the tree
|
||||||
* @param {Object} - Object with values that need to be mutated throughout the traversal
|
* @param {Object} - opts - Object with values that need to be mutated throughout the traversal
|
||||||
* @param {flagBitsUsed} - Number of flag bits used, should start at 0
|
* @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0
|
||||||
* @param {hashesUsed} - Number of hashes used, should start at 0
|
* @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0
|
||||||
* @param {tx} - Will finish populated by transactions found during traversal
|
* @param {Array} - opts.txs - Will finish populated by transactions found during traversal
|
||||||
* @returns {Buffer|null} - Buffer containing the Merkle Hash for that height
|
* @returns {Buffer|null} - Buffer containing the Merkle Hash for that height
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) {
|
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) {
|
||||||
|
/* jshint maxcomplexity: 12*/
|
||||||
|
/* jshint maxstatements: 20 */
|
||||||
|
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
opts.txs = opts.txs || [];
|
opts.txs = opts.txs || [];
|
||||||
opts.flagBitsUsed = opts.flagBitsUsed || 0;
|
opts.flagBitsUsed = opts.flagBitsUsed || 0;
|
||||||
|
@ -195,13 +202,13 @@ MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, p
|
||||||
return new Buffer(hash, 'hex');
|
return new Buffer(hash, 'hex');
|
||||||
} else {
|
} else {
|
||||||
var left = this._traverseMerkleTree(depth-1, pos*2, opts);
|
var left = this._traverseMerkleTree(depth-1, pos*2, opts);
|
||||||
var right = left;;
|
var right = left;
|
||||||
if(pos*2+1 < this._calcTreeWidth(depth-1)) {
|
if(pos*2+1 < this._calcTreeWidth(depth-1)) {
|
||||||
right = this._traverseMerkleTree(depth-1, pos*2+1, opts);
|
right = this._traverseMerkleTree(depth-1, pos*2+1, opts);
|
||||||
}
|
}
|
||||||
return Hash.sha256sha256(new Buffer.concat([left, right]));
|
return Hash.sha256sha256(new Buffer.concat([left, right]));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/** Calculates the width of a merkle tree at a given height.
|
/** Calculates the width of a merkle tree at a given height.
|
||||||
* Modeled after Bitcoin Core merkleblock.h CalcTreeWidth()
|
* Modeled after Bitcoin Core merkleblock.h CalcTreeWidth()
|
||||||
|
@ -211,7 +218,7 @@ MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, p
|
||||||
*/
|
*/
|
||||||
MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) {
|
MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) {
|
||||||
return (this.numTransactions + (1 << height) - 1) >> height;
|
return (this.numTransactions + (1 << height) - 1) >> height;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** Calculates the height of the merkle tree in this MerkleBlock
|
/** Calculates the height of the merkle tree in this MerkleBlock
|
||||||
* @param {Number} - Height at which we want the tree width
|
* @param {Number} - Height at which we want the tree width
|
||||||
|
@ -224,11 +231,11 @@ MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() {
|
||||||
height++;
|
height++;
|
||||||
}
|
}
|
||||||
return height;
|
return height;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Transaction|String} - Transaction or Transaction ID Hash
|
* @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
|
* @private
|
||||||
*/
|
*/
|
||||||
MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
|
MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
|
||||||
|
@ -245,8 +252,8 @@ MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
|
||||||
var txs = [];
|
var txs = [];
|
||||||
var height = this._calcTreeHeight();
|
var height = this._calcTreeHeight();
|
||||||
this._traverseMerkleTree(height, 0, { txs: txs });
|
this._traverseMerkleTree(height, 0, { txs: txs });
|
||||||
return txs.indexOf(hash) !== -1
|
return txs.indexOf(hash) !== -1;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Buffer} - MerkleBlock data
|
* @param {Buffer} - MerkleBlock data
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var should = require('chai').should();
|
||||||
|
|
||||||
var bitcore = require('..');
|
var bitcore = require('..');
|
||||||
var MerkleBlock = bitcore.MerkleBlock;
|
var MerkleBlock = bitcore.MerkleBlock;
|
||||||
var BufferReader = bitcore.encoding.BufferReader;
|
var BufferReader = bitcore.encoding.BufferReader;
|
||||||
|
@ -143,7 +146,7 @@ describe('MerkleBlock', function() {
|
||||||
|
|
||||||
it('should not validate merkleblocks with too few bit flags', function() {
|
it('should not validate merkleblocks with too few bit flags', function() {
|
||||||
var b = MerkleBlock(blockJSON);
|
var b = MerkleBlock(blockJSON);
|
||||||
b.flags.pop()
|
b.flags.pop();
|
||||||
b.validMerkleTree().should.equal(false);
|
b.validMerkleTree().should.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -175,6 +178,22 @@ describe('MerkleBlock', function() {
|
||||||
b.hasTransaction(tx).should.equal(false);
|
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]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue