mempool: cleanup. more sync methods.
This commit is contained in:
parent
e517a7a9f7
commit
82ca244669
@ -1597,20 +1597,7 @@ RPC.prototype.prioritisetransaction = function prioritisetransaction(args, callb
|
||||
if (entry.fees < 0)
|
||||
entry.fees = 0;
|
||||
|
||||
this.mempool.fillAllCoins(entry.tx, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!entry.tx.hasCoins())
|
||||
return callback(new RPCError('Transaction not in mempool.'));
|
||||
|
||||
self.mempool.addUnchecked(entry, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
callback(null, true);
|
||||
});
|
||||
});
|
||||
return callback(null, true);
|
||||
};
|
||||
|
||||
RPC.prototype.submitblock = function submitblock(args, callback) {
|
||||
|
||||
@ -149,54 +149,37 @@ Mempool.prototype._lock = function _lock(func, args, force) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype.addBlock = function addBlock(block, callback, force) {
|
||||
var self = this;
|
||||
var unlock = this._lock(addBlock, [block, callback], force);
|
||||
var len, entries, entry;
|
||||
Mempool.prototype.addBlock = function addBlock(block, callback) {
|
||||
var entries = [];
|
||||
var i, entry, tx, hash;
|
||||
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
len = block.txs.length - 1;
|
||||
entries = [];
|
||||
|
||||
utils.forRangeSerial(0, block.txs.length, function(i, next) {
|
||||
var tx = block.txs[len--];
|
||||
var hash = tx.hash('hex');
|
||||
for (i = block.txs.length - 1; i >= 0; i--) {
|
||||
tx = block.txs[i];
|
||||
hash = tx.hash('hex');
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return next();
|
||||
continue;
|
||||
|
||||
entry = self.getEntry(hash);
|
||||
entry = this.getEntry(hash);
|
||||
|
||||
if (!entry) {
|
||||
self.removeOrphan(hash);
|
||||
return next();
|
||||
this.removeOrphan(hash);
|
||||
continue;
|
||||
}
|
||||
|
||||
self.removeUnchecked(entry, false, function(err) {
|
||||
if (err)
|
||||
return next(err);
|
||||
this.removeUnchecked(entry);
|
||||
this.emit('confirmed', tx, block);
|
||||
|
||||
self.emit('confirmed', tx, block);
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
entries.push(entry);
|
||||
this.blockSinceBump = true;
|
||||
this.lastFeeUpdate = utils.now();
|
||||
|
||||
return next();
|
||||
}, true);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (this.fees)
|
||||
this.fees.processBlock(block.height, entries, this.chain.isFull());
|
||||
|
||||
self.blockSinceBump = true;
|
||||
self.lastFeeUpdate = utils.now();
|
||||
|
||||
if (self.fees)
|
||||
self.fees.processBlock(block.height, entries, self.chain.isFull());
|
||||
|
||||
return callback();
|
||||
});
|
||||
return callback();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -245,62 +228,54 @@ Mempool.prototype.removeBlock = function removeBlock(block, callback, force) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype.limitMempoolSize = function limitMempoolSize(entryHash, callback) {
|
||||
var self = this;
|
||||
Mempool.prototype.limitMempoolSize = function limitMempoolSize(entryHash) {
|
||||
var trimmed = false;
|
||||
var hashes, end, entry;
|
||||
var i, hashes, hash, end, entry;
|
||||
|
||||
if (this.getSize() <= this.maxSize)
|
||||
return callback(null, trimmed);
|
||||
return trimmed;
|
||||
|
||||
hashes = Object.keys(this.tx);
|
||||
hashes = this.getSnapshot();
|
||||
end = utils.now() - constants.mempool.MEMPOOL_EXPIRY;
|
||||
|
||||
utils.forEachSerial(hashes, function(hash, next) {
|
||||
var entry = self.getEntry(hash);
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
entry = this.getEntry(hash);
|
||||
|
||||
if (!entry)
|
||||
return next();
|
||||
|
||||
if (self.getSize() <= self.maxSize)
|
||||
return callback(null, trimmed);
|
||||
continue;
|
||||
|
||||
if (entry.ts >= end)
|
||||
return next();
|
||||
continue;
|
||||
|
||||
if (!trimmed && hash === entryHash)
|
||||
trimmed = true;
|
||||
|
||||
self.removeUnchecked(entry, true, next, true);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
this.removeUnchecked(entry, true);
|
||||
|
||||
if (self.getSize() <= self.maxSize)
|
||||
return callback(null, trimmed);
|
||||
if (this.getSize() <= this.maxSize)
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
hashes = Object.keys(self.tx);
|
||||
hashes = this.getSnapshot();
|
||||
|
||||
utils.forEachSerial(hashes, function(hash, next) {
|
||||
if (self.getSize() <= self.maxSize)
|
||||
return callback(null, trimmed);
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
entry = this.getEntry(hash);
|
||||
|
||||
entry = self.getEntry(hash);
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
if (!entry)
|
||||
return next();
|
||||
if (!trimmed && hash === entryHash)
|
||||
trimmed = true;
|
||||
|
||||
if (!trimmed && hash === entryHash)
|
||||
trimmed = true;
|
||||
this.removeUnchecked(entry, true);
|
||||
|
||||
self.removeUnchecked(entry, true, next, true);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (this.getSize() <= this.maxSize)
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
return callback(null, trimmed);
|
||||
});
|
||||
});
|
||||
return trimmed;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -595,11 +570,11 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
}
|
||||
}
|
||||
|
||||
this.chain.checkFinal(this.chain.tip, tx, lockFlags, function(err, isFinal) {
|
||||
this.chain.checkFinal(this.chain.tip, tx, lockFlags, function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!isFinal) {
|
||||
if (!result) {
|
||||
return callback(new VerifyError(tx,
|
||||
'nonstandard',
|
||||
'non-final',
|
||||
@ -650,19 +625,14 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.limitMempoolSize(hash, function(err, trimmed) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (self.limitMempoolSize(hash)) {
|
||||
return callback(new VerifyError(tx,
|
||||
'insufficientfee',
|
||||
'mempool full',
|
||||
0));
|
||||
}
|
||||
|
||||
if (trimmed) {
|
||||
return callback(new VerifyError(tx,
|
||||
'insufficientfee',
|
||||
'mempool full',
|
||||
0));
|
||||
}
|
||||
|
||||
return callback();
|
||||
});
|
||||
return callback();
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
@ -739,48 +709,35 @@ Mempool.prototype.addUnchecked = function addUnchecked(entry, callback, force) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype.removeUnchecked = function removeUnchecked(entry, limit, callback, force) {
|
||||
var self = this;
|
||||
var unlock, rate, hash;
|
||||
|
||||
unlock = this._lock(removeUnchecked, [entry, limit, callback], force);
|
||||
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
Mempool.prototype.removeUnchecked = function removeUnchecked(entry, limit) {
|
||||
var rate, hash;
|
||||
|
||||
this.removeOrphan(entry.tx);
|
||||
|
||||
this._removeUnchecked(entry, limit, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
this._removeUnchecked(entry, limit);
|
||||
|
||||
self.totalSpent -= entry.tx.inputs.length;
|
||||
self.size -= self.memUsage(entry.tx);
|
||||
self.totalTX--;
|
||||
this.totalSpent -= entry.tx.inputs.length;
|
||||
this.size -= this.memUsage(entry.tx);
|
||||
this.totalTX--;
|
||||
|
||||
if (self.fees) {
|
||||
hash = entry.tx.hash('hex');
|
||||
self.fees.removeTX(hash);
|
||||
if (this.fees) {
|
||||
hash = entry.tx.hash('hex');
|
||||
this.fees.removeTX(hash);
|
||||
}
|
||||
|
||||
if (limit) {
|
||||
this.logger.spam('Removed tx %s from mempool.', entry.tx.rhash);
|
||||
rate = bcoin.tx.getRate(entry.sizes, entry.fees);
|
||||
rate += this.minReasonableFee;
|
||||
if (rate > this.minFeeRate) {
|
||||
this.minFeeRate = rate;
|
||||
this.blockSinceBump = false;
|
||||
}
|
||||
} else {
|
||||
this.logger.spam('Removed block tx %s from mempool.', entry.tx.rhash);
|
||||
}
|
||||
|
||||
if (limit) {
|
||||
self.logger.spam('Removed tx %s from mempool.', entry.tx.rhash);
|
||||
rate = bcoin.tx.getRate(entry.sizes, entry.fees);
|
||||
rate += self.minReasonableFee;
|
||||
if (rate > self.minFeeRate) {
|
||||
self.minFeeRate = rate;
|
||||
self.blockSinceBump = false;
|
||||
}
|
||||
} else {
|
||||
self.logger.spam('Removed block tx %s from mempool.', entry.tx.rhash);
|
||||
}
|
||||
|
||||
self.emit('remove tx', entry.tx);
|
||||
|
||||
return callback();
|
||||
});
|
||||
this.emit('remove tx', entry.tx);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1001,7 +958,7 @@ Mempool.prototype.countDescendants = function countDescendants(tx) {
|
||||
if (!next)
|
||||
continue;
|
||||
count = 1;
|
||||
count += this.countDescendants(next);
|
||||
count += this.countDescendants(next.tx);
|
||||
if (count > max)
|
||||
max = count;
|
||||
}
|
||||
@ -1081,13 +1038,15 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.getBalance = function getBalance() {
|
||||
var keys = Object.keys(this.tx);
|
||||
var hashes = this.getSnapshot();
|
||||
var total = 0;
|
||||
var i, j, key, tx, hash, coin;
|
||||
var i, j, tx, hash, coin;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
tx = this.tx[key].tx;
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
tx = this.getTX(hash);
|
||||
if (!tx)
|
||||
continue;
|
||||
hash = tx.hash('hex');
|
||||
for (j = 0; j < tx.outputs.length; j++) {
|
||||
coin = this.getCoin(hash, j);
|
||||
@ -1105,13 +1064,13 @@ Mempool.prototype.getBalance = function getBalance() {
|
||||
*/
|
||||
|
||||
Mempool.prototype.getHistory = function getHistory() {
|
||||
var keys = Object.keys(this.tx);
|
||||
var hashes = this.getSnapshot();
|
||||
var txs = [];
|
||||
var i, key, tx;
|
||||
var i, hash, tx;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
tx = this.getTX(key);
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
tx = this.getTX(hash);
|
||||
if (!tx)
|
||||
continue;
|
||||
txs.push(tx);
|
||||
@ -1304,7 +1263,7 @@ Mempool.prototype.fillAllCoins = function fillAllCoins(tx, callback) {
|
||||
/**
|
||||
* Get a snapshot of all transaction hashes in the mempool. Used
|
||||
* for generating INV packets in response to MEMPOOL packets.
|
||||
* @param {Function} callback - Returns [Error, {@link Hash}[]].
|
||||
* @returns {Hash[]}
|
||||
*/
|
||||
|
||||
Mempool.prototype.getSnapshot = function getSnapshot() {
|
||||
@ -1421,16 +1380,16 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry) {
|
||||
if (this.options.indexAddress)
|
||||
this.coinIndex.removeCoin(input.coin);
|
||||
|
||||
this.spents[key] = bcoin.outpoint.fromTX(tx, i);
|
||||
this.spents[key] = entry;
|
||||
}
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
if (this.options.indexAddress) {
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
|
||||
if (output.script.isUnspendable())
|
||||
continue;
|
||||
if (output.script.isUnspendable())
|
||||
continue;
|
||||
|
||||
if (this.options.indexAddress) {
|
||||
coin = bcoin.coin.fromTX(tx, i);
|
||||
this.coinIndex.addCoin(coin);
|
||||
}
|
||||
@ -1460,50 +1419,49 @@ Mempool.prototype._addUnchecked = function _addUnchecked(entry) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype._removeUnchecked = function _removeUnchecked(entry, limit, callback) {
|
||||
var self = this;
|
||||
Mempool.prototype._removeUnchecked = function _removeUnchecked(entry, limit) {
|
||||
var tx = entry.tx;
|
||||
var hash = tx.hash('hex');
|
||||
var i, input, output, key, coin;
|
||||
|
||||
this._removeSpenders(entry, limit, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
// 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)
|
||||
this._removeSpenders(entry);
|
||||
|
||||
delete self.tx[hash];
|
||||
delete this.tx[hash];
|
||||
|
||||
if (self.options.indexAddress)
|
||||
self.txIndex.addTX(tx);
|
||||
if (this.options.indexAddress)
|
||||
this.txIndex.removeTX(tx);
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
key = input.prevout.hash + input.prevout.index;
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
key = input.prevout.hash + input.prevout.index;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
break;
|
||||
if (tx.isCoinbase())
|
||||
break;
|
||||
|
||||
delete self.spents[key];
|
||||
delete this.spents[key];
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
assert(input.coin);
|
||||
self.coinIndex.removeCoin(input.coin);
|
||||
}
|
||||
}
|
||||
assert(input.coin);
|
||||
|
||||
if (this.options.indexAddress)
|
||||
this.coinIndex.removeCoin(input.coin);
|
||||
}
|
||||
|
||||
if (this.options.indexAddress) {
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
|
||||
if (output.script.isUnspendable())
|
||||
continue;
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
coin = bcoin.coin.fromTX(tx, i);
|
||||
self.coinIndex.removeCoin(coin);
|
||||
}
|
||||
coin = bcoin.coin.fromTX(tx, i);
|
||||
this.coinIndex.removeCoin(coin);
|
||||
}
|
||||
|
||||
return callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1514,33 +1472,19 @@ Mempool.prototype._removeUnchecked = function _removeUnchecked(entry, limit, cal
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Mempool.prototype._removeSpenders = function _removeSpenders(entry, limit, callback) {
|
||||
var self = this;
|
||||
Mempool.prototype._removeSpenders = function _removeSpenders(entry) {
|
||||
var tx = entry.tx;
|
||||
var hash, spender;
|
||||
var hash = tx.hash('hex');
|
||||
var i, spender;
|
||||
|
||||
// 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) {
|
||||
spender = self.isSpent(hash, i);
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
spender = this.isSpent(hash, i);
|
||||
|
||||
if (!spender)
|
||||
return next();
|
||||
continue;
|
||||
|
||||
entry = self.getEntry(spender.hash);
|
||||
|
||||
if (!entry)
|
||||
return next();
|
||||
|
||||
self.removeUnchecked(entry, limit, next, true);
|
||||
}, callback);
|
||||
this.removeUnchecked(spender, true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1575,11 +1519,14 @@ Mempool.prototype.memUsage = function memUsage(tx) {
|
||||
|
||||
mem += 8;
|
||||
|
||||
// Mempool Entry
|
||||
mem += 40;
|
||||
|
||||
// Map entry
|
||||
mem += 64;
|
||||
|
||||
// Spent entry
|
||||
mem += tx.outputs.length * 72;
|
||||
mem += 64;
|
||||
|
||||
return mem;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user