miner.
This commit is contained in:
parent
9356a40e62
commit
40cabd37fc
31
README.md
31
README.md
@ -132,6 +132,37 @@ $ node bin/bcoin-cli wallet primary --passphrase=node
|
|||||||
$ node bin/bcoin-cli mempool
|
$ node bin/bcoin-cli mempool
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Creating a blockchain and mempool
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var bcoin = require('bcoin');
|
||||||
|
bcoin.protocol.network.set('regtest');
|
||||||
|
var chain = new bcoin.chain({ db: 'memory' });
|
||||||
|
var mempool = new bcoin.mempool({ chain: chain, db: 'memory' });
|
||||||
|
var miner = new bcoin.miner({ chain: chain, mempool: mempool });
|
||||||
|
|
||||||
|
// Create a block "attempt"
|
||||||
|
miner.createBlock(function(err, attempt) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
|
||||||
|
// Mine the block on the worker pool (use mine() for the master process)
|
||||||
|
attempt.mineAsync(function(err, block) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
|
||||||
|
// Add the block to the chain
|
||||||
|
chain.add(block, function(err) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
|
||||||
|
console.log('Added %s to the blockchain.', block.rhash);
|
||||||
|
console.log(block);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### TX creation
|
### TX creation
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|||||||
@ -276,8 +276,6 @@ Block.prototype.getReward = function getReward() {
|
|||||||
var reward = Block.reward(this.height);
|
var reward = Block.reward(this.height);
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
assert(this.height !== -1);
|
|
||||||
|
|
||||||
for (i = 1; i < this.txs.length; i++)
|
for (i = 1; i < this.txs.length; i++)
|
||||||
reward.iadd(this.txs[i].getFee());
|
reward.iadd(this.txs[i].getFee());
|
||||||
|
|
||||||
|
|||||||
@ -44,8 +44,6 @@ function Miner(options) {
|
|||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
|
|
||||||
this.block = null;
|
this.block = null;
|
||||||
this.iterations = 0;
|
|
||||||
this._begin = utils.now();
|
|
||||||
|
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -68,13 +66,13 @@ Miner.prototype._init = function _init() {
|
|||||||
this.mempool.on('tx', function(tx) {
|
this.mempool.on('tx', function(tx) {
|
||||||
if (!self.running)
|
if (!self.running)
|
||||||
return;
|
return;
|
||||||
self.addTX(tx);
|
self.attempt.addTX(tx);
|
||||||
});
|
});
|
||||||
} else if (this.pool) {
|
} else if (this.pool) {
|
||||||
this.pool.on('tx', function(tx) {
|
this.pool.on('tx', function(tx) {
|
||||||
if (!self.running)
|
if (!self.running)
|
||||||
return;
|
return;
|
||||||
self.addTX(tx);
|
self.attempt.addTX(tx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,41 +120,40 @@ Miner.prototype.start = function start() {
|
|||||||
|
|
||||||
this.running = true;
|
this.running = true;
|
||||||
|
|
||||||
// Reset iterations
|
|
||||||
this.iterations = 0;
|
|
||||||
|
|
||||||
// Create a new block and start hashing
|
// Create a new block and start hashing
|
||||||
this.createBlock(function(err, block) {
|
this.createBlock(function(err, attempt) {
|
||||||
if (err)
|
if (err)
|
||||||
return self.emit('error', err);
|
return self.emit('error', err);
|
||||||
|
|
||||||
self.block = block;
|
if (!self.running)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!self.mempool)
|
self.attempt = attempt;
|
||||||
return self.iterate();
|
|
||||||
|
|
||||||
self.mempool.getSnapshot(function(err, hashes) {
|
attempt.on('status', function(status) {
|
||||||
if (err)
|
self.emit('status', status);
|
||||||
return self.emit('error', err);
|
});
|
||||||
|
|
||||||
utils.forEachSerial(hashes, function(hash, next) {
|
attempt.mineAsync(function(err, block) {
|
||||||
self.mempool.getTX(hash, function(err, tx) {
|
if (err) {
|
||||||
if (err)
|
self.emit('error', err);
|
||||||
return next(err);
|
return self.start();
|
||||||
|
}
|
||||||
|
|
||||||
self.mempool.fillAllCoins(tx, function(err) {
|
// Add our block to the chain
|
||||||
if (err)
|
self.chain.add(block, function(err) {
|
||||||
return next(err);
|
if (err) {
|
||||||
|
if (err.type === 'VerifyError')
|
||||||
|
utils.debug('%s could not be added to chain.', block.rhash);
|
||||||
|
self.emit('error', err);
|
||||||
|
return self.start();
|
||||||
|
}
|
||||||
|
|
||||||
self.addTX(tx);
|
// Emit our newly found block
|
||||||
next();
|
self.emit('block', block);
|
||||||
});
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
return self.emit('error', err);
|
|
||||||
|
|
||||||
self.iterate();
|
// `tip` will now be emitted by chain
|
||||||
|
// and the whole process starts over.
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -168,11 +165,185 @@ Miner.prototype.stop = function stop() {
|
|||||||
|
|
||||||
this.running = false;
|
this.running = false;
|
||||||
|
|
||||||
clearTimeout(this.timeout);
|
if (this.attempt) {
|
||||||
this.timeout = null;
|
this.attempt.destroy();
|
||||||
|
this.attempt = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Miner.prototype.addTX = function addTX(tx) {
|
Miner.prototype.createBlock = function createBlock(callback) {
|
||||||
|
var self = this;
|
||||||
|
var ts = Math.max(utils.now(), this.chain.tip.ts + 1);
|
||||||
|
var attempt;
|
||||||
|
|
||||||
|
// Find target
|
||||||
|
this.chain.getTargetAsync(this.chain.tip, ts, function(err, target) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
// Calculate version with versionbits
|
||||||
|
self.chain.computeBlockVersion(self.chain.tip, function(err, version) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
attempt = new MinerBlock({
|
||||||
|
tip: self.chain.tip,
|
||||||
|
version: version,
|
||||||
|
target: target,
|
||||||
|
address: self.address,
|
||||||
|
coinbaseFlags: self.coinbaseFlags,
|
||||||
|
segwit: self.chain.segwitActive,
|
||||||
|
dsha256: self.dsha256
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!self.mempool)
|
||||||
|
return callback(null, attempt);
|
||||||
|
|
||||||
|
self.mempool.getSnapshot(function(err, hashes) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
utils.forEachSerial(hashes, function(hash, next) {
|
||||||
|
self.mempool.getTX(hash, function(err, tx) {
|
||||||
|
if (err)
|
||||||
|
return next(err);
|
||||||
|
|
||||||
|
self.mempool.fillAllCoins(tx, function(err) {
|
||||||
|
if (err)
|
||||||
|
return next(err);
|
||||||
|
|
||||||
|
attempt.addTX(tx);
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, function(err) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
return callback(null, attempt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Miner.prototype.mineBlock = function mineBlock(callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Create a new block and start hashing
|
||||||
|
this.createBlock(function(err, attempt) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
attempt.mineAsync(callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinerBlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
function MinerBlock(options) {
|
||||||
|
if (!(this instanceof MinerBlock))
|
||||||
|
return new MinerBlock(options);
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
this.tip = options.tip;
|
||||||
|
this.height = options.tip.height + 1;
|
||||||
|
this.target = utils.fromCompact(options.target).toBuffer('le', 32);
|
||||||
|
this.extraNonce = new bn(0);
|
||||||
|
this.iterations = 0;
|
||||||
|
this.dsha256 = options.dsha256;
|
||||||
|
|
||||||
|
// Create a coinbase
|
||||||
|
this.coinbase = new bcoin.mtx();
|
||||||
|
|
||||||
|
this.coinbase.addInput({
|
||||||
|
prevout: {
|
||||||
|
hash: utils.toHex(constants.zeroHash),
|
||||||
|
index: 0xffffffff
|
||||||
|
},
|
||||||
|
coin: null,
|
||||||
|
script: new bcoin.script([
|
||||||
|
// Height (required in v2+ blocks)
|
||||||
|
bcoin.script.array(this.height),
|
||||||
|
// extraNonce - incremented when
|
||||||
|
// the nonce overflows.
|
||||||
|
bcoin.script.array(0),
|
||||||
|
// Add a nonce to ensure we don't
|
||||||
|
// collide with a previous coinbase
|
||||||
|
// of ours. This isn't really
|
||||||
|
// necessary nowdays due to bip34
|
||||||
|
// (used above).
|
||||||
|
bcoin.script.array(utils.nonce()),
|
||||||
|
// Let the world know this little
|
||||||
|
// miner succeeded.
|
||||||
|
new Buffer(options.coinbaseFlags, 'ascii')
|
||||||
|
]),
|
||||||
|
witness: new bcoin.script.witness([]),
|
||||||
|
sequence: 0xffffffff
|
||||||
|
});
|
||||||
|
|
||||||
|
this.coinbase.addOutput({
|
||||||
|
address: options.address,
|
||||||
|
value: new bn(0)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create our block
|
||||||
|
this.block = new bcoin.block({
|
||||||
|
version: options.version,
|
||||||
|
prevBlock: this.tip.hash,
|
||||||
|
merkleRoot: constants.zeroHash,
|
||||||
|
ts: Math.max(utils.now(), this.tip.ts + 1),
|
||||||
|
bits: options.target,
|
||||||
|
nonce: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
this.block.txs.push(this.coinbase);
|
||||||
|
|
||||||
|
if (options.segwit) {
|
||||||
|
// Set up the witness nonce and
|
||||||
|
// commitment output for segwit.
|
||||||
|
this.witness = true;
|
||||||
|
this.witnessNonce = utils.dsha256(new Buffer(this.tip.hash, 'hex'));
|
||||||
|
this.coinbase.inputs[0].witness.items[0] = this.witnessNonce;
|
||||||
|
this.coinbase.addOutput({
|
||||||
|
script: new bcoin.script([]),
|
||||||
|
value: new bn(0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update coinbase since our coinbase was added.
|
||||||
|
this.updateCoinbase();
|
||||||
|
|
||||||
|
// Create our merkle root.
|
||||||
|
this.updateMerkle();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.inherits(MinerBlock, EventEmitter);
|
||||||
|
|
||||||
|
MinerBlock.prototype.updateCommitment = function updateCommitment() {
|
||||||
|
var hash = this.block.getCommitmentHash();
|
||||||
|
this.coinbase.outputs[1].script = bcoin.script.createCommitment(hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.updateCoinbase = function updateCoinbase() {
|
||||||
|
this.coinbase.inputs[0].script[1] = this.extraNonce.toBuffer();
|
||||||
|
this.coinbase.outputs[0].value = this.block.getReward();
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.updateMerkle = function updateMerkle() {
|
||||||
|
// Always update commitment before updating merkle root.
|
||||||
|
// The updated commitment output will change the merkle root.
|
||||||
|
if (this.witness)
|
||||||
|
this.updateCommitment();
|
||||||
|
|
||||||
|
this.block.ts = Math.max(utils.now(), this.tip.ts + 1);
|
||||||
|
this.block.merkleRoot = this.block.getMerkleRoot('hex');
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.addTX = function addTX(tx) {
|
||||||
var size = this.block.getVirtualSize() + tx.getVirtualSize();
|
var size = this.block.getVirtualSize() + tx.getVirtualSize();
|
||||||
|
|
||||||
// Deliver me from the block size debate, please
|
// Deliver me from the block size debate, please
|
||||||
@ -197,206 +368,33 @@ Miner.prototype.addTX = function addTX(tx) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Miner.prototype.createBlock = function createBlock(callback) {
|
MinerBlock.prototype.findNonce = function findNonce() {
|
||||||
var self = this;
|
var tip = this.tip;
|
||||||
var ts = Math.max(utils.now(), this.chain.tip.ts + 1);
|
var block = this.block;
|
||||||
var coinbase, headers, block;
|
var target = this.target;
|
||||||
|
var data = block.abbr();
|
||||||
// Find target
|
|
||||||
this.chain.getTargetAsync(this.chain.tip, ts, function(err, target) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
// Calculate version with versionbits
|
|
||||||
self.chain.computeBlockVersion(self.chain.tip, function(err, version) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
// Create a coinbase
|
|
||||||
coinbase = bcoin.mtx();
|
|
||||||
|
|
||||||
coinbase.addInput({
|
|
||||||
prevout: {
|
|
||||||
hash: utils.toHex(constants.zeroHash),
|
|
||||||
index: 0xffffffff
|
|
||||||
},
|
|
||||||
coin: null,
|
|
||||||
script: new bcoin.script([
|
|
||||||
// Height (required in v2+ blocks)
|
|
||||||
bcoin.script.array(self.chain.height + 1),
|
|
||||||
// extraNonce - incremented when
|
|
||||||
// the nonce overflows.
|
|
||||||
bcoin.script.array(0),
|
|
||||||
// Add a nonce to ensure we don't
|
|
||||||
// collide with a previous coinbase
|
|
||||||
// of ours. This isn't really
|
|
||||||
// necessary nowdays due to bip34
|
|
||||||
// (used above).
|
|
||||||
bcoin.script.array(utils.nonce()),
|
|
||||||
// Let the world know this little
|
|
||||||
// miner succeeded.
|
|
||||||
new Buffer(self.coinbaseFlags, 'ascii')
|
|
||||||
]),
|
|
||||||
witness: new bcoin.script.witness([]),
|
|
||||||
sequence: 0xffffffff
|
|
||||||
});
|
|
||||||
|
|
||||||
coinbase.addOutput({
|
|
||||||
address: self.address,
|
|
||||||
value: new bn(0)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create our block
|
|
||||||
headers = {
|
|
||||||
version: version,
|
|
||||||
prevBlock: self.chain.tip.hash,
|
|
||||||
merkleRoot: constants.zeroHash,
|
|
||||||
ts: ts,
|
|
||||||
bits: target,
|
|
||||||
nonce: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
block = bcoin.block(headers);
|
|
||||||
|
|
||||||
block.txs.push(coinbase);
|
|
||||||
|
|
||||||
block.height = self.chain.height + 1;
|
|
||||||
block.target = utils.fromCompact(target).toBuffer('le', 32);
|
|
||||||
block.extraNonce = new bn(0);
|
|
||||||
|
|
||||||
if (self.chain.segwitActive) {
|
|
||||||
// Set up the witness nonce and
|
|
||||||
// commitment output for segwit.
|
|
||||||
block.witness = true;
|
|
||||||
block.witnessNonce = utils.nonce().toBuffer('le', 8);
|
|
||||||
coinbase.inputs[0].witness.items[0] = block.witnessNonce;
|
|
||||||
coinbase.addOutput({
|
|
||||||
script: new bcoin.script([]),
|
|
||||||
value: new bn(0)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update coinbase since our coinbase was added.
|
|
||||||
self.updateCoinbase(block);
|
|
||||||
|
|
||||||
// Create our merkle root.
|
|
||||||
self.updateMerkle(block);
|
|
||||||
|
|
||||||
return callback(null, block);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Miner.prototype.updateCommitment = function updateCommitment(block) {
|
|
||||||
var coinbase = block.txs[0];
|
|
||||||
var hash;
|
|
||||||
|
|
||||||
assert(coinbase);
|
|
||||||
|
|
||||||
if (!block)
|
|
||||||
block = this.block;
|
|
||||||
|
|
||||||
hash = block.getCommitmentHash();
|
|
||||||
coinbase.outputs[1].script = bcoin.script.createCommitment(hash);
|
|
||||||
};
|
|
||||||
|
|
||||||
Miner.prototype.updateCoinbase = function updateCoinbase(block) {
|
|
||||||
var coinbase = block.txs[0];
|
|
||||||
|
|
||||||
assert(coinbase);
|
|
||||||
|
|
||||||
if (!block)
|
|
||||||
block = this.block;
|
|
||||||
|
|
||||||
coinbase.inputs[0].script[1] = block.extraNonce.toBuffer();
|
|
||||||
coinbase.outputs[0].value = block.getReward();
|
|
||||||
};
|
|
||||||
|
|
||||||
Miner.prototype.updateMerkle = function updateMerkle(block) {
|
|
||||||
if (!block)
|
|
||||||
block = this.block;
|
|
||||||
|
|
||||||
// Always update commitment before updating merkle root.
|
|
||||||
// The updated commitment output will change the merkle root.
|
|
||||||
if (block.witness)
|
|
||||||
this.updateCommitment(block);
|
|
||||||
|
|
||||||
block.ts = Math.max(utils.now(), this.chain.tip.ts + 1);
|
|
||||||
block.merkleRoot = block.getMerkleRoot('hex');
|
|
||||||
};
|
|
||||||
|
|
||||||
Miner.prototype.iterate = function iterate() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.timeout = setTimeout(function() {
|
|
||||||
// Try to find a block: do one iteration of extraNonce
|
|
||||||
if (!self.findNonce())
|
|
||||||
return self.iterate();
|
|
||||||
|
|
||||||
// Add our block to the chain
|
|
||||||
self.chain.add(self.block, function(err) {
|
|
||||||
if (err) {
|
|
||||||
if (err.type === 'VerifyError')
|
|
||||||
utils.debug('%s could not be added to chain.', self.block.rhash);
|
|
||||||
self.emit('error', err);
|
|
||||||
return self.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit our newly found block
|
|
||||||
self.emit('block', self.block);
|
|
||||||
|
|
||||||
// `tip` will now be emitted by chain
|
|
||||||
// and the whole process starts over.
|
|
||||||
});
|
|
||||||
}, 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
Miner.prototype.__defineGetter__('hashes', function() {
|
|
||||||
return new bn(this.iterations).mul(utils.U32).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.chain.height + 1,
|
|
||||||
best: utils.revHex(this.chain.tip.hash)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Miner.prototype.findNonce = function findNonce() {
|
|
||||||
var data = this.block.abbr();
|
|
||||||
var now;
|
var now;
|
||||||
|
|
||||||
// Track how long we've been at it.
|
// Track how long we've been at it.
|
||||||
this._begin = utils.now();
|
this.begin = utils.now();
|
||||||
|
|
||||||
assert(this.block.ts > this.chain.tip.ts);
|
assert(block.ts > tip.ts);
|
||||||
|
|
||||||
// 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 (block.nonce <= 0xffffffff) {
|
||||||
// Hash and test against the next target
|
// Hash and test against the next target
|
||||||
if (rcmp(this.dsha256(data), this.block.target) < 0)
|
if (rcmp(this.dsha256(data), target) < 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Increment the nonce to get a different hash
|
// Increment the nonce to get a different hash
|
||||||
this.block.nonce++;
|
block.nonce++;
|
||||||
|
|
||||||
// Update the raw buffer (faster than
|
// Update the raw buffer (faster than
|
||||||
// constantly serializing the block)
|
// constantly serializing the block)
|
||||||
utils.writeU32(data, this.block.nonce, 76);
|
utils.writeU32(data, block.nonce, 76);
|
||||||
|
|
||||||
// Send progress report every so often
|
// Send progress report every so often
|
||||||
if (this.block.nonce % 100000 === 0)
|
if (block.nonce % 100000 === 0)
|
||||||
this.sendStatus();
|
this.sendStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,16 +410,16 @@ Miner.prototype.findNonce = function findNonce() {
|
|||||||
// performance because we do not have to
|
// performance because we do not have to
|
||||||
// recalculate the merkle root.
|
// recalculate the merkle root.
|
||||||
now = utils.now();
|
now = utils.now();
|
||||||
if (now > this.block.ts && now > this.chain.tip.ts) {
|
if (now > block.ts && now > tip.ts) {
|
||||||
this.block.ts = now;
|
block.ts = now;
|
||||||
// Overflow the nonce
|
// Overflow the nonce
|
||||||
this.block.nonce = 0;
|
block.nonce = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overflow the nonce and increment the extraNonce.
|
// Overflow the nonce and increment the extraNonce.
|
||||||
this.block.nonce = 0;
|
block.nonce = 0;
|
||||||
this.block.extraNonce.iaddn(1);
|
block.extraNonce.iaddn(1);
|
||||||
|
|
||||||
// We incremented the extraNonce, need to update coinbase.
|
// We incremented the extraNonce, need to update coinbase.
|
||||||
this.updateCoinbase();
|
this.updateCoinbase();
|
||||||
@ -432,6 +430,61 @@ Miner.prototype.findNonce = function findNonce() {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.__defineGetter__('hashes', function() {
|
||||||
|
return new bn(this.iterations)
|
||||||
|
.mul(utils.U32)
|
||||||
|
.addn(this.block.nonce);
|
||||||
|
});
|
||||||
|
|
||||||
|
MinerBlock.prototype.__defineGetter__('rate', function() {
|
||||||
|
if (!this.block.nonce)
|
||||||
|
return 0;
|
||||||
|
// Calculate our terrible hashrate
|
||||||
|
return (this.block.nonce / (utils.now() - this.begin)) * 2 | 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
MinerBlock.prototype.sendStatus = function sendStatus() {
|
||||||
|
this.emit('status', {
|
||||||
|
block: this.block,
|
||||||
|
target: this.block.bits,
|
||||||
|
hashes: this.hashes.toString(10),
|
||||||
|
hashrate: this.rate,
|
||||||
|
height: this.height,
|
||||||
|
best: utils.revHex(this.tip.hash)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.mine = function mine(callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.timeout = setTimeout(function() {
|
||||||
|
// Try to find a block: do one iteration of extraNonce
|
||||||
|
if (!self.findNonce())
|
||||||
|
return self.mine(callback);
|
||||||
|
|
||||||
|
return callback(null, self.block);
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.mineSync = function mineSync() {
|
||||||
|
while (!this.findNonce());
|
||||||
|
return this.block;
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.mineAsync = function mine(callback) {
|
||||||
|
return this.mine(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
MinerBlock.prototype.destroy = function destroy() {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = null;
|
||||||
|
this.block = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helpers
|
||||||
|
*/
|
||||||
|
|
||||||
function rcmp(a, b) {
|
function rcmp(a, b) {
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
@ -451,4 +504,6 @@ function rcmp(a, b) {
|
|||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = Miner;
|
exports = Miner;
|
||||||
|
exports.minerblock = MinerBlock;
|
||||||
|
module.exports = exports;
|
||||||
|
|||||||
@ -81,17 +81,21 @@ workers.call = function call(method, args, callback) {
|
|||||||
child = workers.alloc(id);
|
child = workers.alloc(id);
|
||||||
|
|
||||||
function listener(err, result) {
|
function listener(err, result) {
|
||||||
clearTimeout(timeout);
|
if (timeout) {
|
||||||
timeout = null;
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
callback(err, result);
|
callback(err, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
child.once(event, listener);
|
child.once(event, listener);
|
||||||
|
|
||||||
timeout = setTimeout(function() {
|
if (method !== 'mine') {
|
||||||
child.removeListener(event, listener);
|
timeout = setTimeout(function() {
|
||||||
return callback(new Error('Worker timed out.'));
|
child.removeListener(event, listener);
|
||||||
}, workers.TIMEOUT);
|
return callback(new Error('Worker timed out.'));
|
||||||
|
}, workers.TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
child.stdin.write(createPacket(id, method, args));
|
child.stdin.write(createPacket(id, method, args));
|
||||||
};
|
};
|
||||||
@ -115,13 +119,25 @@ bcoin.tx.prototype.verifyAsync = function verifyAsync(index, force, flags, callb
|
|||||||
return workers.call('verify', [this, index, force, flags], callback);
|
return workers.call('verify', [this, index, force, flags], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bcoin.miner.minerblock.prototype.mineAsync = function mineAsync(callback) {
|
||||||
|
var attempt = {
|
||||||
|
tip: this.tip.toRaw(),
|
||||||
|
version: this.block.version,
|
||||||
|
target: this.block.bits,
|
||||||
|
address: this.options.address,
|
||||||
|
coinbaseFlags: this.options.coinbaseFlags,
|
||||||
|
segwit: this.options.segwit
|
||||||
|
};
|
||||||
|
return workers.call('mine', [attempt], callback);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Child
|
* Child
|
||||||
*/
|
*/
|
||||||
|
|
||||||
workers.listen = function listen() {
|
workers.listen = function listen() {
|
||||||
bcoin.debug = function debug() {
|
bcoin.debug = function debug() {
|
||||||
process.stderr.write('Worker ' + process.env.BCOIN_WORKER_ID + ':');
|
process.stderr.write('Worker ' + process.env.BCOIN_WORKER_ID + ': ');
|
||||||
return console.error.apply(console.error, arguments);
|
return console.error.apply(console.error, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -155,6 +171,28 @@ workers.verify = function verify(tx, index, force, flags) {
|
|||||||
return tx.verify(index, force, flags);
|
return tx.verify(index, force, flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
workers.mine = function mine(attempt) {
|
||||||
|
attempt = new bcoin.miner.minerblock({
|
||||||
|
tip: bcoin.chainblock.fromRaw(null, attempt.tip),
|
||||||
|
version: attempt.version,
|
||||||
|
target: attempt.target,
|
||||||
|
address: attempt.address,
|
||||||
|
coinbaseFlags: attempt.coinbaseFlags,
|
||||||
|
segwit: attempt.segwit,
|
||||||
|
dsha256: utils.dsha256
|
||||||
|
});
|
||||||
|
attempt.on('status', function(stat) {
|
||||||
|
utils.debug(
|
||||||
|
'hashrate=%dkhs hashes=%d target=%d height=%d best=%s',
|
||||||
|
stat.hashrate / 1000 | 0,
|
||||||
|
stat.hashes,
|
||||||
|
stat.target,
|
||||||
|
stat.height,
|
||||||
|
stat.best);
|
||||||
|
});
|
||||||
|
return attempt.mineSync();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user