test: Use result of getblocktemplate to submitblock
This will ensure that miners can use the values returned by getblocktemplate (in particular, the block commitment hash) to submit a valid block using the submitblock RPC.
This commit is contained in:
parent
8c0177a507
commit
b538577359
|
@ -3,6 +3,8 @@
|
|||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
from io import BytesIO
|
||||
import codecs
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
|
@ -10,13 +12,24 @@ from test_framework.util import (
|
|||
CANOPY_BRANCH_ID,
|
||||
HEARTWOOD_BRANCH_ID,
|
||||
NU5_BRANCH_ID,
|
||||
get_coinbase_address,
|
||||
hex_str_to_bytes,
|
||||
nuparams,
|
||||
start_nodes,
|
||||
wait_and_assert_operationid_status,
|
||||
)
|
||||
from test_framework.mininode import (
|
||||
CTransaction,
|
||||
)
|
||||
from test_framework.blocktools import(
|
||||
create_block
|
||||
)
|
||||
from decimal import Decimal
|
||||
|
||||
class GetBlockTemplateTest(BitcoinTestFramework):
|
||||
'''
|
||||
Test getblocktemplate.
|
||||
Test getblocktemplate, ensure that a block created from its result
|
||||
can be submitted and accepted.
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
|
@ -25,7 +38,8 @@ class GetBlockTemplateTest(BitcoinTestFramework):
|
|||
self.setup_clean_chain = True
|
||||
|
||||
def setup_network(self, split=False):
|
||||
args = [nuparams(BLOSSOM_BRANCH_ID, 1),
|
||||
args = [
|
||||
nuparams(BLOSSOM_BRANCH_ID, 1),
|
||||
nuparams(HEARTWOOD_BRANCH_ID, 1),
|
||||
nuparams(CANOPY_BRANCH_ID, 1),
|
||||
nuparams(NU5_BRANCH_ID, 1),
|
||||
|
@ -36,40 +50,56 @@ class GetBlockTemplateTest(BitcoinTestFramework):
|
|||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
node.generate(1) # Mine a block to leave initial block download
|
||||
print("Generating blocks")
|
||||
node.generate(110)
|
||||
|
||||
# Test 1: Default to coinbasetxn
|
||||
tmpl = node.getblocktemplate()
|
||||
assert('coinbasetxn' in tmpl)
|
||||
assert('coinbasevalue' not in tmpl)
|
||||
print("Add transactions to the mempool so they will be in the template")
|
||||
# This part of the test should be improved, submit some V4 transactions
|
||||
# and varying combinations of shielded and transparent
|
||||
for _ in range(5):
|
||||
# submit a tx with a shielded output
|
||||
taddr0 = get_coinbase_address(node)
|
||||
zaddr = node.z_getnewaddress('sapling')
|
||||
recipients = [{"address": zaddr, "amount": Decimal('0.1')}]
|
||||
myopid = node.z_sendmany(taddr0, recipients, 1, 0)
|
||||
wait_and_assert_operationid_status(node, myopid)
|
||||
|
||||
# Test 2: Get coinbasetxn if requested
|
||||
tmpl = node.getblocktemplate({'capabilities': ['coinbasetxn']})
|
||||
assert('coinbasetxn' in tmpl)
|
||||
assert('coinbasevalue' not in tmpl)
|
||||
# submit a tx with a transparent output
|
||||
outputs = {node.getnewaddress():0.2}
|
||||
node.sendmany('', outputs)
|
||||
|
||||
# Test 3: coinbasevalue not supported if requested
|
||||
tmpl = node.getblocktemplate({'capabilities': ['coinbasevalue']})
|
||||
assert('coinbasetxn' in tmpl)
|
||||
assert('coinbasevalue' not in tmpl)
|
||||
print("Getting block template")
|
||||
gbt = node.getblocktemplate()
|
||||
|
||||
# Test 4: coinbasevalue not supported if both requested
|
||||
tmpl = node.getblocktemplate({'capabilities': ['coinbasetxn', 'coinbasevalue']})
|
||||
assert('coinbasetxn' in tmpl)
|
||||
assert('coinbasevalue' not in tmpl)
|
||||
prevhash = int(gbt['previousblockhash'], 16)
|
||||
blockcommitmentshash = int(gbt['defaultroots']['blockcommitmentshash'], 16)
|
||||
nTime = gbt['mintime']
|
||||
nBits = int(gbt['bits'], 16)
|
||||
|
||||
# Test 5: General checks
|
||||
tmpl = node.getblocktemplate()
|
||||
assert_equal(16, len(tmpl['noncerange']))
|
||||
# should be proposing height 2, since current tip is height 1
|
||||
assert_equal(2, tmpl['height'])
|
||||
f = BytesIO(hex_str_to_bytes(gbt['coinbasetxn']['data']))
|
||||
coinbase = CTransaction()
|
||||
coinbase.deserialize(f)
|
||||
|
||||
# Test 6: coinbasetxn checks
|
||||
assert(tmpl['coinbasetxn']['required'])
|
||||
print("Creating_block from template (simulating a miner)")
|
||||
block = create_block(prevhash, coinbase, nTime, nBits, blockcommitmentshash)
|
||||
|
||||
# copy the non-coinbase transactions from the block template to the block
|
||||
for gbt_tx in gbt['transactions']:
|
||||
f = BytesIO(hex_str_to_bytes(gbt_tx['data']))
|
||||
tx = CTransaction()
|
||||
tx.deserialize(f)
|
||||
block.vtx.append(tx)
|
||||
block.hashMerkleRoot = int(gbt['defaultroots']['merkleroot'], 16)
|
||||
assert_equal(block.hashMerkleRoot, block.calc_merkle_root(), "merkleroot")
|
||||
assert_equal(len(block.vtx), len(gbt['transactions']) + 1, "number of transactions")
|
||||
assert_equal(block.hashPrevBlock, int(gbt['previousblockhash'], 16), "prevhash")
|
||||
block.solve()
|
||||
block = block.serialize()
|
||||
block = codecs.encode(block, 'hex_codec')
|
||||
|
||||
print("Submitting block")
|
||||
node.submitblock(block)
|
||||
|
||||
# Test 7: blockcommitmentshash checks
|
||||
assert('blockcommitmentshash' in tmpl)
|
||||
assert('00' * 32 != tmpl['finalsaplingroothash'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
GetBlockTemplateTest().main()
|
||||
|
|
|
@ -449,9 +449,15 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
|||
"{\n"
|
||||
" \"version\" : n, (numeric) The block version\n"
|
||||
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
|
||||
" \"blockcommitmentshash\" : \"xxxx\", (string) The hash of the block commitments field in the block header\n"
|
||||
" \"blockcommitmentshash\" : \"xxxx\", (string) (DEPRECATED) The hash of the block commitments field in the block header\n"
|
||||
" \"lightclientroothash\" : \"xxxx\", (string) (DEPRECATED) The hash of the light client root field in the block header\n"
|
||||
" \"finalsaplingroothash\" : \"xxxx\", (string) (DEPRECATED) The hash of the light client root field in the block header\n"
|
||||
" \"defaultroots\" : { (json object) root hashes that need to be recomputed if the transaction set is modified\n"
|
||||
" \"merkleroot\" : \"xxxx\" (string) The hash of the transactions in the block header\n"
|
||||
" \"authdataroot\" : \"xxxx\" (string) The hash of the authorizing data merkel tree\n"
|
||||
" \"chainhistoryroot\" : \"xxxx\" (string) The hash of the chain history\n"
|
||||
" \"blockcommitmentshash\" : \"xxxx\" (string) The hash of the block commitments field in the block header\n"
|
||||
" }\n"
|
||||
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
|
||||
" {\n"
|
||||
" \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
|
||||
|
|
Loading…
Reference in New Issue