miner: compare cumulative descendant fee rate.

This commit is contained in:
Christopher Jeffrey 2017-02-26 03:09:33 -08:00
parent dcf7e7a9f4
commit cb7af959ce
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
5 changed files with 58 additions and 25 deletions

View File

@ -1160,10 +1160,10 @@ RPC.prototype._entryToJSON = function _entryToJSON(entry) {
height: entry.height, height: entry.height,
startingpriority: entry.priority, startingpriority: entry.priority,
currentpriority: entry.getPriority(this.chain.height), currentpriority: entry.getPriority(this.chain.height),
descendantcount: this.mempool.countDescendants(tx), descendantcount: this.mempool.countDescendants(entry),
descendantsize: entry.sizes, descendantsize: entry.sizes,
descendantfees: Amount.btc(entry.fee, true), descendantfees: Amount.btc(entry.fee, true),
ancestorcount: this.mempool.countAncestors(tx), ancestorcount: this.mempool.countAncestors(entry),
ancestorsize: entry.sizes, ancestorsize: entry.sizes,
ancestorfees: Amount.btc(entry.fee, true), ancestorfees: Amount.btc(entry.fee, true),
depends: this.mempool.getDepends(tx).map(util.revHex) depends: this.mempool.getDepends(tx).map(util.revHex)

View File

@ -860,7 +860,7 @@ Mempool.prototype.verify = co(function* verify(entry, view) {
throw new VerifyError(tx, 'highfee', 'absurdly-high-fee', 0); throw new VerifyError(tx, 'highfee', 'absurdly-high-fee', 0);
// Why do we have this here? Nested transactions are cool. // 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, throw new VerifyError(tx,
'nonstandard', 'nonstandard',
'too-long-mempool-chain', 'too-long-mempool-chain',
@ -1027,8 +1027,8 @@ Mempool.prototype.removeEntry = function removeEntry(entry, limit) {
* @returns {Number} * @returns {Number}
*/ */
Mempool.prototype.countAncestors = function countAncestors(tx) { Mempool.prototype.countAncestors = function countAncestors(entry, update) {
return this._countAncestors(tx, 0, {}); return this._countAncestors(entry, 0, {}, true);
}; };
/** /**
@ -1040,15 +1040,16 @@ Mempool.prototype.countAncestors = function countAncestors(tx) {
* @returns {Number} * @returns {Number}
*/ */
Mempool.prototype._countAncestors = function countAncestors(tx, count, set) { Mempool.prototype._countAncestors = function countAncestors(entry, count, set, update) {
var i, input, hash, prev; var tx = entry.tx;
var i, input, hash, pentry;
for (i = 0; i < tx.inputs.length; i++) { for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i]; input = tx.inputs[i];
hash = input.prevout.hash; hash = input.prevout.hash;
prev = this.getTX(hash); pentry = this.getEntry(hash);
if (!prev) if (!pentry)
continue; continue;
if (set[hash]) if (set[hash])
@ -1057,10 +1058,15 @@ Mempool.prototype._countAncestors = function countAncestors(tx, count, set) {
set[hash] = true; set[hash] = true;
count += 1; count += 1;
if (update) {
pentry.descFee += entry.fee;
pentry.descSize += entry.size;
}
if (count > this.options.maxAncestors) if (count > this.options.maxAncestors)
break; break;
count = this._countAncestors(prev, count, set); count = this._countAncestors(pentry, count, set);
if (count > this.options.maxAncestors) if (count > this.options.maxAncestors)
break; break;
@ -1076,8 +1082,8 @@ Mempool.prototype._countAncestors = function countAncestors(tx, count, set) {
* @returns {Number} * @returns {Number}
*/ */
Mempool.prototype.countDescendants = function countDescendants(tx) { Mempool.prototype.countDescendants = function countDescendants(entry) {
return this._countDescendants(tx, 0, {}); return this._countDescendants(entry, 0, {});
}; };
/** /**
@ -1090,17 +1096,18 @@ Mempool.prototype.countDescendants = function countDescendants(tx) {
* @returns {Number} * @returns {Number}
*/ */
Mempool.prototype._countDescendants = function countDescendants(tx, count, set) { Mempool.prototype._countDescendants = function countDescendants(entry, count, set) {
var hash = tx.hash('hex'); var tx = entry.tx;
var hash = entry.hash;
var i, next, nhash; var i, next, nhash;
for (i = 0; i < tx.outputs.length; i++) { for (i = 0; i < tx.outputs.length; i++) {
next = this.getSpentTX(hash, i); next = this.getSpent(hash, i);
if (!next) if (!next)
continue; continue;
nhash = next.hash('hex'); nhash = next.hash;
if (set[nhash]) if (set[nhash])
continue; continue;

View File

@ -40,6 +40,8 @@ function MempoolEntry(options) {
this.ts = 0; this.ts = 0;
this.value = 0; this.value = 0;
this.dependencies = false; this.dependencies = false;
this.descFee = 0;
this.descSize = 0;
if (options) if (options)
this.fromOptions(options); this.fromOptions(options);
@ -61,6 +63,8 @@ MempoolEntry.prototype.fromOptions = function fromOptions(options) {
this.ts = options.ts; this.ts = options.ts;
this.value = options.value; this.value = options.value;
this.dependencies = options.dependencies; this.dependencies = options.dependencies;
this.descFee = options.descFee;
this.descSize = options.descSize;
return this; return this;
}; };
@ -108,6 +112,8 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) {
this.ts = util.now(); this.ts = util.now();
this.value = value; this.value = value;
this.dependencies = dependencies; this.dependencies = dependencies;
this.descFee = fee;
this.descSize = size;
return this; return this;
}; };
@ -159,6 +165,15 @@ MempoolEntry.prototype.getRate = function getRate() {
return policy.getRate(this.size, this.fee); 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 * Test whether the entry is free with
* the current priority (calculated by * the current priority (calculated by

View File

@ -374,7 +374,7 @@ Miner.prototype.build = function build(attempt) {
var prev, deps, hashes, weight, sigops; var prev, deps, hashes, weight, sigops;
if (priority) if (priority)
queue.sort(cmpPriority); queue.set(cmpPriority);
if (!this.mempool) if (!this.mempool)
return []; return [];
@ -437,9 +437,8 @@ Miner.prototype.build = function build(attempt) {
if (priority) { if (priority) {
if (weight > this.options.priorityWeight if (weight > this.options.priorityWeight
|| item.priority < this.options.priorityThreshold) { || item.priority < this.options.priorityThreshold) {
// Todo: Compare descendant rate with queue.set(cmpRate);
// cumulative fees and cumulative vsize. queue.sort();
queue.sort(cmpRate);
priority = false; priority = false;
queue.push(item); queue.push(item);
continue; continue;
@ -623,8 +622,12 @@ MinerOptions.fromOptions = function fromOptions(options) {
*/ */
function Queue(cmp) { function Queue(cmp) {
this.cmp = cmp || null; if (!(this instanceof Queue))
return new Queue(cmp);
this.cmp = null;
this.items = []; this.items = [];
this.set(cmp);
} }
Queue.prototype.size = function size() { Queue.prototype.size = function size() {
@ -640,10 +643,15 @@ Queue.prototype.pop = function pop() {
return this.items.pop(); return this.items.pop();
}; };
Queue.prototype.sort = function sort(cmp) { Queue.prototype.set = function set(cmp) {
assert(cmp === null || typeof cmp === 'function', assert(cmp == null || typeof cmp === 'function',
'Comparator must be a 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) { function cmpRate(a, b) {
return a.rate - b.rate; return a.descRate - b.descRate;
} }
/* /*

View File

@ -584,6 +584,7 @@ function BlockEntry(tx) {
this.free = false; this.free = false;
this.sigops = 0; this.sigops = 0;
this.depCount = 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.priority = tx.getPriority(view, attempt.height);
entry.free = false; entry.free = false;
entry.sigops = tx.getSigopsCost(view, attempt.flags); entry.sigops = tx.getSigopsCost(view, attempt.flags);
entry.descRate = entry.rate;
return entry; return entry;
}; };
@ -618,6 +620,7 @@ BlockEntry.fromEntry = function fromEntry(entry, attempt) {
item.priority = entry.getPriority(attempt.height); item.priority = entry.getPriority(attempt.height);
item.free = entry.isFree(attempt.height); item.free = entry.isFree(attempt.height);
item.sigops = entry.sigops; item.sigops = entry.sigops;
item.descRate = entry.getDescRate();
return item; return item;
}; };