miner. improve workers.

This commit is contained in:
Christopher Jeffrey 2016-06-02 01:01:54 -07:00
parent 71934a22f1
commit a1cabfb8bd
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
5 changed files with 129 additions and 44 deletions

View File

@ -217,8 +217,7 @@ Block.prototype.addTX = function addTX(tx) {
index = this.txs.push(tx) - 1;
if (!this.mutable)
tx.setBlock(this, index);
tx.setBlock(this, index);
return tx;
};

View File

@ -11,6 +11,8 @@ var assert = utils.assert;
var constants = bcoin.protocol.constants;
var bn = require('bn.js');
var EventEmitter = require('events').EventEmitter;
var BufferReader = require('./reader');
var BufferWriter = require('./writer');
/**
* A bitcoin miner (supports mining witness blocks).
@ -19,8 +21,6 @@ var EventEmitter = require('events').EventEmitter;
* @param {Object} options
* @param {Base58Address} options.address - Payout address.
* @param {String?} [options.coinbaseFlags="mined by bcoin"]
* @param {Function?} dsha256 - Optional sha256 substitute
* for faster linked code.
* @property {Boolean} running
* @property {Boolean} loaded
* @emits Miner#block
@ -40,10 +40,6 @@ function Miner(options) {
this.address = this.options.address;
this.coinbaseFlags = this.options.coinbaseFlags || 'mined by bcoin';
// Allow a dsha256 option in case someone
// wants to pass in a faster linked in function.
this.dsha256 = this.options.dsha256 || utils.dsha256;
this.pool = options.pool;
this.chain = options.chain;
this.mempool = options.mempool;
@ -101,14 +97,14 @@ Miner.prototype._init = function _init() {
if (!self.running)
return;
if (self.attempt)
self.attempt.addTX(tx);
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);
self.attempt.addTX(tx.clone());
});
}
@ -272,7 +268,6 @@ Miner.prototype.createBlock = function createBlock(version, callback) {
coinbaseFlags: self.coinbaseFlags,
witness: self.chain.segwitActive,
parallel: self.options.parallel,
dsha256: self.dsha256,
network: self.network
});
@ -337,7 +332,6 @@ Miner.prototype.mineBlock = function mineBlock(version, callback) {
* @param {ChainEntry} options.tip
* @param {Number} options.height
* @param {Number} options.target - Compact form.
* @param {Function} options.dsha256
* @param {Base58Address} options.address - Payout address.
* @param {Boolean} options.witness - Allow witness
* transactions, mine a witness block.
@ -350,6 +344,8 @@ Miner.prototype.mineBlock = function mineBlock(version, callback) {
*/
function MinerBlock(options) {
var i;
if (!(this instanceof MinerBlock))
return new MinerBlock(options);
@ -360,7 +356,6 @@ function MinerBlock(options) {
this.target = utils.fromCompact(options.target).toBuffer('le', 32);
this.extraNonce = new bn(0);
this.iterations = 0;
this.dsha256 = options.dsha256;
this.coinbaseFlags = options.coinbaseFlags;
this.witness = options.witness;
this.address = options.address;
@ -415,6 +410,11 @@ function MinerBlock(options) {
this.block.addTX(this.coinbase);
if (options.txs) {
for (i = 0; i < options.txs.length; i++)
this.block.addTX(options.txs[i]);
}
if (this.witness) {
// Set up the witness nonce and
// commitment output for segwit.
@ -526,7 +526,7 @@ MinerBlock.prototype.findNonce = function findNonce() {
// The heart and soul of the miner: match the target.
while (block.nonce <= 0xffffffff) {
// Hash and test against the next target
if (rcmp(this.dsha256(data), target) < 0)
if (rcmp(utils.dsha256(data), target) < 0)
return true;
// Increment the nonce to get a different hash
@ -665,6 +665,64 @@ MinerBlock.prototype.destroy = function destroy() {
this.block = null;
};
/**
* Serialize the miner block.
* @returns {Buffer}
*/
MinerBlock.prototype.toRaw = function toRaw(writer) {
var p = new BufferWriter(writer);
var i;
p.writeBytes(this.tip.toRaw());
p.writeU32(this.block.version);
p.writeU32(this.block.bits);
p.writeVarString(this.address, 'ascii');
p.writeVarString(this.coinbaseFlags, 'utf8');
p.writeU8(this.witness ? 1 : 0);
p.writeVarint(this.block.txs.length - 1);
for (i = 1; i < this.block.txs.length; i++)
p.writeBytes(this.block.txs[i].render());
if (!writer)
p = p.render();
return p;
};
/**
* Instantiate a miner block from serialized data.
* @params {Buffer} data
* @returns {MinerBlock}
*/
MinerBlock.fromRaw = function fromRaw(data) {
var p = new BufferReader(data);
var tip = bcoin.chainentry.fromRaw(null, p);
var version = p.readU32();
var bits = p.readU32();
var address = p.readVarString('ascii');
var coinbaseFlags = p.readVarString('utf8');
var witness = p.readU8() === 1;
var count = p.readVarint();
var txs = [];
var i;
for (i = 0; i < count; i++)
txs.push(bcoin.tx.fromRaw(p));
return new MinerBlock({
tip: tip,
version: version,
target: bits,
address: address,
coinbaseFlags: coinbaseFlags,
witness: witness,
txs: txs
});
};
/**
* "Reverse" comparison so we don't have
* to waste time reversing the block hash.

View File

@ -1274,11 +1274,6 @@ Peer.prototype._handleGetData = function _handleGetData(items) {
return next();
}
if (tx.isCoinbase()) {
notfound.push({ type: constants.inv.TX, hash: hash });
return next();
}
data = witness
? self.framer.witnessTX(tx)
: self.framer.tx(tx);

View File

@ -2413,7 +2413,7 @@ BroadcastItem.prototype.finish = function finish(err) {
assert(this.timeout, 'Already finished.');
assert(this.pool.inv.map[this.hash], 'Already finished.');
clearInterval(this.timeout);
clearTimeout(this.timeout);
this.timeout = null;
delete this.pool.inv.map[this.hash];
@ -2443,6 +2443,8 @@ BroadcastItem.prototype.send = function send(peer, witness) {
if (this.type === constants.inv.TX) {
if (this.msg.isCoinbase()) {
peer.write(peer.framer.notFound([this]));
bcoin.debug('Failsafe: tried to relay a coinbase.');
this.finish(new Error('Coinbase.'));
return true;
}

View File

@ -68,6 +68,52 @@ Workers.cleanup = function cleanup() {
Workers._exitBound = false;
/**
* Bind to process events in order to cleanup listeners.
* @private
*/
Workers._bindExit = function _bindExit() {
if (utils.isBrowser)
return;
if (Workers._exitBound)
return;
Workers._exitBound = true;
function onExit(err) {
Workers.cleanup();
if (err) {
console.error(err.stack + '');
process.exit(1);
return;
}
process.exit(0);
}
process.once('exit', function() {
Workers.cleanup();
});
if (process.listeners('SIGINT').length === 0)
process.once('SIGINT', onExit);
if (process.listeners('SIGTERM').length === 0)
process.once('SIGTERM', onExit);
if (process.listeners('uncaughtException').length === 0)
process.once('uncaughtException', onExit);
process.on('newListener', function(name) {
if (name === 'SIGINT'
|| name === 'SIGTERM'
|| name === 'uncaughtException') {
process.removeListener(name, onExit);
}
});
};
/**
* Spawn a new worker.
* @param {Number} id - Worker ID.
@ -110,10 +156,7 @@ Workers.prototype.spawn = function spawn(id) {
Workers.children.push(child);
if (!Workers._exitBound) {
process.once('exit', Workers.cleanup);
Workers._exitBound = true;
}
Workers._bindExit();
return child;
};
@ -221,15 +264,7 @@ Workers.prototype.verify = function verify(tx, index, force, flags, callback) {
*/
Workers.prototype.mine = function mine(attempt, callback) {
var data = {
tip: attempt.tip,
version: attempt.block.version,
target: attempt.block.bits,
address: attempt.address,
coinbaseFlags: attempt.coinbaseFlags,
witness: attempt.witness
};
return this.execute('mine', [data], -1, callback);
return this.execute('mine', [attempt], -1, callback);
};
/**
@ -679,16 +714,7 @@ jobs.verify = function verify(tx, index, force, flags) {
* @returns {Block}
*/
jobs.mine = function mine(data) {
var attempt = new bcoin.minerblock({
tip: data.tip,
version: data.version,
target: data.target,
address: data.address,
coinbaseFlags: data.coinbaseFlags,
witness: data.witness,
dsha256: utils.dsha256
});
jobs.mine = function mine(attempt) {
attempt.on('status', function(stat) {
bcoin.debug(
'Miner: hashrate=%dkhs hashes=%d target=%d height=%d best=%s',
@ -793,6 +819,9 @@ Framer.item = function _item(item, p) {
} else if (item instanceof bcoin.mempoolentry) {
p.writeU8(44);
item.toRaw(p);
} else if (item instanceof bcoin.minerblock) {
p.writeU8(45);
item.toRaw(p);
} else if (bn.isBN(item)) {
p.writeU8(50);
p.writeVarBytes(item.toBuffer());
@ -951,8 +980,10 @@ Parser.parseItem = function parseItem(p) {
return bcoin.coin.fromExtended(p);
case 43:
return bcoin.chainentry.fromRaw(null, p);
case 43:
case 44:
return bcoin.mempoolentry.fromRaw(p);
case 45:
return bcoin.minerblock.fromRaw(p);
case 50:
return new bn(p.readVarBytes());
default: