miner: refactor.
This commit is contained in:
parent
2c31d7f1b0
commit
749a912f8c
@ -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
|
||||
*/
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user