From f4f465839053627bd3bd733cfeae9543fb2743ca Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 11 May 2016 23:25:23 -0700 Subject: [PATCH] mempool. remove spenders. --- lib/bcoin/mempool.js | 178 ++++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 88 deletions(-) diff --git a/lib/bcoin/mempool.js b/lib/bcoin/mempool.js index 9ae27020..e0face39 100644 --- a/lib/bcoin/mempool.js +++ b/lib/bcoin/mempool.js @@ -91,6 +91,7 @@ function Mempool(options) { : network.requireStandard; this.rejectAbsurdFees = this.options.rejectAbsurdFees !== false; this.prematureWitness = !!this.options.prematureWitness; + this.accurateMemory = !!this.options.accurateMemory; this.maxSize = options.maxSize || constants.mempool.MAX_MEMPOOL_SIZE; this.minFeeRate = 0; @@ -258,7 +259,7 @@ Mempool.prototype.addBlock = function addBlock(block, callback, force) { copy = tx.clone(); copy.unsetBlock(); - self.addUnchecked(tx, next); + self.addUnchecked(tx, next, true); }); }); }, function(err) { @@ -285,14 +286,14 @@ Mempool.prototype.addBlock = function addBlock(block, callback, force) { copy.height = existing.height; copy.ps = existing.ps; - self.removeUnchecked(copy, function(err) { + self.removeUnchecked(copy, false, function(err) { if (err) return next(err); self.emit('confirmed', tx, block); return next(); - }); + }, true); }); }, function(err) { if (err) @@ -348,7 +349,7 @@ Mempool.prototype.removeBlock = function removeBlock(block, callback, force) { self.emit('unconfirmed', tx, block); return next(); - }); + }, true); }); }, callback); }; @@ -376,7 +377,7 @@ Mempool.prototype.limitMempoolSize = function limitMempoolSize(callback) { if (self.getSize() <= self.maxSize) return next(); - self.removeUnchecked(tx, function(err) { + self.removeUnchecked(tx, true, function(err) { if (err) return next(err); @@ -389,7 +390,7 @@ Mempool.prototype.limitMempoolSize = function limitMempoolSize(callback) { } next(); - }); + }, true); }, function(err) { if (err) return callback(err); @@ -406,12 +407,9 @@ Mempool.prototype.limitMempoolSize = function limitMempoolSize(callback) { Mempool.prototype.pruneOrphans = function pruneOrphans(callback) { var self = this; - - callback = utils.ensure(callback); - utils.forEachSerial(Object.keys(this.orphans), function(hash, next) { if (self.totalOrphans <= constants.mempool.MAX_ORPHAN_TX) - return next(); + return callback(); self.removeOrphan(hash, next); }, callback); }; @@ -656,7 +654,7 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) { 0)); } - self.addUnchecked(tx, callback); + self.addUnchecked(tx, callback, true); }); }); }); @@ -676,8 +674,15 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) { * @param {Function} callback - Returns [{@link VerifyError}]. */ -Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) { +Mempool.prototype.addUnchecked = function addUnchecked(tx, callback, force) { var self = this; + + var unlock = this._lock(addUnchecked, [tx, callback], force); + if (!unlock) + return; + + callback = utils.wrap(callback, unlock); + this._addUnchecked(tx, function(err) { if (err) return callback(err); @@ -713,7 +718,7 @@ Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) { } bcoin.debug('Resolved orphan %s in mempool.', tx.rhash); next(); - }); + }, true); }); }, callback); }); @@ -727,10 +732,16 @@ Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) { * @param {Function} callback */ -Mempool.prototype.removeUnchecked = function removeUnchecked(tx, callback, limit) { +Mempool.prototype.removeUnchecked = function removeUnchecked(tx, limit, callback, force) { var self = this; var rate; + var unlock = this._lock(removeUnchecked, [tx, limit, callback], force); + if (!unlock) + return; + + callback = utils.wrap(callback, unlock); + this.fillAllHistory(tx, function(err, tx) { if (err) return callback(err); @@ -739,7 +750,7 @@ Mempool.prototype.removeUnchecked = function removeUnchecked(tx, callback, limit if (err) return callback(err); - self._removeUnchecked(tx, function(err) { + self._removeUnchecked(tx, limit, function(err) { if (err) return callback(err); @@ -1016,13 +1027,8 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx, callback, force) { this.orphans[hash] = tx.toExtended(true); this.totalOrphans++; - if (self.totalOrphans > constants.mempool.MAX_ORPHAN_TX) { - return self.pruneOrphans(function(err) { - if (err) - return callback(err); - callback(); - }); - } + if (this.totalOrphans > constants.mempool.MAX_ORPHAN_TX) + return this.pruneOrphans(callback); return callback(); }; @@ -1144,7 +1150,7 @@ Mempool.prototype.resolveOrphans = function resolveOrphans(tx, callback, force) Mempool.prototype.removeOrphan = function removeOrphan(tx, callback) { var self = this; - var prevout, hash; + var i, prevout, hash; function getOrphan(tx, callback) { if (typeof tx === 'string') @@ -1163,7 +1169,6 @@ Mempool.prototype.removeOrphan = function removeOrphan(tx, callback) { prevout = tx.getPrevout(); utils.forEachSerial(prevout, function(prev, next) { - var i, p; self.getWaiting(prev, function(err, hashes) { if (err) return next(err); @@ -1317,53 +1322,46 @@ Mempool.prototype.isDoubleSpend = function isDoubleSpend(tx, callback) { Mempool.prototype.getConfidence = function getConfidence(hash, callback) { var self = this; - var tx; callback = utils.asyncify(callback); - function isDoubleSpend(callback) { + function getTX(callback) { + if (hash instanceof bcoin.tx) + return callback(null, hash, hash.hash('hex')); + + return this.getTX(hash, function(err, tx) { + if (err) + return callback(err); + return callback(null, tx, hash); + }); + } + + function isDoubleSpend(tx, callback) { if (tx) return self.isDoubleSpend(tx, callback); return callback(null, false); } - function done(tx, hash) { - return isDoubleSpend(function(err, result) { + return getTX(function(err, tx, hash) { + if (err) + return callback(err); + + return self.hasTX(hash, function(err, result) { if (err) return callback(err); if (result) - return callback(null, constants.confidence.INCONFLICT); + return callback(null, constants.confidence.PENDING); - return self.hasTX(hash, function(err, result) { + return isDoubleSpend(tx, function(err, result) { if (err) return callback(err); if (result) - return callback(null, constants.confidence.PENDING); + return callback(null, constants.confidence.INCONFLICT); - function getBlock(callback) { - if (tx && tx.block) - return callback(null, tx.block); - return self.chain.db.getTX(hash, function(err, existing) { - if (err) - return callback(err); - - if (!existing) - return callback(); - - return callback(null, existing.block); - }); - } - - return getBlock(function(err, block) { - if (err) - return callback(err); - - if (!block) - return callback(null, constants.confidence.UNKNOWN); - - self.chain.db.isMainChain(block, function(err, result) { + if (tx && tx.block) { + return self.chain.db.isMainChain(tx.block, function(err, result) { if (err) return callback(err); @@ -1372,18 +1370,19 @@ Mempool.prototype.getConfidence = function getConfidence(hash, callback) { return callback(null, constants.confidence.DEAD); }); + } + + return self.chain.db.isUnspentTX(hash, function(err, existing) { + if (err) + return callback(err); + + if (existing) + return callback(null, constants.confidence.BUILDING); + + return callback(null, constants.confidence.UNKNOWN); }); }); }); - } - - if (hash instanceof bcoin.tx) - return done(hash, hash.hash('hex')); - - return this.getTX(hash, function(err, tx) { - if (err) - return callback(err); - done(tx, hash); }); }; @@ -1394,17 +1393,11 @@ Mempool.prototype.getConfidence = function getConfidence(hash, callback) { * @param {Function} callback */ -Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) { +Mempool.prototype._addUnchecked = function _addUnchecked(tx, callback) { var self = this; var hash = tx.hash('hex'); var i, addresses, address, input, output, key, coin, batch; - var unlock = this.writeLock.lock(addUnchecked, [tx, callback], force); - if (!unlock) - return; - - callback = utils.wrap(callback, unlock); - batch = this.db.batch(); batch.put('t/' + hash, tx.toExtended()); @@ -1464,16 +1457,10 @@ Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) { * @param {Function} callback */ -Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, force) { +Mempool.prototype._removeUnchecked = function _removeUnchecked(hash, limit, callback) { var self = this; var batch, i, addresses, output; - var unlock = this.writeLock.lock(removeUnchecked, [hash, callback], force); - if (!unlock) - return; - - callback = utils.wrap(callback, unlock); - if (hash.hash) hash = hash.hash('hex'); @@ -1533,12 +1520,11 @@ Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, fo if (err) return callback(err); - for (i = 0; i < tx.outputs.length; i++) { - output = tx.outputs[i]; + utils.forEachSerial(tx.outputs, function(output, next, i) { key = hash + '/' + i; if (output.script.isUnspendable()) - continue; + return next(); batch.del('c/' + key); @@ -1547,9 +1533,25 @@ Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, fo if (address) batch.del('C/' + address + '/' + key); } - } - return batch.write(callback); + if (!limit) + return next(); + + self.isSpent(hash, i, function(err, spender) { + if (err) + return next(err); + + if (!spender) + return next(); + + self._removeUnchecked(spender, limit, next); + }); + }, function(err) { + if (err) + return callback(err); + + return batch.write(callback); + }); }); }); }; @@ -1577,7 +1579,7 @@ Mempool.prototype.memUsageBitcoind = function memUsage(tx) { mem += mallocUsage(tx.outputs.length); for (i = 0; i < tx.inputs.length; i++) - mem += mallocUsage(tx.inputs[i].script.getSize()) + 0; + mem += mallocUsage(tx.inputs[i].script.getSize()); for (i = 0; i < tx.outputs.length; i++) mem += mallocUsage(tx.outputs[i].script.getSize()); @@ -1586,9 +1588,9 @@ Mempool.prototype.memUsageBitcoind = function memUsage(tx) { for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; - mem += mallocUsage(input.witness.length); - for (j = 0; j < input.witness.length; j++) - mem += mallocUsage(input.witness[j].length); + mem += mallocUsage(input.witness.items.length); + for (j = 0; j < input.witness.items.length; j++) + mem += mallocUsage(input.witness[j].items.length); } return mem; @@ -1686,11 +1688,11 @@ var ptrSize = (process.platform == null || process.platform === 'arm') ? 8 : 4; function mallocUsage(alloc) { - if (alloc == 0) + if (alloc === 0) return 0; if (ptrSize === 8) - return ((alloc + 31) >> 4) << 4; - return ((alloc + 15) >> 3) << 3; + return ((alloc + 31) >>> 4) << 4; + return ((alloc + 15) >>> 3) << 3; } return Mempool;