miner: better sorting of txs.
This commit is contained in:
parent
749a912f8c
commit
12a5bcc4e2
@ -728,7 +728,7 @@ Mempool.prototype._addUnchecked = co(function* addUnchecked(entry) {
|
||||
this.trackEntry(entry);
|
||||
|
||||
this.emit('tx', entry.tx);
|
||||
this.emit('add tx', entry.tx);
|
||||
this.emit('add entry', entry);
|
||||
|
||||
if (this.fees)
|
||||
this.fees.processTX(entry, this.chain.isFull());
|
||||
@ -809,7 +809,7 @@ Mempool.prototype.removeUnchecked = function removeUnchecked(entry, limit) {
|
||||
this.logger.spam('Removed block tx %s from mempool.', entry.tx.rhash);
|
||||
}
|
||||
|
||||
this.emit('remove tx', entry.tx);
|
||||
this.emit('remove entry', entry);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -121,25 +121,30 @@ Miner.prototype.start = co(function* start() {
|
||||
|
||||
this.running = true;
|
||||
|
||||
try {
|
||||
attempt = yield this.createBlock();
|
||||
} catch (e) {
|
||||
this.running = false;
|
||||
this.emit('error', e);
|
||||
return;
|
||||
}
|
||||
while (!block) {
|
||||
if (!this.running)
|
||||
return;
|
||||
|
||||
if (!this.running)
|
||||
return;
|
||||
try {
|
||||
attempt = yield this.createBlock();
|
||||
} catch (e) {
|
||||
this.running = false;
|
||||
this.emit('error', e);
|
||||
return;
|
||||
}
|
||||
|
||||
this.attempt = attempt;
|
||||
if (!this.running)
|
||||
return;
|
||||
|
||||
try {
|
||||
block = yield attempt.mineAsync();
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
this.restart();
|
||||
return;
|
||||
this.attempt = attempt;
|
||||
|
||||
try {
|
||||
block = yield attempt.mineAsync();
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
this.restart();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -193,7 +198,7 @@ Miner.prototype.restart = function restart() {
|
||||
|
||||
Miner.prototype.createBlock = co(function* createBlock(tip) {
|
||||
var version = this.version;
|
||||
var i, ts, attempt, txs, tx, target;
|
||||
var ts, attempt, target, entries;
|
||||
|
||||
if (!tip)
|
||||
tip = this.chain.tip;
|
||||
@ -211,21 +216,16 @@ Miner.prototype.createBlock = co(function* createBlock(tip) {
|
||||
tip: tip,
|
||||
version: version,
|
||||
bits: target,
|
||||
flags: this.chain.state.flags,
|
||||
address: this.address,
|
||||
coinbaseFlags: this.coinbaseFlags,
|
||||
witness: this.chain.state.hasWitness(),
|
||||
network: this.network
|
||||
});
|
||||
|
||||
if (!this.mempool)
|
||||
return attempt;
|
||||
entries = this.getSorted();
|
||||
|
||||
txs = this.mempool.getHistory();
|
||||
|
||||
for (i = 0; i < txs.length; i++) {
|
||||
tx = txs[i];
|
||||
attempt.addTX(tx);
|
||||
}
|
||||
attempt.build(entries);
|
||||
|
||||
return attempt;
|
||||
});
|
||||
@ -250,8 +250,99 @@ Miner.prototype.addTX = function addTX(tx) {
|
||||
if (!this.running)
|
||||
return;
|
||||
|
||||
if (this.attempt)
|
||||
this.attempt.addTX(tx.clone());
|
||||
if (!this.attempt)
|
||||
return;
|
||||
|
||||
this.attempt.addTX(tx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify the miner that a new tx has entered the mempool.
|
||||
* @param {MempoolEntry} entry
|
||||
*/
|
||||
|
||||
Miner.prototype.notifyEntry = function notifyEntry() {
|
||||
if (!this.running)
|
||||
return;
|
||||
|
||||
if (!this.attempt)
|
||||
return;
|
||||
|
||||
this.attempt.since++;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a block "attempt".
|
||||
* @param {ChainEntry} tip
|
||||
* @returns {Promise} - Returns {@link MinerBlock}.
|
||||
*/
|
||||
|
||||
Miner.prototype.getSorted = function getSorted() {
|
||||
var depMap = {};
|
||||
var count = {};
|
||||
var result = [];
|
||||
var top = [];
|
||||
var i, j, entry, tx, hash, input;
|
||||
var prev, hasDeps, deps, hashes;
|
||||
|
||||
if (!this.mempool)
|
||||
return [];
|
||||
|
||||
hashes = this.mempool.getSnapshot();
|
||||
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
entry = this.mempool.getEntry(hash);
|
||||
tx = entry.tx;
|
||||
|
||||
count[hash] = 0;
|
||||
hasDeps = false;
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
prev = input.prevout.hash;
|
||||
|
||||
if (!this.mempool.hasTX(prev))
|
||||
continue;
|
||||
|
||||
hasDeps = true;
|
||||
|
||||
if (!depMap[prev])
|
||||
depMap[prev] = [];
|
||||
|
||||
depMap[prev].push(entry);
|
||||
count[hash]++;
|
||||
}
|
||||
|
||||
if (hasDeps)
|
||||
continue;
|
||||
|
||||
top.push(entry);
|
||||
}
|
||||
|
||||
for (i = 0; i < top.length; i++) {
|
||||
entry = top[i];
|
||||
tx = entry.tx;
|
||||
hash = tx.hash('hex');
|
||||
|
||||
result.push(entry);
|
||||
|
||||
deps = depMap[hash];
|
||||
|
||||
if (!deps)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < deps.length; j++) {
|
||||
entry = deps[j];
|
||||
tx = entry.tx;
|
||||
hash = tx.hash('hex');
|
||||
|
||||
if (--count[hash] === 0)
|
||||
result.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -53,6 +53,7 @@ function MinerBlock(options) {
|
||||
this.height = options.tip.height + 1;
|
||||
this.bits = options.bits;
|
||||
this.target = utils.fromCompact(this.bits).toArrayLike(Buffer, 'le', 32);
|
||||
this.flags = options.flags;
|
||||
this.extraNonce = new bn(0);
|
||||
this.iterations = 0;
|
||||
this.coinbaseFlags = options.coinbaseFlags;
|
||||
@ -60,6 +61,10 @@ function MinerBlock(options) {
|
||||
this.address = options.address;
|
||||
this.network = Network.get(options.network);
|
||||
this.destroyed = false;
|
||||
this.since = 0;
|
||||
|
||||
this.sigops = 0;
|
||||
this.weight = 0;
|
||||
|
||||
this.coinbase = new TX();
|
||||
this.coinbase.mutable = true;
|
||||
@ -241,23 +246,27 @@ MinerBlock.prototype.updateMerkle = function updateMerkle() {
|
||||
*/
|
||||
|
||||
MinerBlock.prototype.addTX = function addTX(tx) {
|
||||
var weight;
|
||||
var weight, sigops;
|
||||
|
||||
assert(!tx.mutable, 'Cannot add mutable TX to block.');
|
||||
|
||||
weight = this.block.getWeight() + tx.getWeight();
|
||||
|
||||
if (weight > constants.block.MAX_WEIGHT)
|
||||
if (this.block.hasTX(tx))
|
||||
return false;
|
||||
|
||||
if (this.block.hasTX(tx))
|
||||
weight = tx.getWeight();
|
||||
sigops = tx.getSigopsWeight(this.flags);
|
||||
|
||||
if (this.weight + weight > constants.block.MAX_WEIGHT)
|
||||
return false;
|
||||
|
||||
if (this.sigops + sigops > constants.block.MAX_SIGOPS_WEIGHT)
|
||||
return false;
|
||||
|
||||
if (!this.witness && tx.hasWitness())
|
||||
return false;
|
||||
|
||||
// Add the tx to our block
|
||||
this.block.addTX(tx);
|
||||
this.block.addTX(tx.clone());
|
||||
|
||||
// Update coinbase value
|
||||
this.updateCoinbase();
|
||||
@ -268,6 +277,47 @@ MinerBlock.prototype.addTX = function addTX(tx) {
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fill the block with sorted mempool entries.
|
||||
* @param {MempoolEntry[]} entries
|
||||
*/
|
||||
|
||||
MinerBlock.prototype.build = function build(entries) {
|
||||
var len = Math.min(entries.length, constants.block.MAX_SIZE);
|
||||
var i, entry, tx, weight, sigops;
|
||||
|
||||
this.weight = this.block.getWeight() + 12;
|
||||
this.sigops = this.coinbase.getSigopsWeight(this.flags);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
entry = entries[i];
|
||||
tx = entry.tx;
|
||||
|
||||
weight = tx.getWeight();
|
||||
sigops = tx.getSigopsWeight(this.flags);
|
||||
|
||||
if (this.weight + weight > constants.block.MAX_WEIGHT)
|
||||
break;
|
||||
|
||||
if (this.sigops + sigops > constants.block.MAX_SIGOPS_WEIGHT)
|
||||
break;
|
||||
|
||||
this.weight += weight;
|
||||
this.sigops += sigops;
|
||||
|
||||
// Add the tx to our block
|
||||
this.block.addTX(tx.clone());
|
||||
}
|
||||
|
||||
// Update coinbase value
|
||||
this.updateCoinbase();
|
||||
|
||||
// Update merkle root for new coinbase and new tx
|
||||
this.updateMerkle();
|
||||
|
||||
assert(this.block.getWeight() <= this.weight);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash until the nonce overflows.
|
||||
* @returns {Boolean} Whether the nonce was found.
|
||||
@ -322,6 +372,9 @@ MinerBlock.prototype.findNonceAsync = co(function* findNonceAsync() {
|
||||
if (nonce !== -1)
|
||||
break;
|
||||
|
||||
if (this.since > 20)
|
||||
return nonce;
|
||||
|
||||
block.nonce = max;
|
||||
|
||||
min += interval;
|
||||
@ -381,6 +434,9 @@ MinerBlock.prototype.mineAsync = co(function* mineAsync() {
|
||||
if (nonce !== -1)
|
||||
break;
|
||||
|
||||
if (this.since > 20)
|
||||
return;
|
||||
|
||||
this.iterate();
|
||||
}
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ Fullnode.prototype._init = function _init() {
|
||||
this.mempool.on('tx', function(tx) {
|
||||
self.emit('tx', tx);
|
||||
self.walletdb.addTX(tx).catch(onError);
|
||||
self.miner.addTX(tx);
|
||||
self.miner.notifyEntry();
|
||||
});
|
||||
|
||||
this.chain.on('block', function(block) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user