Merge pull request #5431 from LarryRuane/2021-12-test-getblocktemplate-submitblock
test: Use result of getblocktemplate to submitblock
This commit is contained in:
commit
bc6e565bcc
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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