Merge pull request #5431 from LarryRuane/2021-12-test-getblocktemplate-submitblock

test: Use result of getblocktemplate to submitblock
This commit is contained in:
Sasha 2021-12-22 16:06:42 -08:00 committed by GitHub
commit bc6e565bcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 34 deletions

View File

@ -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()

View File

@ -660,7 +660,7 @@ class OutputDescription(object):
self.encCiphertext = f.read(580)
self.outCiphertext = f.read(80)
self.zkproof = Groth16Proof()
self.zkproof.deserialize()
self.zkproof.deserialize(f)
def serialize(self):
r = b""
@ -971,6 +971,8 @@ class CTransaction(object):
self.nLockTime = 0
self.nExpiryHeight = 0
self.valueBalance = 0
self.saplingBundle = SaplingBundle()
self.orchardBundle = OrchardBundle()
self.shieldedSpends = []
self.shieldedOutputs = []
self.vJoinSplit = []
@ -988,6 +990,8 @@ class CTransaction(object):
self.nLockTime = tx.nLockTime
self.nExpiryHeight = tx.nExpiryHeight
self.valueBalance = tx.valueBalance
self.saplingBundle = copy.deepcopy(tx.saplingBundle)
self.orchardBundle = copy.deepcopy(tx.orchardBundle)
self.shieldedSpends = copy.deepcopy(tx.shieldedSpends)
self.shieldedOutputs = copy.deepcopy(tx.shieldedOutputs)
self.vJoinSplit = copy.deepcopy(tx.vJoinSplit)
@ -1075,6 +1079,7 @@ class CTransaction(object):
# Common transaction fields
r += struct.pack("<I", header)
r += struct.pack("<I", self.nVersionGroupId)
r += struct.pack("<I", self.nConsensusBranchId)
r += struct.pack("<I", self.nLockTime)
r += struct.pack("<I", self.nExpiryHeight)

View File

@ -52,7 +52,7 @@ def sapling_digest(saplingBundle):
if len(saplingBundle.spends) + len(saplingBundle.outputs) > 0:
digest.update(sapling_spends_digest(saplingBundle))
digest.update(sapling_outputs_digest(saplingBundle))
digest.update(struct.pack('<Q', saplingBundle.valueBalance))
digest.update(struct.pack('<q', saplingBundle.valueBalance))
return digest.digest()
@ -126,7 +126,7 @@ def sapling_outputs_noncompact_digest(saplingBundle):
for desc in saplingBundle.outputs:
digest.update(ser_uint256(desc.cv))
digest.update(desc.encCiphertext[564:])
digest.update(desc.outCipherText)
digest.update(desc.outCiphertext)
return digest.digest()
# Orchard
@ -139,7 +139,7 @@ def orchard_digest(orchardBundle):
digest.update(orchard_actions_memos_digest(orchardBundle))
digest.update(orchard_actions_noncompact_digest(orchardBundle))
digest.update(struct.pack('<B', orchardBundle.flags()))
digest.update(struct.pack('<Q', orchardBundle.valueBalance))
digest.update(struct.pack('<q', orchardBundle.valueBalance))
digest.update(bytes(orchardBundle.anchor))
return digest.digest()

View File

@ -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"