_traverseMerkleTree state cleanup + improve hasTransactions()
This commit is contained in:
parent
bb0efd2108
commit
3eb95b6576
|
@ -154,16 +154,11 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
|
|||
return false;
|
||||
}
|
||||
|
||||
var height = 0;
|
||||
while (this._calcTreeWidth(height) > 1) {
|
||||
height++;
|
||||
}
|
||||
|
||||
this._flagBitsUsed = 0;
|
||||
this._hashesUsed = 0;
|
||||
var root = this._traverseMerkleTree(height, 0);
|
||||
if(this._hashesUsed !== this.hashes.length) {
|
||||
false;
|
||||
var height = this._calcTreeHeight();
|
||||
var opts = { hashesUsed: 0, flagBitsUsed: 0 };
|
||||
var root = this._traverseMerkleTree(height, 0, opts);
|
||||
if(opts.hashesUsed !== this.hashes.length) {
|
||||
return false;
|
||||
}
|
||||
return BufferUtil.equals(root, this.header.merkleRoot);
|
||||
}
|
||||
|
@ -172,27 +167,37 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
|
|||
* 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
|
||||
* @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
|
||||
* @returns {Buffer|null} - Buffer containing the Merkle Hash for that height
|
||||
* @private
|
||||
*/
|
||||
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos) {
|
||||
if(this._flagBitsUsed > this.flags.length * 8) {
|
||||
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) {
|
||||
opts = opts || {};
|
||||
opts.txs = opts.txs || [];
|
||||
opts.flagBitsUsed = opts.flagBitsUsed || 0;
|
||||
opts.hashesUsed = opts.hashesUsed || 0;
|
||||
|
||||
if(opts.flagBitsUsed > this.flags.length * 8) {
|
||||
return null;
|
||||
}
|
||||
var isParentOfMatch = (this.flags[this._flagBitsUsed >> 3] >>> (this._flagBitsUsed++ & 7)) & 1;
|
||||
var isParentOfMatch = (this.flags[opts.flagBitsUsed >> 3] >>> (opts.flagBitsUsed++ & 7)) & 1;
|
||||
if(depth === 0 || !isParentOfMatch) {
|
||||
if(this._hashesUsed >= this.hashes.length) {
|
||||
if(opts.hashesUsed >= this.hashes.length) {
|
||||
return null;
|
||||
}
|
||||
var hash = this.hashes[this._hashesUsed++];
|
||||
var hash = this.hashes[opts.hashesUsed++];
|
||||
if(depth === 0 && isParentOfMatch) {
|
||||
opts.txs.push(hash);
|
||||
}
|
||||
return new Buffer(hash, 'hex');
|
||||
} else {
|
||||
var left = this._traverseMerkleTree(depth-1, pos*2);
|
||||
var right;
|
||||
var left = this._traverseMerkleTree(depth-1, pos*2, opts);
|
||||
var right = left;;
|
||||
if(pos*2+1 < this._calcTreeWidth(depth-1)) {
|
||||
right = this._traverseMerkleTree(depth-1, pos*2+1);
|
||||
} else {
|
||||
right = left;
|
||||
right = this._traverseMerkleTree(depth-1, pos*2+1, opts);
|
||||
}
|
||||
return Hash.sha256sha256(new Buffer.concat([left, right]));
|
||||
}
|
||||
|
@ -208,6 +213,19 @@ 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
|
||||
* @returns {Number} - Height of the merkle tree in this MerkleBlock
|
||||
* @private
|
||||
*/
|
||||
MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() {
|
||||
var height = 0;
|
||||
while (this._calcTreeWidth(height) > 1) {
|
||||
height++;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction|String} - Transaction or Transaction ID Hash
|
||||
* @returns {Bool} - return true/false if this MerkleBlock has the TX or not
|
||||
|
@ -218,11 +236,16 @@ MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
|
|||
$.checkArgument(tx instanceof Transaction || typeof tx === 'string',
|
||||
'Invalid tx given, tx must be a "string" or "Transaction"');
|
||||
|
||||
var hash = tx.id || tx;
|
||||
var revHash = BufferUtil.reverse(new Buffer(hash,'hex')).toString('hex');
|
||||
var hash = tx;
|
||||
if(tx instanceof Transaction) {
|
||||
// We need to reverse the id hash for the lookup
|
||||
hash = BufferUtil.reverse(new Buffer(tx.id, 'hex')).toString('hex');
|
||||
}
|
||||
|
||||
return (this.hashes.indexOf(hash) !== -1
|
||||
|| this.hashes.indexOf(revHash) !== -1);
|
||||
var txs = [];
|
||||
var height = this._calcTreeHeight();
|
||||
this._traverseMerkleTree(height, 0, { txs: txs });
|
||||
return txs.indexOf(hash) !== -1
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,7 +3,6 @@ var bitcore = require('..');
|
|||
var MerkleBlock = bitcore.MerkleBlock;
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var BufferUtil = bitcore.util.buffer;
|
||||
var Transaction = bitcore.Transaction;
|
||||
var data = require('./data/merkleblocks.js');
|
||||
var transactionVector = require('./data/tx_creation');
|
||||
|
@ -154,7 +153,7 @@ describe('MerkleBlock', function() {
|
|||
|
||||
it('should find transactions via hash string', function() {
|
||||
var json = data.JSON[0];
|
||||
var txId = BufferUtil.reverse(new Buffer(json.hashes[1],'hex')).toString('hex');
|
||||
var txId = new Buffer(json.hashes[1],'hex').toString('hex');
|
||||
var b = MerkleBlock(JSON.stringify(json));
|
||||
b.hasTransaction(txId).should.equal(true);
|
||||
b.hasTransaction(txId + 'abcd').should.equal(false);
|
||||
|
|
Loading…
Reference in New Issue