From 9e1428a8d5bd80e769301e64780b698f0932a4e2 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 17 Nov 2016 23:21:01 -0800 Subject: [PATCH] mempool: better ancestor and descendant traversal. --- lib/mempool/mempool.js | 160 +++++++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 44 deletions(-) diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 889ab2f6..b8b2c7b5 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -384,6 +384,17 @@ Mempool.prototype.getCoin = function getCoin(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]; }; @@ -1076,24 +1087,44 @@ Mempool.prototype.checkInputs = co(function* checkInputs(tx, flags) { */ Mempool.prototype.countAncestors = function countAncestors(tx) { - var max = 0; - var i, input, count, prev; + return this._countAncestors(tx, {}, 0); +}; + +/** + * 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++) { input = tx.inputs[i]; - prev = this.getTX(input.prevout.hash); + hash = input.prevout.hash; + prev = this.getTX(hash); if (!prev) continue; - count = 1; - count += this.countAncestors(prev); + if (set[hash]) + continue; - if (count > max) - max = count; + set[hash] = true; + 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) { - 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 i, count, next; + var i, entry, next, nhash; for (i = 0; i < tx.outputs.length; i++) { - next = this.isSpent(hash, i); + entry = this.getSpent(hash, i); - if (!next) + if (!entry) continue; - count = 1; - count += this.countDescendants(next.tx); + next = entry.tx; + nhash = next.hash('hex'); - if (count > max) - max = count; + if (set[nhash]) + 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) { - var self = this; - var entries = []; + return this._getAncestors(tx, [], {}); +}; - (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++) { - input = tx.inputs[i]; - prev = self.getTX(input.prevout.hash); +Mempool.prototype._getAncestors = function getAncestors(tx, entries, set) { + var i, hash, input, prev; - if (!prev) - continue; + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + hash = input.prevout.hash; + prev = this.getTX(hash); - entries.push(prev); - traverse(prev); - } - })(tx); + if (!prev) + continue; + + if (set[hash]) + continue; + + set[hash] = true; + entries.push(prev); + + this._getAncestors(prev, entries, set); + } return entries; }; @@ -1159,23 +1218,36 @@ Mempool.prototype.getAncestors = function getAncestors(tx) { */ Mempool.prototype.getDescendants = function getDescendants(tx) { - var self = this; - var entries = []; + return this._getDescendants(tx, [], {}); +}; - (function traverse(tx) { - var hash = tx.hash('hex'); - var i, next; +/** + * Get all a transaction descendants. + * @param {TX} tx + * @returns {MempoolEntry[]} + */ - for (i = 0; i < tx.outputs.length; i++) { - next = self.isSpent(hash, i); +Mempool.prototype._getDescendants = function getDescendants(tx, entries, set) { + var hash = tx.hash('hex'); + var i, entry, next, nhash; - if (!next) - continue; + for (i = 0; i < tx.outputs.length; i++) { + entry = this.getSpent(hash, i); - entries.push(next); - traverse(next.tx); - } - })(tx); + if (!entry) + continue; + + next = entry.tx; + nhash = next.hash('hex'); + + if (set[nhash]) + continue; + + set[nhash] = true; + entries.push(next); + + this._getDescendants(next, entries, set); + } return entries; }; @@ -1671,7 +1743,7 @@ Mempool.prototype.removeSpenders = function removeSpenders(entry) { var i, spender; for (i = 0; i < tx.outputs.length; i++) { - spender = this.isSpent(hash, i); + spender = this.getSpent(hash, i); if (!spender) continue;