segwit mining.

This commit is contained in:
Christopher Jeffrey 2016-03-30 23:39:06 -07:00
parent b1d53adb6a
commit 1dc15922f6
4 changed files with 143 additions and 90 deletions

View File

@ -109,7 +109,7 @@ Block.prototype.getSigops = function getSigops(scriptHash, accurate) {
return total; return total;
}; };
Block.prototype.getMerkleRoot = function getMerkleRoot() { Block.prototype.getMerkleRoot = function getMerkleRoot(enc) {
var leaves = []; var leaves = [];
var i, root; var i, root;
@ -121,10 +121,12 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() {
if (!root) if (!root)
return; 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 leaves = [];
var i, witnessNonce, witnessRoot, commitmentHash; var i, witnessNonce, witnessRoot, commitmentHash;
@ -143,7 +145,9 @@ Block.prototype.getCommitmentHash = function getCommitmentHash() {
commitmentHash = utils.dsha256(Buffer.concat([witnessRoot, witnessNonce])); commitmentHash = utils.dsha256(Buffer.concat([witnessRoot, witnessNonce]));
return utils.toHex(commitmentHash); return enc === 'hex'
? utils.toHex(commitmentHash)
: commitmentHash;
}; };
Block.prototype.__defineGetter__('commitmentHash', function() { Block.prototype.__defineGetter__('commitmentHash', function() {
@ -215,7 +219,7 @@ Block.prototype._verify = function _verify(ret) {
} }
// Check merkle root // Check merkle root
if (this.getMerkleRoot() !== this.merkleRoot) { if (this.merkleRoot !== this.getMerkleRoot('hex')) {
ret.reason = 'bad-txnmrkleroot'; ret.reason = 'bad-txnmrkleroot';
ret.score = 100; ret.score = 100;
return false; return false;

View File

@ -566,7 +566,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
} }
if (block.version >= 5 && segwit) { if (block.version >= 5 && segwit) {
if (block.commitmentHash !== block.getCommitmentHash()) { if (block.commitmentHash !== block.getCommitmentHash('hex')) {
return done(new VerifyError(block, return done(new VerifyError(block,
'invalid', 'invalid',
'bad-blk-wit-length', 'bad-blk-wit-length',
@ -1571,6 +1571,7 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) {
var unlock = this._lock(getLocator, [start, callback], force); var unlock = this._lock(getLocator, [start, callback], force);
if (!unlock) if (!unlock)
return; return;
callback = utils.wrap(callback, unlock); callback = utils.wrap(callback, unlock);
if (start) { 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 self = this;
var unlock; var unlock;
@ -1965,7 +1966,7 @@ Chain.prototype.isSegwitActive = function isSegwitActive(callback) {
if (!this.tip) if (!this.tip)
return utils.asyncify(callback)(null, false); return utils.asyncify(callback)(null, false);
// unlock = this._lock(isSegwitActive, [callback]); // unlock = this._lock(isSegwitActive, [callback], force);
// if (!unlock) // if (!unlock)
// return; // return;
// callback = utils.wrap(callback, unlock); // 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 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) { function check(err, ts) {
if (err) if (err)
return callback(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 self = this;
// var unlock = this._lock(checkLocks, [tx, flags, entry, callback], force); // var unlock = this._lock(checkLocks, [tx, flags, entry, callback], force);

View File

@ -28,6 +28,9 @@ function Miner(node, options) {
this.options = options; this.options = options;
this.address = this.options.address; this.address = this.options.address;
this.coinbaseFlags = this.options.coinbaseFlags || 'mined by bcoin'; 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.dsha256 = this.options.dsha256 || utils.dsha256;
this.node = node; this.node = node;
@ -127,7 +130,7 @@ Miner.prototype.start = function start() {
if (err) if (err)
return next(err); return next(err);
self.mempool.fillCoins(tx, function(err) { self.node.fillCoins(tx, function(err) {
if (err) if (err)
return next(err); return next(err);
@ -165,6 +168,9 @@ Miner.prototype.addTX = function addTX(tx) {
if (this.block._txMap[tx.hash('hex')]) if (this.block._txMap[tx.hash('hex')])
return false; return false;
if (!this.block.witness && tx.hasWitness())
return false;
// Add the tx to our block // Add the tx to our block
this.block.txs.push(tx); this.block.txs.push(tx);
this.block._txMap[tx.hash('hex')] = true; this.block._txMap[tx.hash('hex')] = true;
@ -185,8 +191,6 @@ Miner.prototype.createBlock = function createBlock(callback) {
var self = this; var self = this;
var ts, target, coinbase, headers, block; var ts, target, coinbase, headers, block;
ts = Math.max(utils.now(), this.last.ts + 1);
// Find target // Find target
this.last.ensureAncestors(function(err) { this.last.ensureAncestors(function(err) {
if (err) { if (err) {
@ -194,71 +198,111 @@ Miner.prototype.createBlock = function createBlock(callback) {
return callback(err); 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 ts = Math.max(utils.now(), this.last.ts + 1);
coinbase = bcoin.mtx();
coinbase.addInput({ target = self.chain.getTarget(self.last, ts);
prevout: {
hash: utils.toHex(constants.zeroHash), // Create a coinbase
index: 0xffffffff coinbase = bcoin.mtx();
},
script: new bcoin.script([ coinbase.addInput({
// Height (required in v2+ blocks) prevout: {
bcoin.script.array(self.last.height + 1), hash: utils.toHex(constants.zeroHash),
// extraNonce - incremented when index: 0xffffffff
// the nonce overflows. },
new Buffer([0]), coin: null,
// Add a nonce to ensure we don't script: new bcoin.script([
// collide with a previous coinbase // Height (required in v2+ blocks)
// of ours. This isn't really bcoin.script.array(self.last.height + 1),
// necessary nowdays due to bip34 // extraNonce - incremented when
// (used above). // the nonce overflows.
utils.nonce().toBuffer(), bcoin.script.array(0),
// Let the world know this little // Add a nonce to ensure we don't
// miner succeeded. // collide with a previous coinbase
new Buffer(self.coinbaseFlags || 'mined by bcoin', 'ascii') // of ours. This isn't really
]), // necessary nowdays due to bip34
witness: new bcoin.script.witness([]), // (used above).
sequence: 0xffffffff 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) { Miner.prototype.updateCoinbase = function updateCoinbase(block) {
var coinbase = block.txs[0]; var coinbase = block.txs[0];
var reward = bcoin.block.reward(this.last.height + 1); var reward = bcoin.block.reward(this.last.height + 1);
@ -280,37 +324,29 @@ Miner.prototype.updateMerkle = function updateMerkle(block) {
if (!block) if (!block)
block = this.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.ts = utils.now();
block.merkleRoot = block.getMerkleRoot(); block.merkleRoot = block.getMerkleRoot('hex');
}; };
Miner.prototype.iterate = function iterate() { Miner.prototype.iterate = function iterate() {
var self = this; var self = this;
this.timeout = setTimeout(function() { this.timeout = setTimeout(function() {
var hash, res;
// Try to find a block: do one iteration of extraNonce // Try to find a block: do one iteration of extraNonce
if (!self.findNonce()) if (!self.findNonce())
return self.iterate(); 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 // Add our block to the chain
self.chain.add(self.block, self.pool.peers.load, function(err, total) { self.chain.add(self.block, function(err) {
if (err) if (err) {
if (err.type === 'VerifyError')
utils.debug('Miner: %s could not be added to chain.', block.rhash);
return self.emit('error', err); 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 // Emit our newly found block

View File

@ -1700,6 +1700,13 @@ Script.prototype.isCommitment = function isCommitment() {
&& utils.readU32BE(this.code[1], 0) === 0xaa21a9ed; && 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() { Script.prototype.getCommitmentHash = function getCommitmentHash() {
if (!this.isCommitment()) if (!this.isCommitment())
return; return;