mempool. remove spenders.

This commit is contained in:
Christopher Jeffrey 2016-05-11 23:25:23 -07:00
parent 67dc96ff5d
commit f4f4658390
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

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