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,
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)

View File

@ -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;

View File

@ -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

View File

@ -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;
}
/*

View File

@ -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;
};