handle remove for block better.
This commit is contained in:
parent
9d771fe0b6
commit
b74b6e8b83
@ -559,18 +559,12 @@ Mempool.prototype.getTXByAddress = function getTXByAddress(addresses, callback)
|
||||
Mempool.prototype.fillHistory = function fillHistory(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
return utils.forEachSerial(tx, function(tx, next) {
|
||||
self.fillHistory(tx, next);
|
||||
}, callback);
|
||||
if (tx.isCoinbase()) {
|
||||
callback = utils.asyncify(callback);
|
||||
return callback(null, tx);
|
||||
}
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(null, tx);
|
||||
|
||||
utils.forEach(tx.inputs, function(input, next) {
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
if (input.coin)
|
||||
return next();
|
||||
|
||||
@ -600,18 +594,12 @@ Mempool.prototype.fillHistory = function fillHistory(tx, callback) {
|
||||
Mempool.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
return utils.forEachSerial(tx, function(tx, next) {
|
||||
self.fillCoins(tx, next);
|
||||
}, callback);
|
||||
if (tx.isCoinbase()) {
|
||||
callback = utils.asyncify(callback);
|
||||
return callback(null, tx);
|
||||
}
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(null, tx);
|
||||
|
||||
utils.forEach(tx.inputs, function(input, next) {
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
if (input.coin)
|
||||
return next();
|
||||
|
||||
@ -842,7 +830,7 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
* and may lend itself to race conditions if used unwisely.
|
||||
* This function will also resolve orphans if possible (the
|
||||
* resolved orphans _will_ be validated).
|
||||
* @param {TX} tx
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {Function} callback - Returns [{@link VerifyError}].
|
||||
*/
|
||||
|
||||
@ -903,7 +891,7 @@ Mempool.prototype.addUnchecked = function addUnchecked(entry, callback, force) {
|
||||
/**
|
||||
* Remove a transaction from the mempool. Generally
|
||||
* only called when a new block is added to the main chain.
|
||||
* @param {TX} tx
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
@ -1425,7 +1413,7 @@ Mempool.prototype.fillAllCoins = function fillAllCoins(tx, callback) {
|
||||
if (tx.hasCoins())
|
||||
return callback(null, tx);
|
||||
|
||||
utils.forEach(tx.inputs, function(input, next) {
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
var hash = input.prevout.hash;
|
||||
var index = input.prevout.index;
|
||||
|
||||
@ -1587,7 +1575,7 @@ Mempool.prototype.getConfidence = function getConfidence(hash, callback) {
|
||||
/**
|
||||
* Add a transaction to the mempool database.
|
||||
* @private
|
||||
* @param {TX} tx
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
@ -1616,14 +1604,14 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry, callback) {
|
||||
|
||||
assert(input.coin);
|
||||
|
||||
batch.del('c/' + key);
|
||||
batch.put('s/' + key, tx.hash());
|
||||
|
||||
if (this.options.indexAddress) {
|
||||
address = input.getHash('hex');
|
||||
if (address)
|
||||
batch.del('C/' + address + '/' + key);
|
||||
}
|
||||
|
||||
batch.del('c/' + key);
|
||||
batch.put('s/' + key, tx.hash());
|
||||
}
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
@ -1633,15 +1621,15 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry, callback) {
|
||||
if (output.script.isUnspendable())
|
||||
continue;
|
||||
|
||||
coin = bcoin.coin.fromTX(tx, i).toRaw();
|
||||
|
||||
batch.put('c/' + key, coin);
|
||||
|
||||
if (this.options.indexAddress) {
|
||||
address = output.getHash('hex');
|
||||
if (address)
|
||||
batch.put('C/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
coin = bcoin.coin.fromTX(tx, i).toRaw();
|
||||
|
||||
batch.put('c/' + key, coin);
|
||||
}
|
||||
|
||||
return batch.write(callback);
|
||||
@ -1650,28 +1638,37 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry, callback) {
|
||||
/**
|
||||
* Remove a transaction from the database. Note
|
||||
* that this _may_ not disconnect the inputs.
|
||||
* Transactions get removed for 2 reasons:
|
||||
* Either they are included in a block,
|
||||
* or they are limited.
|
||||
*
|
||||
* - If they are limited, we want to disconnect
|
||||
* the inputs and also remove all spender
|
||||
* transactions along with their outputs/coins.
|
||||
*
|
||||
* - If they are included in a block, we do not
|
||||
* disconnect the inputs (the coins have already
|
||||
* been used on the blockchain-layer). We also
|
||||
* do not remove spenders, since they are still
|
||||
* spending valid coins that exist on the blockchain.
|
||||
*
|
||||
* @private
|
||||
* @param {Hash} hash
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {Boolean} limit
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype._removeUnchecked = function _removeUnchecked(hash, limit, callback) {
|
||||
Mempool.prototype._removeUnchecked = function _removeUnchecked(entry, limit, callback) {
|
||||
var self = this;
|
||||
var batch, i, addresses, tx;
|
||||
var tx = entry.tx;
|
||||
var hash = tx.hash('hex');
|
||||
var batch = this.db.batch();
|
||||
var i, addresses, input, output, key, address;
|
||||
|
||||
if (hash.tx)
|
||||
hash = hash.tx.hash('hex');
|
||||
|
||||
this.getEntry(hash, function(err, entry) {
|
||||
this._removeSpenders(entry, limit, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!entry)
|
||||
return callback();
|
||||
|
||||
tx = entry.tx;
|
||||
batch = self.db.batch();
|
||||
|
||||
batch.del('t/' + hash);
|
||||
batch.del('m/' + pad32(entry.ts) + '/' + hash);
|
||||
|
||||
@ -1681,79 +1678,98 @@ Mempool.prototype._removeUnchecked = function _removeUnchecked(hash, limit, call
|
||||
batch.del('T/' + addresses[i] + '/' + hash);
|
||||
}
|
||||
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
key = input.prevout.hash + '/' + input.prevout.index;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return next();
|
||||
|
||||
if (!input.coin)
|
||||
return next();
|
||||
break;
|
||||
|
||||
batch.del('s/' + key);
|
||||
|
||||
self.hasTX(input.prevout.hash, function(err, result) {
|
||||
// We only disconnect inputs if this
|
||||
// is a limited transaction. For block
|
||||
// transactions, the coins are still
|
||||
// spent. They were spent on the
|
||||
// blockchain.
|
||||
if (!limit)
|
||||
continue;
|
||||
|
||||
assert(input.coin);
|
||||
|
||||
if (input.coin.height !== -1)
|
||||
continue;
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
address = input.getHash('hex');
|
||||
if (address)
|
||||
batch.put('C/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
batch.put('c/' + key, input.coin.toRaw());
|
||||
}
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
key = hash + '/' + i;
|
||||
|
||||
if (output.script.isUnspendable())
|
||||
continue;
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
address = output.getHash('hex');
|
||||
if (address)
|
||||
batch.del('C/' + address + '/' + key);
|
||||
}
|
||||
|
||||
batch.del('c/' + key);
|
||||
}
|
||||
|
||||
return batch.write(callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively remove spenders of a transaction.
|
||||
* @private
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {Boolean} limit
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype._removeSpenders = function _removeSpenders(entry, limit, callback) {
|
||||
var self = this;
|
||||
var tx = entry.tx;
|
||||
var hash;
|
||||
|
||||
// We do not remove spenders if this is
|
||||
// being removed for a block. The spenders
|
||||
// are still spending valid coins (which
|
||||
// now exist on the blockchain).
|
||||
if (!limit)
|
||||
return callback();
|
||||
|
||||
hash = tx.hash('hex');
|
||||
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
self.isSpent(hash, i, function(err, spender) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!spender)
|
||||
return next();
|
||||
|
||||
self.getEntry(spender, function(err, entry) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (result) {
|
||||
batch.put('c/' + key, input.coin.toRaw());
|
||||
if (self.options.indexAddress) {
|
||||
address = input.getHash('hex');
|
||||
if (address)
|
||||
batch.put('C/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
} else {
|
||||
batch.del('c/' + key);
|
||||
if (self.options.indexAddress) {
|
||||
address = input.getHash('hex');
|
||||
if (address)
|
||||
batch.del('C/' + address + '/' + key);
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address;
|
||||
|
||||
if (output.script.isUnspendable())
|
||||
if (!entry)
|
||||
return next();
|
||||
|
||||
batch.del('c/' + key);
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
address = output.getHash('hex');
|
||||
if (address)
|
||||
batch.del('C/' + address + '/' + key);
|
||||
}
|
||||
|
||||
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);
|
||||
self.removeUnchecked(entry, limit, next, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -250,7 +250,7 @@ TXDB.prototype._getOrphans = function _getOrphans(key, callback) {
|
||||
if (!orphans)
|
||||
return callback();
|
||||
|
||||
utils.forEach(orphans, function(orphan, next) {
|
||||
utils.forEachSerial(orphans, function(orphan, next) {
|
||||
self.getTX(orphan.hash, function(err, tx) {
|
||||
if (err)
|
||||
return next(err);
|
||||
@ -1452,18 +1452,12 @@ TXDB.prototype.getCoins = function getCoins(id, callback) {
|
||||
TXDB.prototype.fillHistory = function fillHistory(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
return utils.forEachSerial(tx, function(tx, next) {
|
||||
self.fillHistory(tx, next);
|
||||
}, callback);
|
||||
if (tx.isCoinbase()) {
|
||||
callback = utils.asyncify(callback);
|
||||
return callback(null, tx);
|
||||
}
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(null, tx);
|
||||
|
||||
utils.forEach(tx.inputs, function(input, next) {
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
if (input.coin)
|
||||
return next();
|
||||
|
||||
@ -1492,18 +1486,12 @@ TXDB.prototype.fillHistory = function fillHistory(tx, callback) {
|
||||
TXDB.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
return utils.forEachSerial(tx, function(tx, next) {
|
||||
self.fillCoins(tx, next);
|
||||
}, callback);
|
||||
if (tx.isCoinbase()) {
|
||||
callback = utils.asyncify(callback);
|
||||
return callback(null, tx);
|
||||
}
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(null, tx);
|
||||
|
||||
utils.forEach(tx.inputs, function(input, next) {
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
if (input.coin)
|
||||
return next();
|
||||
|
||||
|
||||
@ -692,7 +692,7 @@ WalletDB.prototype.saveAddress = function saveAddress(id, addresses, callback) {
|
||||
hashes.push([address.getProgramHash('hex'), address]);
|
||||
}
|
||||
|
||||
utils.forEach(hashes, function(hash, next) {
|
||||
utils.forEachSerial(hashes, function(hash, next) {
|
||||
if (self.tx.filter)
|
||||
self.tx.filter.add(hash[0], 'hex');
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user