mempool: better ancestor and descendant traversal.

This commit is contained in:
Christopher Jeffrey 2016-11-17 23:21:01 -08:00
parent f625013548
commit 9e1428a8d5
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -384,6 +384,17 @@ Mempool.prototype.getCoin = function getCoin(hash, index) {
*/ */
Mempool.prototype.isSpent = function isSpent(hash, index) { Mempool.prototype.isSpent = function isSpent(hash, index) {
return this.spents[hash + index] != null;
};
/**
* Get an output's spender transaction.
* @param {Hash} hash
* @param {Number} index
* @returns {MempoolEntry}
*/
Mempool.prototype.getSpent = function getSpent(hash, index) {
return this.spents[hash + index]; return this.spents[hash + index];
}; };
@ -1076,24 +1087,44 @@ Mempool.prototype.checkInputs = co(function* checkInputs(tx, flags) {
*/ */
Mempool.prototype.countAncestors = function countAncestors(tx) { Mempool.prototype.countAncestors = function countAncestors(tx) {
var max = 0; return this._countAncestors(tx, {}, 0);
var i, input, count, prev; };
/**
* Traverse ancestors and count.
* @private
* @param {TX} tx
* @param {Object} set
* @param {Number} count
*/
Mempool.prototype._countAncestors = function countAncestors(tx, set, count) {
var i, input, hash, prev;
for (i = 0; i < tx.inputs.length; i++) { for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i]; input = tx.inputs[i];
prev = this.getTX(input.prevout.hash); hash = input.prevout.hash;
prev = this.getTX(hash);
if (!prev) if (!prev)
continue; continue;
count = 1; if (set[hash])
count += this.countAncestors(prev); continue;
if (count > max) set[hash] = true;
max = count; count += 1;
if (count > constants.mempool.ANCESTOR_LIMIT)
break;
count = this._countAncestors(prev, set, count);
if (count > constants.mempool.ANCESTOR_LIMIT)
break;
} }
return max; return count;
}; };
/** /**
@ -1104,24 +1135,40 @@ Mempool.prototype.countAncestors = function countAncestors(tx) {
*/ */
Mempool.prototype.countDescendants = function countDescendants(tx) { Mempool.prototype.countDescendants = function countDescendants(tx) {
var max = 0; return this._countDescendants(tx, {}, 0);
};
/**
* Count the highest number of
* descendants a transaction may have.
* @private
* @param {TX} tx
* @returns {Number}
*/
Mempool.prototype._countDescendants = function countDescendants(tx, set, count) {
var hash = tx.hash('hex'); var hash = tx.hash('hex');
var i, count, next; var i, entry, next, nhash;
for (i = 0; i < tx.outputs.length; i++) { for (i = 0; i < tx.outputs.length; i++) {
next = this.isSpent(hash, i); entry = this.getSpent(hash, i);
if (!next) if (!entry)
continue; continue;
count = 1; next = entry.tx;
count += this.countDescendants(next.tx); nhash = next.hash('hex');
if (count > max) if (set[nhash])
max = count; continue;
set[nhash] = true;
count += 1;
count = this._countDescendants(next, set, count);
} }
return max; return count;
}; };
/** /**
@ -1131,23 +1178,35 @@ Mempool.prototype.countDescendants = function countDescendants(tx) {
*/ */
Mempool.prototype.getAncestors = function getAncestors(tx) { Mempool.prototype.getAncestors = function getAncestors(tx) {
var self = this; return this._getAncestors(tx, [], {});
var entries = []; };
(function traverse(tx) { /**
var i, input, prev; * Get all transaction ancestors.
* @private
* @param {TX} tx
* @returns {MempoolEntry[]}
*/
for (i = 0; i < tx.inputs.length; i++) { Mempool.prototype._getAncestors = function getAncestors(tx, entries, set) {
input = tx.inputs[i]; var i, hash, input, prev;
prev = self.getTX(input.prevout.hash);
if (!prev) for (i = 0; i < tx.inputs.length; i++) {
continue; input = tx.inputs[i];
hash = input.prevout.hash;
prev = this.getTX(hash);
entries.push(prev); if (!prev)
traverse(prev); continue;
}
})(tx); if (set[hash])
continue;
set[hash] = true;
entries.push(prev);
this._getAncestors(prev, entries, set);
}
return entries; return entries;
}; };
@ -1159,23 +1218,36 @@ Mempool.prototype.getAncestors = function getAncestors(tx) {
*/ */
Mempool.prototype.getDescendants = function getDescendants(tx) { Mempool.prototype.getDescendants = function getDescendants(tx) {
var self = this; return this._getDescendants(tx, [], {});
var entries = []; };
(function traverse(tx) { /**
var hash = tx.hash('hex'); * Get all a transaction descendants.
var i, next; * @param {TX} tx
* @returns {MempoolEntry[]}
*/
for (i = 0; i < tx.outputs.length; i++) { Mempool.prototype._getDescendants = function getDescendants(tx, entries, set) {
next = self.isSpent(hash, i); var hash = tx.hash('hex');
var i, entry, next, nhash;
if (!next) for (i = 0; i < tx.outputs.length; i++) {
continue; entry = this.getSpent(hash, i);
entries.push(next); if (!entry)
traverse(next.tx); continue;
}
})(tx); next = entry.tx;
nhash = next.hash('hex');
if (set[nhash])
continue;
set[nhash] = true;
entries.push(next);
this._getDescendants(next, entries, set);
}
return entries; return entries;
}; };
@ -1671,7 +1743,7 @@ Mempool.prototype.removeSpenders = function removeSpenders(entry) {
var i, spender; var i, spender;
for (i = 0; i < tx.outputs.length; i++) { for (i = 0; i < tx.outputs.length; i++) {
spender = this.isSpent(hash, i); spender = this.getSpent(hash, i);
if (!spender) if (!spender)
continue; continue;