miner: refactor.

This commit is contained in:
Christopher Jeffrey 2016-10-05 21:39:43 -07:00
parent 2c31d7f1b0
commit 749a912f8c
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 66 additions and 94 deletions

View File

@ -23,7 +23,7 @@ var time = require('../net/timedata');
* @param {Base58Address} options.address - Payout address.
* @param {String?} [options.coinbaseFlags="mined by bcoin"]
* @property {Boolean} running
* @property {Boolean} loaded
* @property {MinerBlock} attempt
* @emits Miner#block
* @emits Miner#status
*/
@ -34,30 +34,21 @@ function Miner(options) {
AsyncObject.call(this);
if (!options)
options = {};
assert(options, 'Miner requires options.');
assert(options.chain, 'Miner requires a blockchain.');
this.options = options;
this.address = Address(this.options.address);
this.coinbaseFlags = this.options.coinbaseFlags || 'mined by bcoin';
this.version = null;
if (typeof this.coinbaseFlags === 'string')
this.coinbaseFlags = new Buffer(this.coinbaseFlags, 'utf8');
this.pool = options.pool;
this.chain = options.chain;
this.logger = options.logger || this.chain.logger;
this.mempool = options.mempool;
this.fees = this.mempool ? this.mempool.fees : options.fees;
assert(this.chain, 'Miner requires a blockchain.');
this.network = this.chain.network;
this.logger = options.logger || this.chain.logger;
this.running = false;
this.timeout = null;
this.attempt = null;
this.version = -1;
this.address = Address(options.address);
this.coinbaseFlags = options.coinbaseFlags || 'mined by bcoin';
this._init();
}
@ -71,29 +62,8 @@ utils.inherits(Miner, AsyncObject);
Miner.prototype._init = function _init() {
var self = this;
if (this.mempool) {
this.mempool.on('tx', function(tx) {
if (!self.running)
return;
if (self.attempt)
self.attempt.addTX(tx.clone());
});
} else if (this.pool) {
this.pool.on('tx', function(tx) {
if (!self.running)
return;
if (self.attempt)
self.attempt.addTX(tx.clone());
});
}
this.chain.on('tip', function(tip) {
if (!self.running)
return;
self.stop();
setTimeout(function() {
self.start();
}, self.network.type === 'regtest' ? 100 : 5000);
self.restart();
});
this.on('block', function(block) {
@ -120,10 +90,10 @@ Miner.prototype._init = function _init() {
*/
Miner.prototype._open = co(function* open() {
yield this.chain.open();
if (this.mempool)
yield this.mempool.open();
else
yield this.chain.open();
this.logger.info('Miner loaded (flags=%s).',
this.coinbaseFlags.toString('utf8'));
@ -145,17 +115,16 @@ Miner.prototype._close = function close() {
*/
Miner.prototype.start = co(function* start() {
var self = this;
var attempt, block;
this.stop();
assert(!this.running, 'Miner is already running.');
this.running = true;
// Create a new block and start hashing
try {
attempt = yield this.createBlock();
} catch (e) {
this.running = false;
this.emit('error', e);
return;
}
@ -165,35 +134,23 @@ Miner.prototype.start = co(function* start() {
this.attempt = attempt;
attempt.on('status', function(status) {
self.emit('status', status);
});
try {
block = yield attempt.mineAsync();
} catch (e) {
if (!this.running)
return;
this.emit('error', e);
return this.start();
}
// Add our block to the chain
try {
yield this.chain.add(block);
} catch (err) {
if (err.type === 'VerifyError')
this.logger.warning('%s could not be added to chain.', block.rhash);
this.emit('error', err);
this.start();
this.restart();
return;
}
// Emit our newly found block
this.emit('block', block);
try {
yield this.chain.add(block);
} catch (e) {
this.emit('error', e);
this.restart();
return;
}
// `tip` will now be emitted by chain
// and the whole process starts over.
this.emit('block', block);
});
/**
@ -201,8 +158,7 @@ Miner.prototype.start = co(function* start() {
*/
Miner.prototype.stop = function stop() {
if (!this.running)
return;
assert(this.running, 'Miner is not running.');
this.running = false;
@ -212,17 +168,32 @@ Miner.prototype.stop = function stop() {
}
};
/**
* Restart miner.
*/
Miner.prototype.restart = function restart() {
var self = this;
if (!this.running)
return;
this.stop();
setTimeout(function() {
self.start();
}, 500);
};
/**
* Create a block "attempt".
* @param {Number?} version - Custom block version.
* @param {ChainEntry} tip
* @returns {Promise} - Returns {@link MinerBlock}.
*/
Miner.prototype.createBlock = co(function* createBlock(tip) {
var i, ts, attempt, txs, tx, target, version;
if (!this.loaded)
yield this.open();
var version = this.version;
var i, ts, attempt, txs, tx, target;
if (!tip)
tip = this.chain.tip;
@ -231,23 +202,18 @@ Miner.prototype.createBlock = co(function* createBlock(tip) {
ts = Math.max(time.now(), tip.ts + 1);
// Find target
target = yield this.chain.getTargetAsync(ts, tip);
if (this.version != null) {
version = this.version;
} else {
// Calculate version with versionbits
if (version === -1)
version = yield this.chain.computeBlockVersion(tip);
}
attempt = new MinerBlock({
tip: tip,
version: version,
target: target,
bits: target,
address: this.address,
coinbaseFlags: this.coinbaseFlags,
witness: this.chain.segwitActive,
witness: this.chain.state.hasWitness(),
network: this.network
});
@ -266,16 +232,28 @@ Miner.prototype.createBlock = co(function* createBlock(tip) {
/**
* Mine a single block.
* @param {Number?} version - Custom block version.
* @param {ChainEntry} tip
* @returns {Promise} - Returns [{@link Block}].
*/
Miner.prototype.mineBlock = co(function* mineBlock(tip) {
// Create a new block and start hashing
var attempt = yield this.createBlock(tip);
return yield attempt.mineAsync();
});
/**
* Add a transaction to the current block.
* @param {TX} tx
*/
Miner.prototype.addTX = function addTX(tx) {
if (!this.running)
return;
if (this.attempt)
this.attempt.addTX(tx.clone());
};
/*
* Expose
*/

View File

@ -48,11 +48,10 @@ function MinerBlock(options) {
EventEmitter.call(this);
this.options = options;
this.workerPool = options.workerPool;
this.tip = options.tip;
this.version = options.version;
this.height = options.tip.height + 1;
this.bits = options.target;
this.bits = options.bits;
this.target = utils.fromCompact(this.bits).toArrayLike(Buffer, 'le', 32);
this.extraNonce = new bn(0);
this.iterations = 0;
@ -95,10 +94,9 @@ MinerBlock.prototype.__defineGetter__('rate', function() {
*/
MinerBlock.prototype._init = function _init() {
var options = this.options;
var block = this.block;
var cb = this.coinbase;
var i, input, output, hash, witnessNonce;
var input, output, hash, witnessNonce;
// Coinbase input.
input = new Input();
@ -148,7 +146,7 @@ MinerBlock.prototype._init = function _init() {
}
// Setup our block.
block.version = options.version;
block.version = this.version;
block.prevBlock = this.tip.hash;
block.merkleRoot = constants.NULL_HASH;
block.ts = Math.max(time.now(), this.tip.ts + 1);
@ -158,11 +156,6 @@ MinerBlock.prototype._init = function _init() {
block.addTX(cb);
if (options.txs) {
for (i = 0; i < options.txs.length; i++)
block.addTX(options.txs[i]);
}
// Update coinbase since our coinbase was added.
this.updateCoinbase();

View File

@ -199,6 +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);
});
this.chain.on('block', function(block) {