Auto merge of #1602 - str4d:1424-minimal-getblocktemplate, r=daira
Minimal modifications to getblocktemplate A simpler alternative to #1435 that ensures Zcash GBT will remain compatible with BIP 22. Closes #1424
This commit is contained in:
@@ -31,6 +31,7 @@ testScripts=(
|
|||||||
'walletbackup.py'
|
'walletbackup.py'
|
||||||
'zcjoinsplit.py'
|
'zcjoinsplit.py'
|
||||||
'zcjoinsplitdoublespend.py'
|
'zcjoinsplitdoublespend.py'
|
||||||
|
'getblocktemplate.py'
|
||||||
);
|
);
|
||||||
testScriptsExt=(
|
testScriptsExt=(
|
||||||
'bipdersig-p2p.py'
|
'bipdersig-p2p.py'
|
||||||
|
|||||||
58
qa/rpc-tests/getblocktemplate.py
Executable file
58
qa/rpc-tests/getblocktemplate.py
Executable file
@@ -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()
|
||||||
@@ -71,9 +71,11 @@ def genmrklroot(leaflist):
|
|||||||
def template_to_bytes(tmpl, txlist):
|
def template_to_bytes(tmpl, txlist):
|
||||||
blkver = pack('<L', tmpl['version'])
|
blkver = pack('<L', tmpl['version'])
|
||||||
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
|
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
|
||||||
|
reserved = b'\0'*32
|
||||||
timestamp = pack('<L', tmpl['curtime'])
|
timestamp = pack('<L', tmpl['curtime'])
|
||||||
nonce = b'\0\0\0\0'
|
nonce = b'\0'*32
|
||||||
blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce
|
soln = b'\0'
|
||||||
|
blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + reserved + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce + soln
|
||||||
blk += varlenEncode(len(txlist))
|
blk += varlenEncode(len(txlist))
|
||||||
for tx in txlist:
|
for tx in txlist:
|
||||||
blk += tx
|
blk += tx
|
||||||
|
|||||||
@@ -389,10 +389,10 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||||||
" }\n"
|
" }\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
" ],\n"
|
" ],\n"
|
||||||
" \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
|
// " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
|
||||||
" \"flags\" : \"flags\" (string) \n"
|
// " \"flags\" : \"flags\" (string) \n"
|
||||||
" },\n"
|
// " },\n"
|
||||||
" \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
|
// " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
|
||||||
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
|
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
|
||||||
" \"target\" : \"xxxx\", (string) The hash target\n"
|
" \"target\" : \"xxxx\", (string) The hash target\n"
|
||||||
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
|
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
|
||||||
@@ -415,8 +415,15 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
|
// Wallet is required because we support coinbasetxn
|
||||||
|
if (pwalletMain == NULL) {
|
||||||
|
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
|
||||||
|
}
|
||||||
|
|
||||||
std::string strMode = "template";
|
std::string strMode = "template";
|
||||||
Value lpval = Value::null;
|
Value lpval = Value::null;
|
||||||
|
// TODO: Re-enable coinbasevalue once a specification has been written
|
||||||
|
bool coinbasetxn = true;
|
||||||
if (params.size() > 0)
|
if (params.size() > 0)
|
||||||
{
|
{
|
||||||
const Object& oparam = params[0].get_obj();
|
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
|
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
||||||
pindexPrev = NULL;
|
pindexPrev = NULL;
|
||||||
|
|
||||||
// Store the pindexBest used before CreateNewBlock, to avoid races
|
// Store the pindexBest used before CreateNewBlockWithKey, to avoid races
|
||||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||||
CBlockIndex* pindexPrevNew = chainActive.Tip();
|
CBlockIndex* pindexPrevNew = chainActive.Tip();
|
||||||
nStart = GetTime();
|
nStart = GetTime();
|
||||||
@@ -540,12 +547,12 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
pblocktemplate = NULL;
|
pblocktemplate = NULL;
|
||||||
}
|
}
|
||||||
CScript scriptDummy = CScript() << OP_TRUE;
|
CReserveKey reservekey(pwalletMain);
|
||||||
pblocktemplate = CreateNewBlock(scriptDummy);
|
pblocktemplate = CreateNewBlockWithKey(reservekey);
|
||||||
if (!pblocktemplate)
|
if (!pblocktemplate)
|
||||||
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
|
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;
|
pindexPrev = pindexPrevNew;
|
||||||
}
|
}
|
||||||
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
|
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");
|
static const Array aCaps = boost::assign::list_of("proposal");
|
||||||
|
|
||||||
|
Value txCoinbase = Value::null;
|
||||||
Array transactions;
|
Array transactions;
|
||||||
map<uint256, int64_t> setTxIndex;
|
map<uint256, int64_t> setTxIndex;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -564,7 +572,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||||||
uint256 txHash = tx.GetHash();
|
uint256 txHash = tx.GetHash();
|
||||||
setTxIndex[txHash] = i++;
|
setTxIndex[txHash] = i++;
|
||||||
|
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase() && !coinbasetxn)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Object entry;
|
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("fee", pblocktemplate->vTxFees[index_in_template]));
|
||||||
entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[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;
|
Object aux;
|
||||||
@@ -606,8 +624,13 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
|||||||
result.push_back(Pair("version", pblock->nVersion));
|
result.push_back(Pair("version", pblock->nVersion));
|
||||||
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
|
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
|
||||||
result.push_back(Pair("transactions", transactions));
|
result.push_back(Pair("transactions", transactions));
|
||||||
result.push_back(Pair("coinbaseaux", aux));
|
if (coinbasetxn) {
|
||||||
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
|
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("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
|
||||||
result.push_back(Pair("target", hashTarget.GetHex()));
|
result.push_back(Pair("target", hashTarget.GetHex()));
|
||||||
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
|
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
|
||||||
|
|||||||
Reference in New Issue
Block a user