mining: refactor proof handling.

This commit is contained in:
Christopher Jeffrey 2017-03-10 06:59:36 -08:00
parent b453898f6e
commit b0c2b89e79
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
5 changed files with 214 additions and 37 deletions

View File

@ -915,7 +915,7 @@ RPC.prototype._submitWork = co(function* _submitWork(data) {
var header = Headers.fromAbbr(data);
var nonce = header.nonce;
var ts = header.ts;
var job, n1, n2, hash, block, entry;
var job, n1, n2, proof, block, entry;
if (!attempt)
return false;
@ -942,12 +942,12 @@ RPC.prototype._submitWork = co(function* _submitWork(data) {
n1 = job.nonce1;
n2 = job.nonce2;
hash = attempt.hash(n1, n2, ts, nonce);
proof = attempt.getProof(n1, n2, ts, nonce);
if (!consensus.verifyPOW(hash, attempt.bits))
if (!proof.verify(attempt.target))
return false;
block = attempt.commit(n1, n2, ts, nonce);
block = attempt.commit(proof);
try {
entry = yield this.chain.add(block);
@ -983,12 +983,14 @@ RPC.prototype._createWork = co(function* _createWork() {
var n1 = this.nonce1;
var n2 = this.nonce2;
var ts = attempt.ts;
var data, head;
var data, root, head;
data = new Buffer(128);
data.fill(0);
head = attempt.getHeader(n1, n2, ts, 0);
root = attempt.getRoot(n1, n2);
head = attempt.getHeader(root, ts, 0);
head.copy(data, 0);
data[80] = 0x80;

124
lib/mining/common.js Normal file
View File

@ -0,0 +1,124 @@
/*!
* common.js - mining utils
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
/**
* @exports mining/common
*/
var common = exports;
/*
* Constants
*/
var DIFF_TARGET = 0x00000000ffff0000000000000000000000000000000000000000000000000000;
var B192 = 0x1000000000000000000000000000000000000000000000000;
var B128 = 0x100000000000000000000000000000000;
var B64 = 0x10000000000000000;
var B0 = 0x1;
/**
* Swap 32 bit endianness of uint256.
* @param {Buffer} data
* @returns {Buffer}
*/
exports.swap32 = function swap32(data) {
var i, field;
for (i = 0; i < data.length; i += 4) {
field = data.readUInt32LE(i, true);
data.writeUInt32BE(field, i, true);
}
return data;
};
/**
* Swap 32 bit endianness of uint256 (hex).
* @param {String} data
* @returns {String}
*/
exports.hswap32 = function hswap32(hex) {
var data = new Buffer(hex, 'hex');
exports.swap32(data)
return data.toString('hex');
};
/**
* Compare two uint256le's.
* @param {Buffer} a
* @param {Buffer} b
* @returns {Number}
*/
exports.rcmp = function rcmp(a, b) {
var i;
assert(a.length === b.length);
for (i = a.length - 1; i >= 0; i--) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
return 0;
};
/**
* Convert a uint256le to a double.
* @param {Buffer} target
* @returns {Number}
*/
exports.double256 = function double256(target) {
var n = 0;
var hi, lo;
assert(target.length === 32);
hi = target.readUInt32LE(28, true);
lo = target.readUInt32LE(24, true);
n += (hi * 0x100000000 + lo) * B192;
hi = target.readUInt32LE(20, true);
lo = target.readUInt32LE(16, true);
n += (hi * 0x100000000 + lo) * B128;
hi = target.readUInt32LE(12, true);
lo = target.readUInt32LE(8, true);
n += (hi * 0x100000000 + lo) * B64;
hi = target.readUInt32LE(4, true);
lo = target.readUInt32LE(0, true);
n += (hi * 0x100000000 + lo) * B0;
return n;
};
/**
* Calculate mining difficulty
* from little-endian target.
* @param {Buffer} target
* @returns {Number}
*/
exports.getDifficulty = function getDifficulty(target) {
var d = DIFF_TARGET;
var n = exports.double256(target);
if (n === 0)
return d;
if (n > d)
return d;
return Math.floor(d / n);
};

View File

@ -279,7 +279,7 @@ CPUMiner.prototype.notifyEntry = function notifyEntry() {
*/
CPUMiner.prototype.findNonce = function findNonce(job) {
var data = job.getHeader(0);
var data = job.getHeader();
var target = job.attempt.target;
var interval = CPUMiner.INTERVAL;
var min = 0;
@ -309,7 +309,7 @@ CPUMiner.prototype.findNonce = function findNonce(job) {
*/
CPUMiner.prototype.findNonceAsync = co(function* findNonceAsync(job) {
var data = job.getHeader(0);
var data = job.getHeader();
var target = job.attempt.target;
var interval = CPUMiner.INTERVAL;
var min = 0;
@ -439,12 +439,14 @@ function CPUJob(miner, attempt) {
* @returns {Buffer}
*/
CPUJob.prototype.getHeader = function getHeader(nonce) {
CPUJob.prototype.getHeader = function getHeader() {
var attempt = this.attempt;
var n1 = this.nonce1;
var n2 = this.nonce2;
var ts = attempt.ts;
return this.attempt.getHeader(n1, n2, ts, nonce);
var root = attempt.getRoot(n1, n2);
var data = attempt.getHeader(root, ts, 0);
return data;
};
/**
@ -458,11 +460,14 @@ CPUJob.prototype.commit = function commit(nonce) {
var n1 = this.nonce1;
var n2 = this.nonce2;
var ts = attempt.ts;
var proof;
assert(!this.committed, 'Job already committed.');
this.committed = true;
return this.attempt.commit(n1, n2, ts, nonce);
proof = attempt.getProof(n1, n2, ts, nonce);
return attempt.commit(proof);
};
/**

View File

@ -5,6 +5,7 @@
*/
exports.BlockTemplate = require('./template');
exports.common = require('./common');
exports.CPUMiner = require('./cpuminer');
exports.mine = require('./mine');
exports.Miner = require('./miner');

View File

@ -21,6 +21,7 @@ var consensus = require('../protocol/consensus');
var policy = require('../protocol/policy');
var encoding = require('../utils/encoding');
var CoinView = require('../coins/coinview');
var common = require('./common');
var DUMMY = new Buffer(0);
/**
@ -60,7 +61,7 @@ function BlockTemplate(options) {
* @returns {Buffer}
*/
BlockTemplate.prototype.commitmentHash = function commitmentHash() {
BlockTemplate.prototype.getWitnessHash = function getWitnessHash() {
var nonce = encoding.ZERO_HASH;
var leaves = [];
var i, item, root, data;
@ -139,7 +140,7 @@ BlockTemplate.prototype.createCoinbase = function createCoinbase() {
if (this.witness) {
// Commitment output.
commit = new Output();
hash = this.commitmentHash();
hash = this.getWitnessHash();
commit.script.fromCommitment(hash);
cb.outputs.push(commit);
}
@ -220,7 +221,7 @@ BlockTemplate.prototype.refresh = function refresh() {
* @returns {Buffer}
*/
BlockTemplate.prototype.getCoinbase = function getCoinbase(nonce1, nonce2) {
BlockTemplate.prototype.getRawCoinbase = function getRawCoinbase(nonce1, nonce2) {
var size = 0;
var bw;
@ -245,23 +246,21 @@ BlockTemplate.prototype.getCoinbase = function getCoinbase(nonce1, nonce2) {
*/
BlockTemplate.prototype.getRoot = function getRoot(nonce1, nonce2) {
var raw = this.getCoinbase(nonce1, nonce2);
var raw = this.getRawCoinbase(nonce1, nonce2);
var hash = crypto.hash256(raw);
return this.tree.withFirst(hash);
};
/**
* Create raw block header with given parameters.
* @param {Number} nonce1
* @param {Number} nonce2
* @param {Buffer} root
* @param {Number} ts
* @param {Number} nonce
* @returns {Buffer}
*/
BlockTemplate.prototype.getHeader = function getHeader(nonce1, nonce2, ts, nonce) {
BlockTemplate.prototype.getHeader = function getHeader(root, ts, nonce) {
var bw = new StaticWriter(80);
var root = this.getRoot(nonce1, nonce2);
bw.writeU32(this.version);
bw.writeHash(this.prevBlock);
@ -274,17 +273,19 @@ BlockTemplate.prototype.getHeader = function getHeader(nonce1, nonce2, ts, nonce
};
/**
* Calculate block hash with given parameters.
* Calculate proof with given parameters.
* @param {Number} nonce1
* @param {Number} nonce2
* @param {Number} ts
* @param {Number} nonce
* @returns {Buffer}
* @returns {BlockProof}
*/
BlockTemplate.prototype.hash = function hash(nonce1, nonce2, ts, nonce) {
var data = this.getHeader(nonce1, nonce2, ts, nonce);
return crypto.hash256(data);
BlockTemplate.prototype.getProof = function getProof(nonce1, nonce2, ts, nonce) {
var root = this.getRoot(nonce1, nonce2);
var data = this.getHeader(root, ts, nonce);
var hash = crypto.hash256(data);
return new BlockProof(hash, root, nonce1, nonce2, ts, nonce);
};
/**
@ -294,8 +295,8 @@ BlockTemplate.prototype.hash = function hash(nonce1, nonce2, ts, nonce) {
* @returns {TX}
*/
BlockTemplate.prototype.coinbase = function coinbase(nonce1, nonce2) {
var raw = this.getCoinbase(nonce1, nonce2);
BlockTemplate.prototype.getCoinbase = function getCoinbase(nonce1, nonce2) {
var raw = this.getRawCoinbase(nonce1, nonce2);
var tx = TX.fromRaw(raw);
var input;
@ -310,19 +311,19 @@ BlockTemplate.prototype.coinbase = function coinbase(nonce1, nonce2) {
};
/**
* Create block from given parameters.
* @param {Number} nonce1
* @param {Number} nonce2
* @param {Number} ts
* @param {Number} nonce
* Create block from calculated proof.
* @param {BlockProof} proof
* @returns {Block}
*/
BlockTemplate.prototype.commit = function commit(nonce1, nonce2, ts, nonce) {
var tx = this.coinbase(nonce1, nonce2);
var root = this.tree.withFirst(tx.hash());
BlockTemplate.prototype.commit = function commit(proof) {
var root = proof.root;
var n1 = proof.nonce1;
var n2 = proof.nonce2;
var ts = proof.ts;
var nonce = proof.nonce;
var block = new Block();
var i, item;
var i, tx, item;
block.version = this.version;
block.prevBlock = this.prevBlock;
@ -331,6 +332,8 @@ BlockTemplate.prototype.commit = function commit(nonce1, nonce2, ts, nonce) {
block.bits = this.bits;
block.nonce = nonce;
tx = this.getCoinbase(n1, n2);
block.txs.push(tx);
for (i = 0; i < this.items.length; i++) {
@ -348,7 +351,7 @@ BlockTemplate.prototype.commit = function commit(nonce1, nonce2, ts, nonce) {
*/
BlockTemplate.prototype.toCoinbase = function toCoinbase() {
return this.coinbase(0, 0);
return this.getCoinbase(0, 0);
};
/**
@ -358,7 +361,17 @@ BlockTemplate.prototype.toCoinbase = function toCoinbase() {
*/
BlockTemplate.prototype.toBlock = function toBlock() {
return this.commit(0, 0, this.ts, 0);
var proof = this.getProof(0, 0, this.ts, 0);
return this.commit(proof);
};
/**
* Calculate the target difficulty.
* @returns {Number}
*/
BlockTemplate.prototype.getDifficulty = function getDifficulty() {
return common.getDifficulty(this.target);
};
/**
@ -601,6 +614,38 @@ MerkleTree.fromLeaves = function fromLeaves(leaves) {
return new MerkleTree().fromLeaves(leaves);
};
/*
* BlockProof
* @constructor
* @param {Hash} hash
* @param {Hash} root
* @param {Number} nonce1
* @param {Number} nonce2
* @param {Number} ts
* @param {Number} nonce
*/
function BlockProof(hash, root, nonce1, nonce2, ts, nonce) {
this.hash = hash;
this.root = root;
this.nonce1 = nonce1;
this.nonce2 = nonce2;
this.ts = ts;
this.nonce = nonce;
}
BlockProof.prototype.rhash = function rhash() {
return util.revHex(this.hash.toString('hex'));
};
BlockProof.prototype.verify = function verify(target) {
return common.rcmp(this.hash, target) <= 0;
};
BlockProof.prototype.getDifficulty = function getDifficulty() {
return common.getDifficulty(this.hash);
};
/*
* Helpers
*/