diff --git a/lib/bcoin/lru.js b/lib/bcoin/lru.js index 301d5f40..397f632c 100644 --- a/lib/bcoin/lru.js +++ b/lib/bcoin/lru.js @@ -7,8 +7,7 @@ 'use strict'; -var utils = require('./utils'); -var assert = utils.assert; +var assert = require('assert'); /** * An LRU cache, used for caching {@link ChainEntry}s. @@ -22,15 +21,22 @@ function LRU(maxSize, getSize) { if (!(this instanceof LRU)) return new LRU(maxSize, getSize); - this.data = {}; - this.size = 0; this.maxSize = maxSize; this.getSize = this._createGetSize(getSize); + this.data = {}; + this.size = 0; this.head = null; this.tail = null; } +/** + * Create a getSize callback. + * @private + * @param {Number} size + * @returns {Function} + */ + LRU.prototype._createGetSize = function _createGetSize(size) { if (!size) return; diff --git a/lib/bcoin/mempool.js b/lib/bcoin/mempool.js index 9066f5b7..48b38471 100644 --- a/lib/bcoin/mempool.js +++ b/lib/bcoin/mempool.js @@ -1914,7 +1914,8 @@ MempoolEntry.fromOptions = function fromOptions(options) { */ MempoolEntry.prototype.fromTX = function fromTX(tx, height) { - var data = tx.getPriority(height); + var priority = tx.getPriority(height); + var value = tx.getChainValue(height); var dependencies = false; var size = tx.getVirtualSize(); var fee = tx.getFee(); @@ -1930,9 +1931,9 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, height) { this.tx = tx; this.height = height; this.size = size; - this.priority = data.priority; + this.priority = priority; this.fee = fee; - this.chainValue = data.value; + this.chainValue = value; this.ts = utils.now(); this.count = 1; this.sizes = size; diff --git a/lib/bcoin/mtx.js b/lib/bcoin/mtx.js index f591586f..ba8ec03a 100644 --- a/lib/bcoin/mtx.js +++ b/lib/bcoin/mtx.js @@ -1266,9 +1266,9 @@ MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) { height = 0; if ((Math.random() * 10 | 0) === 0) - this.setLocktime(Math.max(0, height - (Math.random() * 100 | 0))); - else - this.setLocktime(height); + height = Math.max(0, height - (Math.random() * 100 | 0)); + + this.setLocktime(height); }; /** diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 9b69bf2f..b3dffe57 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -1447,6 +1447,13 @@ TX.prototype.checkInputs = function checkInputs(spendHeight, ret) { input = this.inputs[i]; coin = input.coin; + if (!coin) { + // Note: don't trigger dos score here. + ret.reason = 'bad-txns-inputs-missingorspent'; + ret.score = 0; + return false; + } + if (coin.coinbase && spendHeight != null) { if (spendHeight - coin.height < constants.tx.COINBASE_MATURITY) { ret.reason = 'bad-txns-premature-spend-of-coinbase'; @@ -1462,17 +1469,18 @@ TX.prototype.checkInputs = function checkInputs(spendHeight, ret) { } total += coin.value; + + if (total < 0 || total > constants.MAX_MONEY) { + ret.reason = 'bad-txns-inputvalues-outofrange'; + ret.score = 100; + return false; + } } - if (total < 0 || total > constants.MAX_MONEY) { - ret.reason = 'bad-txns-inputvalues-outofrange'; - ret.score = 100; - return false; - } - + // Overflows already checked in `isSane()`. value = this.getOutputValue(); - if (value > total) { + if (total < value) { ret.reason = 'bad-txns-in-belowout'; ret.score = 100; return false; @@ -1532,32 +1540,28 @@ TX.prototype.getModifiedSize = function getModifiedSize(size) { /** * Calculate the transaction priority. * @param {Number?} height - If not present, tx height - * or mempool height will be used. + * or network height will be used. * @param {Number?} size - Size to calculate priority - * based on. If not present, modified size will be - * calculated and used. - * @returns {Object} data - Object containing - * `priority` and `value`. + * based on. If not present, virtual size will be used. + * @returns {Number} */ TX.prototype.getPriority = function getPriority(height, size) { - var sum, i, input, age, value; + var sum = 0; + var i, input, age; if (this.isCoinbase()) - return { value: 0, priority: 0 }; + return sum; if (height == null) { height = this.height; if (height === -1) - height = bcoin.network.get().height + 1; + height = bcoin.network.get().height; } if (size == null) size = this.maxSize(); - sum = 0; - value = 0; - for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; @@ -1570,14 +1574,42 @@ TX.prototype.getPriority = function getPriority(height, size) { if (input.coin.height <= height) { age = height - input.coin.height; sum += input.coin.value * age; - value += input.coin.value; } } - return { - value: value, - priority: Math.floor(sum / size) - }; + return Math.floor(sum / size); +}; + +/** + * Calculate the transaction's on-chain value. + * @param {Number?} height + * @returns {Number} + */ + +TX.prototype.getChainValue = function getChainValue(height) { + var value = 0; + var i, input; + + if (this.isCoinbase()) + return value; + + if (height == null) + height = Infinity; + + for (i = 0; i < this.inputs.length; i++) { + input = this.inputs[i]; + + if (!input.coin) + continue; + + if (input.coin.height === -1) + continue; + + if (input.coin.height <= height) + value += input.coin.value; + } + + return value; }; /** @@ -1586,24 +1618,15 @@ TX.prototype.getPriority = function getPriority(height, size) { * passed this test is most likely relayable * without a fee. * @param {Number?} height - If not present, tx - * height or mempool height will be used. + * height or network height will be used. * @param {Number?} size - If not present, modified * size will be calculated and used. * @returns {Boolean} */ TX.prototype.isFree = function isFree(height, size) { - var data; - - if (height == null) { - height = this.height; - if (height === -1) - height = bcoin.network.get().height + 1; - } - - data = this.getPriority(height, size); - - return data.priority > constants.tx.FREE_THRESHOLD; + var priority = this.getPriority(height, size); + return priority > constants.tx.FREE_THRESHOLD; }; /** @@ -1852,7 +1875,7 @@ TX.prototype.inspect = function inspect() { minFee: utils.btc(this.getMinFee()), rate: utils.btc(this.getRate()), confirmations: this.getConfirmations(), - priority: this.getPriority().priority.toString(10), + priority: this.getPriority(), date: utils.date(this.ts || this.ps), block: this.block ? utils.revHex(this.block) : null, ts: this.ts,