_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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var height = 0;
|
var height = this._calcTreeHeight();
|
||||||
while (this._calcTreeWidth(height) > 1) {
|
var opts = { hashesUsed: 0, flagBitsUsed: 0 };
|
||||||
height++;
|
var root = this._traverseMerkleTree(height, 0, opts);
|
||||||
}
|
if(opts.hashesUsed !== this.hashes.length) {
|
||||||
|
return false;
|
||||||
this._flagBitsUsed = 0;
|
|
||||||
this._hashesUsed = 0;
|
|
||||||
var root = this._traverseMerkleTree(height, 0);
|
|
||||||
if(this._hashesUsed !== this.hashes.length) {
|
|
||||||
false;
|
|
||||||
}
|
}
|
||||||
return BufferUtil.equals(root, this.header.merkleRoot);
|
return BufferUtil.equals(root, this.header.merkleRoot);
|
||||||
}
|
}
|
||||||
@ -172,27 +167,37 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
|
|||||||
* Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
|
* Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
|
||||||
* @param {Number} - Current height
|
* @param {Number} - Current height
|
||||||
* @param {Number} - Current position in the tree
|
* @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
|
* @private
|
||||||
*/
|
*/
|
||||||
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos) {
|
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) {
|
||||||
if(this._flagBitsUsed > this.flags.length * 8) {
|
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;
|
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(depth === 0 || !isParentOfMatch) {
|
||||||
if(this._hashesUsed >= this.hashes.length) {
|
if(opts.hashesUsed >= this.hashes.length) {
|
||||||
return null;
|
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');
|
return new Buffer(hash, 'hex');
|
||||||
} else {
|
} else {
|
||||||
var left = this._traverseMerkleTree(depth-1, pos*2);
|
var left = this._traverseMerkleTree(depth-1, pos*2, opts);
|
||||||
var right;
|
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);
|
right = this._traverseMerkleTree(depth-1, pos*2+1, opts);
|
||||||
} else {
|
|
||||||
right = left;
|
|
||||||
}
|
}
|
||||||
return Hash.sha256sha256(new Buffer.concat([left, right]));
|
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;
|
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
|
* @param {Transaction|String} - Transaction or Transaction ID Hash
|
||||||
* @returns {Bool} - return true/false if this MerkleBlock has the TX or not
|
* @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',
|
$.checkArgument(tx instanceof Transaction || typeof tx === 'string',
|
||||||
'Invalid tx given, tx must be a "string" or "Transaction"');
|
'Invalid tx given, tx must be a "string" or "Transaction"');
|
||||||
|
|
||||||
var hash = tx.id || tx;
|
var hash = tx;
|
||||||
var revHash = BufferUtil.reverse(new Buffer(hash,'hex')).toString('hex');
|
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
|
var txs = [];
|
||||||
|| this.hashes.indexOf(revHash) !== -1);
|
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 MerkleBlock = bitcore.MerkleBlock;
|
||||||
var BufferReader = bitcore.encoding.BufferReader;
|
var BufferReader = bitcore.encoding.BufferReader;
|
||||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||||
var BufferUtil = bitcore.util.buffer;
|
|
||||||
var Transaction = bitcore.Transaction;
|
var Transaction = bitcore.Transaction;
|
||||||
var data = require('./data/merkleblocks.js');
|
var data = require('./data/merkleblocks.js');
|
||||||
var transactionVector = require('./data/tx_creation');
|
var transactionVector = require('./data/tx_creation');
|
||||||
@ -154,7 +153,7 @@ describe('MerkleBlock', function() {
|
|||||||
|
|
||||||
it('should find transactions via hash string', function() {
|
it('should find transactions via hash string', function() {
|
||||||
var json = data.JSON[0];
|
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));
|
var b = MerkleBlock(JSON.stringify(json));
|
||||||
b.hasTransaction(txId).should.equal(true);
|
b.hasTransaction(txId).should.equal(true);
|
||||||
b.hasTransaction(txId + 'abcd').should.equal(false);
|
b.hasTransaction(txId + 'abcd').should.equal(false);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user