diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index b44df9d7b..13ddc461f 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -31,6 +31,7 @@ testScripts=( 'walletbackup.py' 'zcjoinsplit.py' 'zcjoinsplitdoublespend.py' + 'getblocktemplate.py' ); testScriptsExt=( 'bipdersig-p2p.py' diff --git a/qa/rpc-tests/getblocktemplate.py b/qa/rpc-tests/getblocktemplate.py new file mode 100755 index 000000000..c9777c0c7 --- /dev/null +++ b/qa/rpc-tests/getblocktemplate.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python2 +# Copyright (c) 2016 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class GetBlockTemplateTest(BitcoinTestFramework): + ''' + Test getblocktemplate. + ''' + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self, split=False): + self.nodes = start_nodes(2, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + self.is_network_split=False + self.sync_all() + + def run_test(self): + node = self.nodes[0] + node.generate(1) # Mine a block to leave initial block download + + # Test 1: Default to coinbasetxn + tmpl = node.getblocktemplate() + assert('coinbasetxn' in tmpl) + assert('coinbasevalue' not in tmpl) + + # Test 2: Get coinbasetxn if requested + tmpl = node.getblocktemplate({'capabilities': ['coinbasetxn']}) + assert('coinbasetxn' in tmpl) + assert('coinbasevalue' not in tmpl) + + # Test 3: coinbasevalue not supported if requested + tmpl = node.getblocktemplate({'capabilities': ['coinbasevalue']}) + assert('coinbasetxn' in tmpl) + assert('coinbasevalue' not in tmpl) + + # Test 4: coinbasevalue not supported if both requested + tmpl = node.getblocktemplate({'capabilities': ['coinbasetxn', 'coinbasevalue']}) + assert('coinbasetxn' in tmpl) + assert('coinbasevalue' not in tmpl) + + # Test 5: General checks + tmpl = node.getblocktemplate() + assert(len(tmpl['noncerange']) == 16) + + # Test 6: coinbasetxn checks + assert('foundersreward' in tmpl['coinbasetxn']) + assert(tmpl['coinbasetxn']['required']) + +if __name__ == '__main__': + GetBlockTemplateTest().main() diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py index aca0cd749..0c9e7e4cc 100755 --- a/qa/rpc-tests/getblocktemplate_proposals.py +++ b/qa/rpc-tests/getblocktemplate_proposals.py @@ -71,9 +71,11 @@ def genmrklroot(leaflist): def template_to_bytes(tmpl, txlist): blkver = pack(' 0) { const Object& oparam = params[0].get_obj(); @@ -529,7 +536,7 @@ Value getblocktemplate(const Array& params, bool fHelp) // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = NULL; - // Store the pindexBest used before CreateNewBlock, to avoid races + // Store the pindexBest used before CreateNewBlockWithKey, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrevNew = chainActive.Tip(); nStart = GetTime(); @@ -540,12 +547,12 @@ Value getblocktemplate(const Array& params, bool fHelp) delete pblocktemplate; pblocktemplate = NULL; } - CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy); + CReserveKey reservekey(pwalletMain); + pblocktemplate = CreateNewBlockWithKey(reservekey); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); - // Need to update only after we know CreateNewBlock succeeded + // Need to update only after we know CreateNewBlockWithKey succeeded pindexPrev = pindexPrevNew; } CBlock* pblock = &pblocktemplate->block; // pointer for convenience @@ -556,6 +563,7 @@ Value getblocktemplate(const Array& params, bool fHelp) static const Array aCaps = boost::assign::list_of("proposal"); + Value txCoinbase = Value::null; Array transactions; map setTxIndex; int i = 0; @@ -564,7 +572,7 @@ Value getblocktemplate(const Array& params, bool fHelp) uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; - if (tx.IsCoinBase()) + if (tx.IsCoinBase() && !coinbasetxn) continue; Object entry; @@ -585,7 +593,17 @@ Value getblocktemplate(const Array& params, bool fHelp) entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); - transactions.push_back(entry); + if (tx.IsCoinBase()) { + // Show founders' reward if it is required + if (pblock->vtx[0].vout.size() > 1) { + // Correct this if GetBlockTemplate changes the order + entry.push_back(Pair("foundersreward", (int64_t)tx.vout[1].nValue)); + } + entry.push_back(Pair("required", true)); + txCoinbase = entry; + } else { + transactions.push_back(entry); + } } Object aux; @@ -606,8 +624,13 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); - result.push_back(Pair("coinbaseaux", aux)); - result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + if (coinbasetxn) { + assert(txCoinbase.type() == obj_type); + result.push_back(Pair("coinbasetxn", txCoinbase)); + } else { + result.push_back(Pair("coinbaseaux", aux)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + } result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));