From 160f895a80660e4e3904a2624e4110960d051902 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 8 Aug 2016 21:16:40 +0000 Subject: [PATCH 1/2] Bugfix: Use pre-BIP141 sigops until segwit activates --- src/rpc/mining.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 92ca4bab6..2479e5d59 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -546,6 +546,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) UpdateTime(pblock, consensusParams, pindexPrev); pblock->nNonce = 0; + // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration + const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); @@ -574,7 +577,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) int index_in_template = i - 1; entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); - entry.push_back(Pair("sigops", pblocktemplate->vTxSigOpsCost[index_in_template])); + int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template]; + if (fPreSegWit) { + assert(nTxSigOps % WITNESS_SCALE_FACTOR == 0); + nTxSigOps /= WITNESS_SCALE_FACTOR; + } + entry.push_back(Pair("sigops", nTxSigOps)); entry.push_back(Pair("weight", GetTransactionWeight(tx))); transactions.push_back(entry); @@ -657,7 +665,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); - result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS_COST)); + int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST; + if (fPreSegWit) { + assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0); + nSigOpLimit /= WITNESS_SCALE_FACTOR; + } + result.push_back(Pair("sigoplimit", nSigOpLimit)); result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE)); result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT)); result.push_back(Pair("curtime", pblock->GetBlockTime())); From 239cbd2e5c2a36843b45b356e9aea6e8d35f0968 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 8 Aug 2016 21:58:36 +0000 Subject: [PATCH 2/2] qa/rpc-tests/segwit: Test GBT sigops before and after activation --- qa/rpc-tests/segwit.py | 50 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py index d4c9a8afe..097e119f3 100755 --- a/qa/rpc-tests/segwit.py +++ b/qa/rpc-tests/segwit.py @@ -69,6 +69,11 @@ def getutxo(txid): utxo["txid"] = txid return utxo +def find_unspent(node, min_value): + for utxo in node.listunspent(): + if utxo['amount'] >= min_value: + return utxo + class SegWitTest(BitcoinTestFramework): def setup_chain(self): @@ -117,8 +122,21 @@ class SegWitTest(BitcoinTestFramework): sync_blocks(self.nodes) def run_test(self): - self.nodes[0].generate(160) #block 160 + self.nodes[0].generate(161) #block 161 + print("Verify sigops are counted in GBT with pre-BIP141 rules before the fork") + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) + tmpl = self.nodes[0].getblocktemplate({}) + assert(tmpl['sigoplimit'] == 20000) + assert(tmpl['transactions'][0]['hash'] == txid) + assert(tmpl['transactions'][0]['sigops'] == 2) + tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']}) + assert(tmpl['sigoplimit'] == 20000) + assert(tmpl['transactions'][0]['hash'] == txid) + assert(tmpl['transactions'][0]['sigops'] == 2) + self.nodes[0].generate(1) #block 162 + + balance_presetup = self.nodes[0].getbalance() self.pubkey = [] p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness @@ -137,18 +155,18 @@ class SegWitTest(BitcoinTestFramework): for i in range(5): for n in range(3): for v in range(2): - wit_ids[n][v].append(send_to_witness(v, self.nodes[0], self.nodes[0].listunspent()[0], self.pubkey[n], False, Decimal("49.999"))) - p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], self.nodes[0].listunspent()[0], self.pubkey[n], True, Decimal("49.999"))) + wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999"))) + p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999"))) - self.nodes[0].generate(1) #block 161 + self.nodes[0].generate(1) #block 163 sync_blocks(self.nodes) # Make sure all nodes recognize the transactions as theirs - assert_equal(self.nodes[0].getbalance(), 60*50 - 60*50 + 20*Decimal("49.999") + 50) + assert_equal(self.nodes[0].getbalance(), balance_presetup - 60*50 + 20*Decimal("49.999") + 50) assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999")) assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999")) - self.nodes[0].generate(262) #block 423 + self.nodes[0].generate(260) #block 423 sync_blocks(self.nodes) print("Verify default node can't accept any witness format txs before fork") @@ -205,5 +223,25 @@ class SegWitTest(BitcoinTestFramework): self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435 + print("Verify sigops are counted in GBT with BIP141 rules after the fork") + txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) + tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']}) + assert(tmpl['sigoplimit'] == 80000) + assert(tmpl['transactions'][0]['txid'] == txid) + assert(tmpl['transactions'][0]['sigops'] == 8) + + print("Verify non-segwit miners get a valid GBT response after the fork") + send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.998")) + try: + tmpl = self.nodes[0].getblocktemplate({}) + assert(len(tmpl['transactions']) == 1) # Doesn't include witness tx + assert(tmpl['sigoplimit'] == 20000) + assert(tmpl['transactions'][0]['hash'] == txid) + assert(tmpl['transactions'][0]['sigops'] == 2) + assert(('!segwit' in tmpl['rules']) or ('segwit' not in tmpl['rules'])) + except JSONRPCException: + # This is an acceptable outcome + pass + if __name__ == '__main__': SegWitTest().main()