From 89cbdac61ef619fe9ccdb64a5ba3a78ccd75c0db Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 15 Mar 2017 08:48:28 -0700 Subject: [PATCH] rpc: more gbt/getwork improvements. --- lib/http/rpc.js | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 7d0a406e..506954f0 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -1120,11 +1120,19 @@ RPC.prototype.getBlockTemplate = co(function* getBlockTemplate(args, help) { // Prefer value if they support it. valueCap = true; break; - case 'coinbase/append': - break; } } + // BIP22 states that we can't have coinbasetxn + // _and_ coinbasevalue in the same template. + // The problem is, many clients _say_ they + // support coinbasetxn when they don't (ckpool). + // To make matters worse, some clients will + // parse an undefined `coinbasevalue` as zero. + // Because of all of this, coinbasetxn is + // disabled for now. + valueCap = true; + if (txnCap && !valueCap) { if (this.miner.addresses.length === 0) { throw new RPCError(errs.MISC_ERROR, @@ -1173,11 +1181,29 @@ RPC.prototype._createTemplate = co(function* _createTemplate(version, coinbase, var dep, deps, json, name, deploy; var state; + // The miner doesn't support + // versionbits. Force them to + // encode our version. + if (version >= 2) + mutable.push('version/force'); + + // Allow the miner to change + // our provided coinbase. + // Note that these are implied + // without `coinbasetxn`. + if (coinbase) { + mutable.push('coinbase'); + mutable.push('coinbase/append'); + mutable.push('generation'); + } + + // Build an index of every transaction. for (i = 0; i < attempt.items.length; i++) { entry = attempt.items[i]; index[entry.hash] = i; } + // Calculate dependencies for each transaction. for (i = 0; i < attempt.items.length; i++) { entry = attempt.items[i]; tx = entry.tx; @@ -1203,9 +1229,7 @@ RPC.prototype._createTemplate = co(function* _createTemplate(version, coinbase, }); } - if (version >= 2) - mutable.push('version/force'); - + // Calculate version based on given rules. for (i = 0; i < this.network.deploys.length; i++) { deploy = this.network.deploys[i]; state = yield this.chain.getState(this.chain.tip, deploy); @@ -1280,9 +1304,15 @@ RPC.prototype._createTemplate = co(function* _createTemplate(version, coinbase, json.weightlimit = consensus.MAX_BLOCK_WEIGHT; } + // The client wants a coinbasetxn + // instead of a coinbasevalue. if (coinbase) { tx = attempt.toCoinbase(); + // Pop off the nonces. + tx.inputs[0].script.code.pop(); + tx.inputs[0].script.compile(); + if (attempt.witness) { // We don't include the commitment // output (see bip145). @@ -2198,6 +2228,11 @@ RPC.prototype.updateWork = co(function* updateWork() { this.bindChain(); if (attempt) { + if (attempt.address.isNull()) { + throw new RPCError(errs.MISC_ERROR, + 'No addresses available for coinbase.'); + } + this.miner.updateTime(attempt); if (++this.nonce2 === 0x100000000) { @@ -2216,6 +2251,11 @@ RPC.prototype.updateWork = co(function* updateWork() { return attempt; } + if (this.miner.addresses.length === 0) { + throw new RPCError(errs.MISC_ERROR, + 'No addresses available for coinbase.'); + } + attempt = yield this.miner.createBlock(); n1 = this.nonce1;