mempool: evict by lowest fee rate.
This commit is contained in:
parent
ef92070a28
commit
210ce4c767
@ -31,6 +31,7 @@ var Fees = require('./fees');
|
|||||||
var Map = require('../utils/map');
|
var Map = require('../utils/map');
|
||||||
var CoinView = require('../coins/coinview');
|
var CoinView = require('../coins/coinview');
|
||||||
var Coins = require('../coins/coins');
|
var Coins = require('../coins/coins');
|
||||||
|
var Heap = require('../utils/heap');
|
||||||
var VerifyError = errors.VerifyError;
|
var VerifyError = errors.VerifyError;
|
||||||
var VerifyResult = errors.VerifyResult;
|
var VerifyResult = errors.VerifyResult;
|
||||||
|
|
||||||
@ -357,58 +358,74 @@ Mempool.prototype._reset = co(function* reset() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure the size of the mempool stays below 300mb.
|
* Ensure the size of the mempool stays below `maxSize`.
|
||||||
* @param {Hash} entryHash - TX that initiated the trim.
|
* Evicts entries by timestamp and cumulative fee rate.
|
||||||
|
* @param {MempoolEntry} added
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.limitSize = function limitSize(entryHash) {
|
Mempool.prototype.limitSize = function limitSize(added) {
|
||||||
|
var maxSize = this.options.maxSize;
|
||||||
|
var expiryTime = this.options.expiryTime;
|
||||||
|
var now = util.now();
|
||||||
var trimmed = false;
|
var trimmed = false;
|
||||||
var i, hashes, hash, end, entry;
|
var i, queue, entry, keys, hash, start;
|
||||||
|
|
||||||
if (this.getSize() <= this.options.maxSize)
|
if (this.size <= maxSize)
|
||||||
return trimmed;
|
return trimmed;
|
||||||
|
|
||||||
hashes = this.getSnapshot();
|
queue = new Heap(cmpRate);
|
||||||
end = util.now() - this.options.expiryTime;
|
keys = this.getSnapshot();
|
||||||
|
|
||||||
for (i = 0; i < hashes.length; i++) {
|
start = util.hrtime();
|
||||||
hash = hashes[i];
|
|
||||||
|
for (i = 0; i < keys.length; i++) {
|
||||||
|
hash = keys[i];
|
||||||
entry = this.getEntry(hash);
|
entry = this.getEntry(hash);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (entry.ts >= end)
|
if (now < entry.ts + expiryTime) {
|
||||||
|
queue.insert(entry);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!trimmed && hash === entryHash)
|
if (entry === added)
|
||||||
trimmed = true;
|
trimmed = true;
|
||||||
|
|
||||||
this.evictEntry(entry);
|
this.evictEntry(entry);
|
||||||
|
|
||||||
if (this.getSize() <= this.options.maxSize)
|
|
||||||
return trimmed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hashes = this.getSnapshot();
|
if (this.size <= maxSize)
|
||||||
|
return trimmed;
|
||||||
|
|
||||||
for (i = 0; i < hashes.length; i++) {
|
this.logger.debug(
|
||||||
hash = hashes[i];
|
'(bench) Heap mempool traversal: %d.',
|
||||||
entry = this.getEntry(hash);
|
util.hrtime(start));
|
||||||
|
|
||||||
if (!entry)
|
start = util.hrtime();
|
||||||
|
|
||||||
|
while (queue.size() > 0) {
|
||||||
|
entry = queue.shift();
|
||||||
|
hash = entry.hash('hex');
|
||||||
|
|
||||||
|
if (!this.hasTX(hash))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!trimmed && hash === entryHash)
|
|
||||||
trimmed = true;
|
|
||||||
|
|
||||||
this.evictEntry(entry);
|
this.evictEntry(entry);
|
||||||
|
|
||||||
if (this.getSize() <= this.options.maxSize)
|
if (entry === added)
|
||||||
return trimmed;
|
trimmed = true;
|
||||||
|
|
||||||
|
if (this.size <= maxSize - (maxSize / 10))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.debug(
|
||||||
|
'(bench) Heap mempool map removal: %d.',
|
||||||
|
util.hrtime(start));
|
||||||
|
|
||||||
return trimmed;
|
return trimmed;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -860,7 +877,7 @@ Mempool.prototype.insertTX = co(function* insertTX(tx) {
|
|||||||
yield this.addEntry(entry, view);
|
yield this.addEntry(entry, view);
|
||||||
|
|
||||||
// Trim size if we're too big.
|
// Trim size if we're too big.
|
||||||
if (this.limitSize(hash)) {
|
if (this.limitSize(entry)) {
|
||||||
throw new VerifyError(tx,
|
throw new VerifyError(tx,
|
||||||
'insufficientfee',
|
'insufficientfee',
|
||||||
'mempool full',
|
'mempool full',
|
||||||
@ -1084,7 +1101,9 @@ Mempool.prototype.addEntry = co(function* addEntry(entry, view) {
|
|||||||
if (this.fees)
|
if (this.fees)
|
||||||
this.fees.processTX(entry, this.chain.synced);
|
this.fees.processTX(entry, this.chain.synced);
|
||||||
|
|
||||||
this.logger.debug('Added tx %s to mempool.', tx.txid());
|
this.logger.debug(
|
||||||
|
'Added %s to mempool (txs=%d).',
|
||||||
|
tx.txid(), this.totalTX);
|
||||||
|
|
||||||
this.cache.save(entry);
|
this.cache.save(entry);
|
||||||
|
|
||||||
@ -1517,7 +1536,9 @@ Mempool.prototype.handleOrphans = co(function* handleOrphans(tx) {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Resolved orphan %s in mempool.', orphan.txid());
|
this.logger.debug(
|
||||||
|
'Resolved orphan %s in mempool (txs=%d).',
|
||||||
|
orphan.txid(), this.totalTX);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolved;
|
return resolved;
|
||||||
@ -2517,6 +2538,40 @@ function removeFee(parent, child) {
|
|||||||
parent.descSize -= child.descSize;
|
parent.descSize -= child.descSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cmpRate(a, b) {
|
||||||
|
var xf = a.fee;
|
||||||
|
var xs = a.size;
|
||||||
|
var yf = b.fee;
|
||||||
|
var ys = b.size;
|
||||||
|
var x, y;
|
||||||
|
|
||||||
|
if (useDesc(a)) {
|
||||||
|
xf = a.descFee;
|
||||||
|
xs = a.descSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useDesc(b)) {
|
||||||
|
yf = b.descFee;
|
||||||
|
ys = b.descSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = xf * ys;
|
||||||
|
y = xs * yf;
|
||||||
|
|
||||||
|
if (x === y) {
|
||||||
|
x = a.ts;
|
||||||
|
y = b.ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x - y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useDesc(a) {
|
||||||
|
var x = a.fee * a.descSize;
|
||||||
|
var y = a.descFee * a.size;
|
||||||
|
return y > x;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -132,6 +132,16 @@ MempoolEntry.fromTX = function fromTX(tx, view, height) {
|
|||||||
return new MempoolEntry().fromTX(tx, view, height);
|
return new MempoolEntry().fromTX(tx, view, height);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate transaction hash.
|
||||||
|
* @param {String?} enc
|
||||||
|
* @returns {Hash}
|
||||||
|
*/
|
||||||
|
|
||||||
|
MempoolEntry.prototype.hash = function hash(enc) {
|
||||||
|
return this.tx.hash(enc);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate priority, taking into account
|
* Calculate priority, taking into account
|
||||||
* the entry height delta, modified size,
|
* the entry height delta, modified size,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user