diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 05c1dbda..36178766 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -109,7 +109,7 @@ Block.prototype.getSigops = function getSigops(scriptHash, accurate) { return total; }; -Block.prototype.getMerkleRoot = function getMerkleRoot() { +Block.prototype.getMerkleRoot = function getMerkleRoot(enc) { var leaves = []; var i, root; @@ -121,10 +121,12 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() { if (!root) return; - return utils.toHex(root); + return enc === 'hex' + ? utils.toHex(root) + : root; }; -Block.prototype.getCommitmentHash = function getCommitmentHash() { +Block.prototype.getCommitmentHash = function getCommitmentHash(enc) { var leaves = []; var i, witnessNonce, witnessRoot, commitmentHash; @@ -143,7 +145,9 @@ Block.prototype.getCommitmentHash = function getCommitmentHash() { commitmentHash = utils.dsha256(Buffer.concat([witnessRoot, witnessNonce])); - return utils.toHex(commitmentHash); + return enc === 'hex' + ? utils.toHex(commitmentHash) + : commitmentHash; }; Block.prototype.__defineGetter__('commitmentHash', function() { @@ -215,7 +219,7 @@ Block.prototype._verify = function _verify(ret) { } // Check merkle root - if (this.getMerkleRoot() !== this.merkleRoot) { + if (this.merkleRoot !== this.getMerkleRoot('hex')) { ret.reason = 'bad-txnmrkleroot'; ret.score = 100; return false; diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 81a9a1cd..c9d925ff 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -566,7 +566,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) { } if (block.version >= 5 && segwit) { - if (block.commitmentHash !== block.getCommitmentHash()) { + if (block.commitmentHash !== block.getCommitmentHash('hex')) { return done(new VerifyError(block, 'invalid', 'bad-blk-wit-length', @@ -1571,6 +1571,7 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) { var unlock = this._lock(getLocator, [start, callback], force); if (!unlock) return; + callback = utils.wrap(callback, unlock); if (start) { @@ -1950,7 +1951,7 @@ Chain.prototype.computeBlockVersion = function computeBlockVersion(prev, callbac }); }; -Chain.prototype.isSegwitActive = function isSegwitActive(callback) { +Chain.prototype.isSegwitActive = function isSegwitActive(callback, force) { var self = this; var unlock; @@ -1965,7 +1966,7 @@ Chain.prototype.isSegwitActive = function isSegwitActive(callback) { if (!this.tip) return utils.asyncify(callback)(null, false); - // unlock = this._lock(isSegwitActive, [callback]); + // unlock = this._lock(isSegwitActive, [callback], force); // if (!unlock) // return; // callback = utils.wrap(callback, unlock); @@ -2015,9 +2016,14 @@ Chain.prototype.isSegwitActive = function isSegwitActive(callback) { }); }; -Chain.prototype.checkFinal = function checkFinal(prev, tx, flags, callback) { +Chain.prototype.checkFinal = function checkFinal(prev, tx, flags, callback, force) { var height = prev.height + 1; + // var unlock = this._lock(checkFinal, [prev, tx, flags, callback], force); + // if (!unlock) + // return; + // callback = utils.wrap(callback, unlock); + function check(err, ts) { if (err) return callback(err); @@ -2100,7 +2106,7 @@ Chain.prototype.evalLocks = function evalLocks(entry, minHeight, minTime, callba }); }; -Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback) { +Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback, force) { var self = this; // var unlock = this._lock(checkLocks, [tx, flags, entry, callback], force); diff --git a/lib/bcoin/miner.js b/lib/bcoin/miner.js index ffa1ea5d..70866b92 100644 --- a/lib/bcoin/miner.js +++ b/lib/bcoin/miner.js @@ -28,6 +28,9 @@ function Miner(node, options) { this.options = 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.node = node; @@ -127,7 +130,7 @@ Miner.prototype.start = function start() { if (err) return next(err); - self.mempool.fillCoins(tx, function(err) { + self.node.fillCoins(tx, function(err) { if (err) return next(err); @@ -165,6 +168,9 @@ Miner.prototype.addTX = function addTX(tx) { if (this.block._txMap[tx.hash('hex')]) return false; + if (!this.block.witness && tx.hasWitness()) + return false; + // Add the tx to our block this.block.txs.push(tx); this.block._txMap[tx.hash('hex')] = true; @@ -185,8 +191,6 @@ Miner.prototype.createBlock = function createBlock(callback) { var self = this; var ts, target, coinbase, headers, block; - ts = Math.max(utils.now(), this.last.ts + 1); - // Find target this.last.ensureAncestors(function(err) { if (err) { @@ -194,71 +198,111 @@ Miner.prototype.createBlock = function createBlock(callback) { return callback(err); } - target = self.chain.getTarget(self.last, ts); + // Calculate version with versionbits + self.chain.computeBlockVersion(self.last, function(err, version) { + if (err) { + self.last.free(); + return callback(err); + } - // Create a coinbase - coinbase = bcoin.mtx(); + ts = Math.max(utils.now(), this.last.ts + 1); - coinbase.addInput({ - prevout: { - hash: utils.toHex(constants.zeroHash), - index: 0xffffffff - }, - script: new bcoin.script([ - // Height (required in v2+ blocks) - bcoin.script.array(self.last.height + 1), - // extraNonce - incremented when - // the nonce overflows. - new Buffer([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). - utils.nonce().toBuffer(), - // Let the world know this little - // miner succeeded. - new Buffer(self.coinbaseFlags || 'mined by bcoin', 'ascii') - ]), - witness: new bcoin.script.witness([]), - sequence: 0xffffffff + target = self.chain.getTarget(self.last, ts); + + // 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.last.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.last.hash, + merkleRoot: utils.toHex(constants.zeroHash), + ts: ts, + bits: target, + nonce: 0 + }; + + block = bcoin.block(headers, 'block'); + block._txMap = {}; + + block.txs.push(coinbase); + + block.target = utils.fromCompact(target); + block.extraNonce = new bn(0, 'le'); + + if (self.chain.segwitActive) { + // Set up the witness nonce and + // commitment output for segwit. + block.witness = true; + block.witnessNonce = utils.nonce().toBuffer(); + 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); + + self.last.free(); + + return callback(null, block); }); - - coinbase.addOutput({ - address: self.address, - value: new bn(0) - }); - - // Create our block - headers = { - version: 4, - prevBlock: self.last.hash, - merkleRoot: utils.toHex(constants.zeroHash), - ts: ts, - bits: target, - nonce: 0 - }; - - block = bcoin.block(headers, 'block'); - block._txMap = {}; - - block.txs.push(coinbase); - - block.target = utils.fromCompact(target); - block.extraNonce = new bn(0, 'le'); - - // Update coinbase since our coinbase was added. - self.updateCoinbase(block); - - // Create our merkle root. - self.updateMerkle(block); - - self.last.free(); - - return callback(null, block); }); }; +Miner.prototype.updateCommitment = function updateCommitment(block) { + var coinbase = block.txs[0]; + var hash; + + assert(coinbase); + + if (!block) + block = this.block; + + delete block._txMap[coinbase.hash('hex')]; + + hash = block.getCommitmentHash(); + coinbase.outputs[1].script = bcoin.script.createCommitment(hash); + + block._txMap[coinbase.hash('hex')] = true; +}; + Miner.prototype.updateCoinbase = function updateCoinbase(block) { var coinbase = block.txs[0]; var reward = bcoin.block.reward(this.last.height + 1); @@ -280,37 +324,29 @@ 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 = utils.now(); - block.merkleRoot = block.getMerkleRoot(); + block.merkleRoot = block.getMerkleRoot('hex'); }; Miner.prototype.iterate = function iterate() { var self = this; this.timeout = setTimeout(function() { - var hash, res; - // Try to find a block: do one iteration of extraNonce if (!self.findNonce()) return self.iterate(); - hash = self.block.hash('hex'); - - // Make sure our block is valid - if (!self.block.verify()) { - utils.debug('%s did not verify.', hash); - return self.emit('error', new Error(hash + ' did not verify.')); - } - // Add our block to the chain - self.chain.add(self.block, self.pool.peers.load, function(err, total) { - if (err) + self.chain.add(self.block, function(err) { + if (err) { + if (err.type === 'VerifyError') + utils.debug('Miner: %s could not be added to chain.', block.rhash); return self.emit('error', err); - - if (total === 0) { - utils.debug('%s could not be added to chain.', hash); - return self.emit('error', - new Error(hash + ' could not be added to chain.')); } // Emit our newly found block diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index df0ced60..afb7c2c9 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -1700,6 +1700,13 @@ Script.prototype.isCommitment = function isCommitment() { && utils.readU32BE(this.code[1], 0) === 0xaa21a9ed; }; +Script.prototype.createCommitment = function createCommitment(hash) { + return new Script([ + opcodes.OP_RETURN, + Buffer.concat([new Buffer([0xaa, 0x21, 0xa9, 0xed]), hash]) + ]); +}; + Script.prototype.getCommitmentHash = function getCommitmentHash() { if (!this.isCommitment()) return;