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;
};
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;

View File

@ -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);

View File

@ -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

View File

@ -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;