Skip to content
Permalink
Browse files

chain/block/mining: implement a more foolproof pow (WIP).

  • Loading branch information
chjj committed Jul 7, 2019
1 parent a62f7ee commit 5a34dd6633cda3b5e5066e0602a142a08f0a80ec
@@ -30,7 +30,6 @@ const ZERO = new BN(0);
* @property {Hash} merkleRoot
* @property {Hash} witnessRoot
* @property {Hash} treeRoot
* @property {Hash} filterRoot
* @property {Hash} reservedRoot
* @property {Number} time
* @property {Number} bits
@@ -55,11 +54,12 @@ class ChainEntry extends bio.Struct {
this.merkleRoot = consensus.ZERO_HASH;
this.witnessRoot = consensus.ZERO_HASH;
this.treeRoot = consensus.ZERO_HASH;
this.filterRoot = consensus.ZERO_HASH;
this.reservedRoot = consensus.ZERO_HASH;
this.time = 0;
this.bits = 0;
this.nonce = consensus.ZERO_NONCE;
this.nonce = 0;
this.extraNonce = consensus.ZERO_NONCE;
this.mask = consensus.ZERO_HASH;
this.height = 0;
this.chainwork = ZERO;

@@ -81,11 +81,12 @@ class ChainEntry extends bio.Struct {
assert(Buffer.isBuffer(options.merkleRoot));
assert(Buffer.isBuffer(options.witnessRoot));
assert(Buffer.isBuffer(options.treeRoot));
assert(Buffer.isBuffer(options.filterRoot));
assert(Buffer.isBuffer(options.reservedRoot));
assert(util.isU64(options.time));
assert((options.bits >>> 0) === options.bits);
assert(Buffer.isBuffer(options.nonce));
assert((options.nonce >>> 0) === options.nonce);
assert(Buffer.isBuffer(options.extraNonce));
assert(Buffer.isBuffer(options.mask));
assert((options.height >>> 0) === options.height);
assert(!options.chainwork || BN.isBN(options.chainwork));

@@ -95,11 +96,12 @@ class ChainEntry extends bio.Struct {
this.merkleRoot = options.merkleRoot;
this.witnessRoot = options.witnessRoot;
this.treeRoot = options.treeRoot;
this.filterRoot = options.filterRoot;
this.reservedRoot = options.reservedRoot;
this.time = options.time;
this.bits = options.bits;
this.nonce = options.nonce;
this.extraNonce = options.extraNonce;
this.mask = options.mask;

this.height = options.height;
this.chainwork = options.chainwork || ZERO;
@@ -179,11 +181,12 @@ class ChainEntry extends bio.Struct {
this.merkleRoot = block.merkleRoot;
this.witnessRoot = block.witnessRoot;
this.treeRoot = block.treeRoot;
this.filterRoot = block.filterRoot;
this.reservedRoot = block.reservedRoot;
this.time = block.time;
this.bits = block.bits;
this.nonce = block.nonce;
this.extraNonce = block.extraNonce;
this.mask = block.mask;
this.height = prev ? prev.height + 1 : 0;
this.chainwork = this.getChainwork(prev);
return this;
@@ -211,11 +214,12 @@ class ChainEntry extends bio.Struct {
bw.writeHash(this.merkleRoot);
bw.writeHash(this.witnessRoot);
bw.writeHash(this.treeRoot);
bw.writeHash(this.filterRoot);
bw.writeHash(this.reservedRoot);
bw.writeU64(this.time);
bw.writeU32(this.bits);
bw.writeBytes(this.nonce);
bw.writeU32(this.nonce);
bw.writeBytes(this.extraNonce);
bw.writeBytes(this.mask);
bw.writeBytes(this.chainwork.toArrayLike(Buffer, 'be', 32));
return bw;
}
@@ -234,11 +238,12 @@ class ChainEntry extends bio.Struct {
this.merkleRoot = br.readHash();
this.witnessRoot = br.readHash();
this.treeRoot = br.readHash();
this.filterRoot = br.readHash();
this.reservedRoot = br.readHash();
this.time = br.readU64();
this.bits = br.readU32();
this.nonce = br.readBytes(consensus.NONCE_SIZE);
this.nonce = br.readU32();
this.extraNonce = br.readBytes(consensus.NONCE_SIZE);
this.mask = br.readBytes(32);
this.chainwork = new BN(br.readBytes(32), 'be');
return this;
}
@@ -258,11 +263,12 @@ class ChainEntry extends bio.Struct {
merkleRoot: this.merkleRoot.toString('hex'),
witnessRoot: this.witnessRoot.toString('hex'),
treeRoot: this.treeRoot.toString('hex'),
filterRoot: this.filterRoot.toString('hex'),
reservedRoot: this.reservedRoot.toString('hex'),
time: this.time,
bits: this.bits,
nonce: this.nonce.toString('hex'),
nonce: this.nonce,
extraNonce: this.extraNonce.toString('hex'),
mask: this.mask.toString('hex'),
chainwork: this.chainwork.toString('hex', 64)
};
}
@@ -279,6 +285,7 @@ class ChainEntry extends bio.Struct {
assert((json.version >>> 0) === json.version);
assert(util.isU64(json.time));
assert((json.bits >>> 0) === json.bits);
assert((json.nonce >>> 0) === json.nonce);

const work = util.parseHex(json.chainwork, 32);

@@ -289,11 +296,12 @@ class ChainEntry extends bio.Struct {
this.merkleRoot = util.parseHex(json.merkleRoot, 32);
this.witnessRoot = util.parseHex(json.witnessRoot, 32);
this.treeRoot = util.parseHex(json.treeRoot, 32);
this.filterRoot = util.parseHex(json.filterRoot, 32);
this.reservedRoot = util.parseHex(json.reservedRoot, 32);
this.time = json.time;
this.bits = json.bits;
this.nonce = util.parseHex(json.nonce, 20);
this.nonce = json.nonce;
this.extraNonce = util.parseHex(json.extraNonce, consensus.NONCE_SIZE);
this.mask = util.parseHex(json.mask, 32);
this.chainwork = new BN(work, 'be');

return this;
@@ -7,6 +7,7 @@
'use strict';

const assert = require('bsert');
const bio = require('bufio');
const EventEmitter = require('events');
const {Lock} = require('bmutex');
const util = require('../utils/util');
@@ -282,7 +283,7 @@ class CPUMiner extends EventEmitter {
const target = job.attempt.target;
const interval = CPUMiner.INTERVAL;

let nonce = hdr.slice(consensus.NONCE_POS);
let nonce = 0;
let solved = false;

for (;;) {
@@ -312,7 +313,7 @@ class CPUMiner extends EventEmitter {
const target = job.attempt.target;
const interval = CPUMiner.INTERVAL;

let nonce = hdr.slice(consensus.NONCE_POS);
let nonce = 0;
let solved = false;

for (;;) {
@@ -435,8 +436,8 @@ class CPUJob {
this.destroyed = false;
this.committed = false;
this.start = util.now();
this.nonce1 = 0;
this.nonce2 = 0;
this.extraNonce = Buffer.alloc(consensus.NONCE_SIZE, 0x00);
this.mask = consensus.ZERO_HASH;
this.refresh();
}

@@ -447,12 +448,10 @@ class CPUJob {

getHeader() {
const attempt = this.attempt;
const n1 = this.nonce1;
const n2 = this.nonce2;
const time = attempt.time;
const root = attempt.getRoot(n1, n2);
const nonce = consensus.ZERO_NONCE;
const hdr = attempt.getHeader(root, time, nonce);
const extraNonce = this.extraNonce;
const mask = this.mask;
const hdr = attempt.getHeader(0, time, extraNonce, mask);
return hdr;
}

@@ -464,14 +463,14 @@ class CPUJob {

commit(nonce) {
const attempt = this.attempt;
const n1 = this.nonce1;
const n2 = this.nonce2;
const time = attempt.time;
const extraNonce = this.extraNonce;
const mask = this.mask;

assert(!this.committed, 'Job already committed.');
this.committed = true;

const proof = attempt.getProof(n1, n2, time, nonce);
const proof = attempt.getProof(nonce, time, extraNonce, mask);

return attempt.commit(proof);
}
@@ -507,10 +506,11 @@ class CPUJob {
*/

updateNonce() {
this.nonce2 += 1;
if (this.nonce2 === 0x100000000) {
this.nonce2 = 0;
this.nonce1 += 1;
for (let i = 0; i < consensus.NONCE_SIZE; i++) {
this.extraNonce[i] += 1;

if (this.extraNonce[i] !== 0)
break;
}
}

@@ -530,8 +530,10 @@ class CPUJob {
*/

getHashes(nonce) {
const extra = this.nonce1 * 0x100000000 + this.nonce2;
return extra * 0xffffffff + nonce.readUInt32LE(0, true);
const nonce1 = bio.readU32(this.extraNonce, 0);
const nonce2 = bio.readU32(this.extraNonce, 4);
const extra = nonce2 * 0x100000000 + nonce1;
return extra * 0xffffffff + nonce;
}

/**
@@ -6,38 +6,51 @@

'use strict';

const KMAC256 = require('bcrypto/lib/kmac256');
const BLAKE2b256 = require('bcrypto/lib/blake2b256');
const consensus = require('../protocol/consensus');
const bio = require('bufio');
const SHA3 = require('bcrypto/lib/sha3');
const BLAKE2b = require('bcrypto/lib/blake2b');

/**
* Hash until the nonce overflows.
* @alias module:mining.mine
* @param {Buffer} hdr
* @param {Buffer} raw
* @param {Buffer} target
* @param {Number} rounds
* @returns {Buffer|null}
*/

function mine(hdr, target, rounds) {
const data = hdr.slice(0, consensus.NONCE_POS);
const nonce = hdr.slice(consensus.NONCE_POS);
const prevBlock = hdr.slice(32, 64);
const treeRoot = hdr.slice(64, 96);
const preHead = Buffer.from(hdr.slice(0, 128));
const maskHash = hdr.slice(96, 128);
const subHead = Buffer.from(hdr.slice(128, 256));

const subHash = BLAKE2b.digest(subHead);
const commitHash = BLAKE2b.multi(subHash, maskHash);

commitHash.copy(preHead, 96);

const pad32 = Buffer.alloc(32);
const pad8 = pad32.slice(0, 8);

for (let i = 0; i < 32; i++)
pad32[i] = prevBlock[i] ^ treeRoot[i];

let nonce = 0;

// The heart and soul of the miner: match the target.
for (let i = 0; i < rounds; i++) {
const key = KMAC256.digest(data, nonce);
const hash = BLAKE2b256.digest(data, key);
const left = BLAKE2b.digest(preHead, 64);
const right = SHA3.multi(preHead, pad8);
const hash = BLAKE2b.multi(left, pad32, right);

if (hash.compare(target) <= 0)
return [nonce, true];

for (let j = 0; j < consensus.NONCE_SIZE; j++) {
if (nonce[j] !== 0xff) {
nonce[j] += 1;
break;
}
nonce[j] = 0;
}
nonce += 1;

bio.writeU32(preHead, nonce, 0);
}

return [nonce, false];

0 comments on commit 5a34dd6

Please sign in to comment.
You can’t perform that action at this time.