From cb7af959cecdac07d276db14202e556e2613eed2 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 26 Feb 2017 03:09:33 -0800 Subject: [PATCH] miner: compare cumulative descendant fee rate. --- lib/http/rpc.js | 4 ++-- lib/mempool/mempool.js | 35 +++++++++++++++++++++-------------- lib/mempool/mempoolentry.js | 15 +++++++++++++++ lib/mining/miner.js | 26 +++++++++++++++++--------- lib/mining/minerblock.js | 3 +++ 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 6f6a5466..58938ef2 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -1160,10 +1160,10 @@ RPC.prototype._entryToJSON = function _entryToJSON(entry) { height: entry.height, startingpriority: entry.priority, currentpriority: entry.getPriority(this.chain.height), - descendantcount: this.mempool.countDescendants(tx), + descendantcount: this.mempool.countDescendants(entry), descendantsize: entry.sizes, descendantfees: Amount.btc(entry.fee, true), - ancestorcount: this.mempool.countAncestors(tx), + ancestorcount: this.mempool.countAncestors(entry), ancestorsize: entry.sizes, ancestorfees: Amount.btc(entry.fee, true), depends: this.mempool.getDepends(tx).map(util.revHex) diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index b7f66aca..8f708303 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -860,7 +860,7 @@ Mempool.prototype.verify = co(function* verify(entry, view) { throw new VerifyError(tx, 'highfee', 'absurdly-high-fee', 0); // Why do we have this here? Nested transactions are cool. - if (this.countAncestors(tx) > this.options.maxAncestors) { + if (this.countAncestors(entry, true) > this.options.maxAncestors) { throw new VerifyError(tx, 'nonstandard', 'too-long-mempool-chain', @@ -1027,8 +1027,8 @@ Mempool.prototype.removeEntry = function removeEntry(entry, limit) { * @returns {Number} */ -Mempool.prototype.countAncestors = function countAncestors(tx) { - return this._countAncestors(tx, 0, {}); +Mempool.prototype.countAncestors = function countAncestors(entry, update) { + return this._countAncestors(entry, 0, {}, true); }; /** @@ -1040,15 +1040,16 @@ Mempool.prototype.countAncestors = function countAncestors(tx) { * @returns {Number} */ -Mempool.prototype._countAncestors = function countAncestors(tx, count, set) { - var i, input, hash, prev; +Mempool.prototype._countAncestors = function countAncestors(entry, count, set, update) { + var tx = entry.tx; + var i, input, hash, pentry; for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; hash = input.prevout.hash; - prev = this.getTX(hash); + pentry = this.getEntry(hash); - if (!prev) + if (!pentry) continue; if (set[hash]) @@ -1057,10 +1058,15 @@ Mempool.prototype._countAncestors = function countAncestors(tx, count, set) { set[hash] = true; count += 1; + if (update) { + pentry.descFee += entry.fee; + pentry.descSize += entry.size; + } + if (count > this.options.maxAncestors) break; - count = this._countAncestors(prev, count, set); + count = this._countAncestors(pentry, count, set); if (count > this.options.maxAncestors) break; @@ -1076,8 +1082,8 @@ Mempool.prototype._countAncestors = function countAncestors(tx, count, set) { * @returns {Number} */ -Mempool.prototype.countDescendants = function countDescendants(tx) { - return this._countDescendants(tx, 0, {}); +Mempool.prototype.countDescendants = function countDescendants(entry) { + return this._countDescendants(entry, 0, {}); }; /** @@ -1090,17 +1096,18 @@ Mempool.prototype.countDescendants = function countDescendants(tx) { * @returns {Number} */ -Mempool.prototype._countDescendants = function countDescendants(tx, count, set) { - var hash = tx.hash('hex'); +Mempool.prototype._countDescendants = function countDescendants(entry, count, set) { + var tx = entry.tx; + var hash = entry.hash; var i, next, nhash; for (i = 0; i < tx.outputs.length; i++) { - next = this.getSpentTX(hash, i); + next = this.getSpent(hash, i); if (!next) continue; - nhash = next.hash('hex'); + nhash = next.hash; if (set[nhash]) continue; diff --git a/lib/mempool/mempoolentry.js b/lib/mempool/mempoolentry.js index 4e8379cd..2bac093d 100644 --- a/lib/mempool/mempoolentry.js +++ b/lib/mempool/mempoolentry.js @@ -40,6 +40,8 @@ function MempoolEntry(options) { this.ts = 0; this.value = 0; this.dependencies = false; + this.descFee = 0; + this.descSize = 0; if (options) this.fromOptions(options); @@ -61,6 +63,8 @@ MempoolEntry.prototype.fromOptions = function fromOptions(options) { this.ts = options.ts; this.value = options.value; this.dependencies = options.dependencies; + this.descFee = options.descFee; + this.descSize = options.descSize; return this; }; @@ -108,6 +112,8 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) { this.ts = util.now(); this.value = value; this.dependencies = dependencies; + this.descFee = fee; + this.descSize = size; return this; }; @@ -159,6 +165,15 @@ MempoolEntry.prototype.getRate = function getRate() { return policy.getRate(this.size, this.fee); }; +/** + * Calculate fee cumulative descendant rate. + * @returns {Rate} + */ + +MempoolEntry.prototype.getDescRate = function getDescRate() { + return policy.getRate(this.descSize, this.descFee); +}; + /** * Test whether the entry is free with * the current priority (calculated by diff --git a/lib/mining/miner.js b/lib/mining/miner.js index f19704b5..83380ff1 100644 --- a/lib/mining/miner.js +++ b/lib/mining/miner.js @@ -374,7 +374,7 @@ Miner.prototype.build = function build(attempt) { var prev, deps, hashes, weight, sigops; if (priority) - queue.sort(cmpPriority); + queue.set(cmpPriority); if (!this.mempool) return []; @@ -437,9 +437,8 @@ Miner.prototype.build = function build(attempt) { if (priority) { if (weight > this.options.priorityWeight || item.priority < this.options.priorityThreshold) { - // Todo: Compare descendant rate with - // cumulative fees and cumulative vsize. - queue.sort(cmpRate); + queue.set(cmpRate); + queue.sort(); priority = false; queue.push(item); continue; @@ -623,8 +622,12 @@ MinerOptions.fromOptions = function fromOptions(options) { */ function Queue(cmp) { - this.cmp = cmp || null; + if (!(this instanceof Queue)) + return new Queue(cmp); + + this.cmp = null; this.items = []; + this.set(cmp); } Queue.prototype.size = function size() { @@ -640,10 +643,15 @@ Queue.prototype.pop = function pop() { return this.items.pop(); }; -Queue.prototype.sort = function sort(cmp) { - assert(cmp === null || typeof cmp === 'function', +Queue.prototype.set = function set(cmp) { + assert(cmp == null || typeof cmp === 'function', 'Comparator must be a function.'); - this.cmp = cmp; + this.cmp = cmp || null; +}; + +Queue.prototype.sort = function sort() { + assert(this.cmp, 'No comparator for queue.'); + this.items.sort(this.cmp); }; /* @@ -655,7 +663,7 @@ function cmpPriority(a, b) { } function cmpRate(a, b) { - return a.rate - b.rate; + return a.descRate - b.descRate; } /* diff --git a/lib/mining/minerblock.js b/lib/mining/minerblock.js index dcc80272..215e7fb7 100644 --- a/lib/mining/minerblock.js +++ b/lib/mining/minerblock.js @@ -584,6 +584,7 @@ function BlockEntry(tx) { this.free = false; this.sigops = 0; this.depCount = 0; + this.descRate = 0; } /** @@ -601,6 +602,7 @@ BlockEntry.fromTX = function fromTX(tx, view, attempt) { entry.priority = tx.getPriority(view, attempt.height); entry.free = false; entry.sigops = tx.getSigopsCost(view, attempt.flags); + entry.descRate = entry.rate; return entry; }; @@ -618,6 +620,7 @@ BlockEntry.fromEntry = function fromEntry(entry, attempt) { item.priority = entry.getPriority(attempt.height); item.free = entry.isFree(attempt.height); item.sigops = entry.sigops; + item.descRate = entry.getDescRate(); return item; };