various fixes for our miner.

This commit is contained in:
Christopher Jeffrey 2016-01-06 19:57:35 -08:00
parent 8d120a4fd6
commit c56640a433
4 changed files with 100 additions and 34 deletions

View File

@ -25,6 +25,7 @@ bcoin.wallet = require('./bcoin/wallet');
bcoin.peer = require('./bcoin/peer'); bcoin.peer = require('./bcoin/peer');
bcoin.pool = require('./bcoin/pool'); bcoin.pool = require('./bcoin/pool');
bcoin.hd = require('./bcoin/hd'); bcoin.hd = require('./bcoin/hd');
bcoin.miner = require('./bcoin/miner');
bcoin.protocol.network.set(process.env.BCOIN_NETWORK || 'main'); bcoin.protocol.network.set(process.env.BCOIN_NETWORK || 'main');

View File

@ -110,15 +110,20 @@ Chain.prototype._init = function _init() {
var self = this; var self = this;
var s; var s;
if (!this.storage) this.loading = true;
if (!this.storage) {
utils.nextTick(function() {
self.loading = false;
self.emit('load');
});
return; return;
}
utils.nextTick(function() { utils.nextTick(function() {
self.emit('debug', 'Chain is loading.'); self.emit('debug', 'Chain is loading.');
}); });
this.loading = true;
s = this.storage.createReadStream({ s = this.storage.createReadStream({
start: this.prefix, start: this.prefix,
end: this.prefix + 'z' end: this.prefix + 'z'
@ -681,7 +686,7 @@ Chain.prototype._compact = function _compact(keep) {
var entries = this._filter(this.index.entries); var entries = this._filter(this.index.entries);
if (!keep) if (!keep)
keep = 1000; keep = network.powDiffInterval + 10;
// Keep only last 1000 consequent blocks, dilate others at: // Keep only last 1000 consequent blocks, dilate others at:
// 7 day range for blocks before 2013 // 7 day range for blocks before 2013

View File

@ -13,6 +13,8 @@ var bn = require('bn.js');
var inherits = require('inherits'); var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var crypto = require('crypto');
/** /**
* Miner * Miner
*/ */
@ -30,8 +32,8 @@ function Miner(options) {
this.address = this.options.address; this.address = this.options.address;
this.msg = this.options.msg || 'mined by bcoin'; this.msg = this.options.msg || 'mined by bcoin';
this.chain = options.chain || bcoin.chain.global;
this.pool = options.pool || bcoin.pool.global; this.pool = options.pool || bcoin.pool.global;
this.chain = options.chain || this.pool.chain || bcoin.chain.global;
this.running = false; this.running = false;
this.timeout = null; this.timeout = null;
@ -40,7 +42,9 @@ function Miner(options) {
this.fee = new bn(0); this.fee = new bn(0);
this.last = this.chain.getTip(); this.last = this.chain.getTip();
this.block = null; this.block = null;
this.rate = 0; this._begin = utils.now();
this._init();
} }
inherits(Miner, EventEmitter); inherits(Miner, EventEmitter);
@ -61,15 +65,23 @@ Miner.prototype._init = function _init() {
// }); // });
this.on('block', function(block) { this.on('block', function(block) {
self.emit('debug', self.chain.emit('debug',
'Found block: %d (%s)', 'Found block: %d (%s)',
self.last.height + 1, block.height,
block.hash('hex')); block.hash('hex'));
// Emit the block hex as a failsafe (in case we can't send it)
self.chain.emit('debug', 'Block: %s', utils.toHex(block.render()));
self.pool.sendBlock(block); self.pool.sendBlock(block);
}); });
this.on('status', function(stat) { this.on('status', function(stat) {
self.emit('debug', 'Hashes per second: %s', stat.hashrate); self.chain.emit('debug',
'hashrate=%dkhs hashes=%d target=%d height=%d best=%s',
stat.hashrate / 1000 | 0,
stat.hashes,
stat.target,
stat.height,
stat.best);
}); });
}; };
@ -154,7 +166,7 @@ Miner.prototype.addTX = function addTX(tx) {
// Add the tx to our block // Add the tx to our block
this.block.txs.push(tx); this.block.txs.push(tx);
// Calulcate our new reward fee // Calculate our new reward fee
if (full) if (full)
this.fee.iadd(tx.getFee()); this.fee.iadd(tx.getFee());
@ -202,7 +214,7 @@ Miner.prototype.createBlock = function createBlock(tx) {
: this.last.hash, : this.last.hash,
merkleRoot: utils.toHex(constants.zeroHash.slice()), merkleRoot: utils.toHex(constants.zeroHash.slice()),
ts: ts, ts: ts,
bits: utils.toCompact(target), bits: target,
nonce: 0 nonce: 0
}; };
@ -212,20 +224,21 @@ Miner.prototype.createBlock = function createBlock(tx) {
block.txs.push(coinbase); block.txs.push(coinbase);
block.target = utils.fromCompact(target);
block.extraNonce = new bn(0);
// Update coinbase since our coinbase was added. // Update coinbase since our coinbase was added.
this.updateCoinbase(block); this.updateCoinbase(block);
// Create our merkle root. // Create our merkle root.
this.updateMerkle(block); this.updateMerkle(block);
block.target = target;
block.extraNonce = new bn(0);
return block; return block;
}; };
Miner.prototype.updateCoinbase = function updateCoinbase(block) { Miner.prototype.updateCoinbase = function updateCoinbase(block) {
var coinbase = block.coinbase; var coinbase = block.coinbase;
var reward = bcoin.block.reward(this.last.height + 1);
assert(coinbase); assert(coinbase);
@ -233,7 +246,7 @@ Miner.prototype.updateCoinbase = function updateCoinbase(block) {
block = this.block; block = this.block;
coinbase.inputs[0].script[1] = block.extraNonce.toArray(); coinbase.inputs[0].script[1] = block.extraNonce.toArray();
coinbase.outputs[0].value = bcoin.block.reward(this.last.height + 1).add(fee); coinbase.outputs[0].value = reward.add(this.fee);
}; };
Miner.prototype.updateMerkle = function updateMerkle(block) { Miner.prototype.updateMerkle = function updateMerkle(block) {
@ -277,19 +290,62 @@ Miner.prototype.iterate = function iterate() {
}, 10); }, 10);
}; };
Miner.prototype.__defineGetter__('hashes', function() {
return this.block.extraNonce.muln(0xffffffff).addn(this.block.nonce);
});
Miner.prototype.__defineGetter__('rate', function() {
if (!this.block.nonce)
return 0;
// Calculate our terrible hashrate
return (this.block.nonce / (utils.now() - this._begin)) * 2 | 0;
});
Miner.prototype.sendStatus = function sendStatus() {
this.emit('status', {
block: this.block,
target: this.block.bits,
hashes: this.hashes.toString(10),
hashrate: this.rate,
height: this.last.height + 1,
best: utils.revHex(this.last.hash)
});
};
Miner.prototype.findNonce = function findNonce() { Miner.prototype.findNonce = function findNonce() {
var begin = utils.now(); var data = new Buffer(this.block.render());
var now;
this._begin = utils.now();
// The heart and soul of the miner: match the target. // The heart and soul of the miner: match the target.
while (this.block.nonce <= 0xffffffff) { while (this.block.nonce <= 0xffffffff) {
if (utils.testTarget(this.block.target, this.block.hash())) // Hash and test against the next target
if (utils.testTarget(this.block.target, dsha256(data)))
return true; return true;
// Increment the nonce to get a different hash
this.block.nonce++; this.block.nonce++;
utils.writeU32(data, this.block.nonce, 76);
// Send progress report every so often
if (this.block.nonce % 100000 === 0)
this.sendStatus();
} }
// Calculate our terrible hashrate // Send progress report
this.rate = (0xffffffff / (utils.now() - begin)) * 2; this.sendStatus();
// If we took more a second or more (likely),
// skip incrementing the extra nonce and just
// update the timestamp. This improves
// performance because we do not have to
// recalculate the merkle root.
now = utils.now();
if (now > this.block.ts) {
this.block.ts = now;
return false;
}
// Overflow the nonce and increment the extraNonce. // Overflow the nonce and increment the extraNonce.
this.block.nonce = 0; this.block.nonce = 0;
@ -301,17 +357,21 @@ Miner.prototype.findNonce = function findNonce() {
// We changed the coinbase, need to update merkleRoot. // We changed the coinbase, need to update merkleRoot.
this.updateMerkle(); this.updateMerkle();
// Send progress report
this.emit('status', {
block: this.block,
target: this.block.target,
hashes: this.block.extraNonce.mul(0xffffffff).toString(10),
hashrate: this.rate
});
return false; return false;
}; };
/**
* Utils
*/
function sha256(data, enc) {
return crypto.createHash('sha256').update(data).digest();
}
function dsha256(data, enc) {
return Array.prototype.slice.call(sha256(sha256(data, enc)));
}
/** /**
* Expose * Expose
*/ */

View File

@ -149,13 +149,13 @@ function Pool(options) {
Pool.global = this; Pool.global = this;
if (!this.chain.loading) { this.loading = true;
this._init();
} else { this.chain.once('load', function() {
this.chain.once('load', function() { self.loading = false;
self._init(); self.emit('load');
}); self._init();
} });
} }
inherits(Pool, EventEmitter); inherits(Pool, EventEmitter);