diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 3b6d51e1..7e2e3760 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -708,6 +708,9 @@ RPC.prototype.getRawMempool = co(function* getRawMempool(args, help) { if (help || args.length > 1) throw new RPCError('getrawmempool ( verbose )'); + if (!this.mempool) + throw new RPCError('No mempool available.'); + if (verbose) { hashes = this.mempool.getSnapshot(); @@ -748,8 +751,11 @@ RPC.prototype.getTXOut = co(function* getTXOut(args, help) { if (!hash || index == null) throw new RPCError('Invalid outpoint.'); - if (mempool) + if (mempool) { + if (!this.mempool) + throw new RPCError('No mempool available.'); coin = this.mempool.getCoin(hash, index); + } if (!coin) coin = yield this.chain.db.getCoin(hash, index); @@ -1352,7 +1358,7 @@ RPC.prototype.prioritiseTransaction = co(function* prioritiseTransaction(args, h var valid = new Validator([args]); var hash = valid.hash(0); var pri = valid.num(1); - var fee = valid.num(2); + var fee = valid.i64(2); var entry; if (help || args.length !== 3) { @@ -1374,6 +1380,8 @@ RPC.prototype.prioritiseTransaction = co(function* prioritiseTransaction(args, h if (!entry) throw new RPCError('Transaction not in mempool.'); + this.mempool.prioritise(entry, pri, fee); + return true; }); @@ -1673,6 +1681,9 @@ RPC.prototype.signRawTransaction = co(function* signRawTransaction(args, help) { if (!data) throw new RPCError('Invalid hex string.'); + if (!this.mempool) + throw new RPCError('No mempool available.'); + tx = MTX.fromRaw(data); tx.view = yield this.mempool.getSpentView(tx); diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index e69273a3..a117ec54 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -1953,6 +1953,29 @@ Mempool.prototype.getSize = function getSize() { return this.size; }; +/** + * Prioritise transaction. + * @param {MempoolEntry} entry + * @param {Number} pri + * @param {Amount} fee + */ + +Mempool.prototype.prioritise = function _prioritise(entry, pri, fee) { + if (-fee > entry.deltaFee) + fee = -entry.deltaFee; + + if (-pri < entry.priority) + pri = -entry.priority; + + this.updateAncestors(entry, preprioritise); + + entry.priority += pri; + entry.deltaFee += fee; + entry.descFee += fee; + + this.updateAncestors(entry, prioritise); +}; + /** * MempoolOptions * @alias module:mempool.MempoolOptions @@ -2571,7 +2594,7 @@ function nop(parent, child) { } function addFee(parent, child) { - parent.descFee += child.fee; + parent.descFee += child.deltaFee; parent.descSize += child.size; } @@ -2580,10 +2603,18 @@ function removeFee(parent, child) { parent.descSize -= child.descSize; } +function preprioritise(parent, child) { + parent.descFee -= child.deltaFee; +} + +function prioritise(parent, child) { + parent.descFee += child.deltaFee; +} + function cmpRate(a, b) { - var xf = a.fee; + var xf = a.deltaFee; var xs = a.size; - var yf = b.fee; + var yf = b.deltaFee; var ys = b.size; var x, y; @@ -2609,7 +2640,7 @@ function cmpRate(a, b) { } function useDesc(a) { - var x = a.fee * a.descSize; + var x = a.deltaFee * a.descSize; var y = a.descFee * a.size; return y > x; } diff --git a/lib/mempool/mempoolentry.js b/lib/mempool/mempoolentry.js index 09ab312f..07cebbab 100644 --- a/lib/mempool/mempoolentry.js +++ b/lib/mempool/mempoolentry.js @@ -40,6 +40,7 @@ function MempoolEntry(options) { this.sigops = 0; this.priority = 0; this.fee = 0; + this.deltaFee = 0; this.ts = 0; this.value = 0; this.dependencies = false; @@ -63,6 +64,7 @@ MempoolEntry.prototype.fromOptions = function fromOptions(options) { this.sigops = options.sigops; this.priority = options.priority; this.fee = options.fee; + this.deltaFee = options.deltaFee; this.ts = options.ts; this.value = options.value; this.dependencies = options.dependencies; @@ -112,6 +114,7 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) { this.sigops = sigops; this.priority = priority; this.fee = fee; + this.deltaFee = fee; this.ts = util.now(); this.value = value; this.dependencies = dependencies; @@ -160,9 +163,9 @@ MempoolEntry.prototype.txid = function txid() { */ MempoolEntry.prototype.getPriority = function getPriority(height) { - var heightDelta = height - this.height; - var deltaPriority = (heightDelta * this.value) / this.size; - var result = this.priority + Math.floor(deltaPriority); + var height = height - this.height; + var priority = (height * this.value) / this.size; + var result = this.priority + Math.floor(priority); if (result < 0) result = 0; return result; @@ -177,6 +180,15 @@ MempoolEntry.prototype.getFee = function getFee() { return this.fee; }; +/** + * Get delta fee. + * @returns {Amount} + */ + +MempoolEntry.prototype.getDeltaFee = function getDeltaFee() { + return this.deltaFee; +}; + /** * Calculate fee rate. * @returns {Rate} @@ -186,6 +198,15 @@ MempoolEntry.prototype.getRate = function getRate() { return policy.getRate(this.size, this.fee); }; +/** + * Calculate delta fee rate. + * @returns {Rate} + */ + +MempoolEntry.prototype.getDeltaRate = function getDeltaRate() { + return policy.getRate(this.size, this.deltaFee); +}; + /** * Calculate fee cumulative descendant rate. * @returns {Rate} @@ -322,6 +343,7 @@ MempoolEntry.prototype.fromRaw = function fromRaw(data) { this.sigops = br.readU32(); this.priority = br.readDouble(); this.fee = br.readU64(); + this.deltaFee = this.fee; this.ts = br.readU32(); this.value = br.readU64(); this.dependencies = br.readU8() === 1; diff --git a/lib/mining/template.js b/lib/mining/template.js index f635ed80..b259a969 100644 --- a/lib/mining/template.js +++ b/lib/mining/template.js @@ -649,9 +649,9 @@ BlockEntry.fromTX = function fromTX(tx, view, attempt) { BlockEntry.fromEntry = function fromEntry(entry, attempt) { var item = new BlockEntry(entry.tx); item.fee = entry.getFee(); - item.rate = entry.getRate(); + item.rate = entry.getDeltaRate(); item.priority = entry.getPriority(attempt.height); - item.free = item.fee < policy.getMinFee(entry.size); + item.free = entry.getDeltaFee() < policy.getMinFee(entry.size); item.sigops = entry.sigops; item.descRate = entry.getDescRate(); return item; diff --git a/lib/utils/validator.js b/lib/utils/validator.js index 147e4a69..3f4dceff 100644 --- a/lib/utils/validator.js +++ b/lib/utils/validator.js @@ -197,6 +197,50 @@ Validator.prototype.u64 = function u64(key, fallback) { return value; }; +/** + * Get a value (as an int32). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.i32 = function i32(key, fallback) { + var value = this.num(key); + + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; + + if (value % 1 !== 0 || Math.abs(value) > 0x7fffffff) + throw new Error(fmt(key) + ' must be an int32.'); + + return value; +}; + +/** + * Get a value (as an int64). + * @param {String} key + * @param {Object?} fallback + * @returns {Number|null} + */ + +Validator.prototype.i64 = function i64(key, fallback) { + var value = this.num(key); + + if (fallback === undefined) + fallback = null; + + if (value === null) + return fallback; + + if (value % 1 !== 0 || Math.abs(value) > 0x1fffffffffffff) + throw new Error(fmt(key) + ' must be an int64.'); + + return value; +}; + /** * Get a value (as a satoshi number or btc string). * @param {String} key