2019-12-04 07:04:37 -08:00
|
|
|
#!/usr/bin/env python3
|
2016-10-10 13:24:00 -07:00
|
|
|
# Copyright (c) 2016 The Zcash developers
|
|
|
|
# Distributed under the MIT software license, see the accompanying
|
2019-07-18 07:16:09 -07:00
|
|
|
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2021-12-19 12:49:38 -08:00
|
|
|
from io import BytesIO
|
|
|
|
import codecs
|
2016-10-10 13:24:00 -07:00
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
2021-12-03 10:02:59 -08:00
|
|
|
from test_framework.util import (
|
|
|
|
assert_equal,
|
|
|
|
CANOPY_BRANCH_ID,
|
|
|
|
NU5_BRANCH_ID,
|
2022-05-09 19:17:23 -07:00
|
|
|
get_coinbase_address,
|
2021-12-19 12:49:38 -08:00
|
|
|
hex_str_to_bytes,
|
2021-12-03 10:02:59 -08:00
|
|
|
nuparams,
|
2022-03-23 13:28:31 -07:00
|
|
|
nustr,
|
2021-12-03 10:02:59 -08:00
|
|
|
start_nodes,
|
2021-12-19 12:49:38 -08:00
|
|
|
wait_and_assert_operationid_status,
|
2021-12-03 10:02:59 -08:00
|
|
|
)
|
2021-12-19 12:49:38 -08:00
|
|
|
from test_framework.mininode import (
|
|
|
|
CTransaction,
|
|
|
|
)
|
2022-01-04 08:46:30 -08:00
|
|
|
from test_framework.blocktools import (
|
2021-12-19 12:49:38 -08:00
|
|
|
create_block
|
|
|
|
)
|
|
|
|
from decimal import Decimal
|
2016-10-10 13:24:00 -07:00
|
|
|
|
|
|
|
class GetBlockTemplateTest(BitcoinTestFramework):
|
|
|
|
'''
|
2021-12-19 12:49:38 -08:00
|
|
|
Test getblocktemplate, ensure that a block created from its result
|
|
|
|
can be submitted and accepted.
|
2016-10-10 13:24:00 -07:00
|
|
|
'''
|
|
|
|
|
2016-05-14 04:01:31 -07:00
|
|
|
def __init__(self):
|
|
|
|
super().__init__()
|
2021-12-03 10:02:59 -08:00
|
|
|
self.num_nodes = 1
|
2016-05-14 04:01:31 -07:00
|
|
|
self.setup_clean_chain = True
|
2016-10-10 13:24:00 -07:00
|
|
|
|
|
|
|
def setup_network(self, split=False):
|
2021-12-19 12:49:38 -08:00
|
|
|
args = [
|
2022-01-04 08:46:30 -08:00
|
|
|
nuparams(CANOPY_BRANCH_ID, 115),
|
|
|
|
nuparams(NU5_BRANCH_ID, 130),
|
2021-12-03 10:02:59 -08:00
|
|
|
]
|
|
|
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [args] * self.num_nodes)
|
2022-01-04 08:46:30 -08:00
|
|
|
self.is_network_split = False
|
|
|
|
self.node = self.nodes[0]
|
|
|
|
|
|
|
|
def add_nu5_v4_tx_to_mempool(self):
|
|
|
|
node = self.node
|
|
|
|
# sprout to transparent (v4)
|
|
|
|
recipients = [{"address": self.transparent_addr, "amount": Decimal('0.1')}]
|
2022-05-09 19:17:23 -07:00
|
|
|
myopid = node.z_sendmany(self.sprout_addr, recipients, 1)
|
|
|
|
wait_and_assert_operationid_status(node, myopid)
|
|
|
|
|
|
|
|
def add_nu5_v5_tx_to_mempool(self):
|
|
|
|
node = self.node
|
|
|
|
recipients = [{"address": self.unified_addr, "amount": Decimal('9.99999')}]
|
|
|
|
myopid = node.z_sendmany(get_coinbase_address(node), recipients, 1, Decimal('0.00001'), 'AllowRevealedSenders')
|
2022-01-04 08:46:30 -08:00
|
|
|
wait_and_assert_operationid_status(node, myopid)
|
|
|
|
|
|
|
|
def add_transparent_tx_to_mempool(self):
|
|
|
|
node = self.node
|
|
|
|
# transparent to transparent (v5 after nu5)
|
|
|
|
outputs = {self.transparent_addr: 0.1}
|
|
|
|
node.sendmany('', outputs)
|
|
|
|
|
2022-01-04 18:13:14 -08:00
|
|
|
def gbt_submitblock(self, nu5_active):
|
2022-01-04 08:46:30 -08:00
|
|
|
node = self.node
|
|
|
|
mempool_tx_list = node.getrawmempool()
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2021-12-19 12:49:38 -08:00
|
|
|
gbt = node.getblocktemplate()
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2022-01-04 08:46:30 -08:00
|
|
|
# make sure no transactions were left out (or added)
|
|
|
|
assert_equal(len(mempool_tx_list), len(gbt['transactions']))
|
|
|
|
assert_equal(set(mempool_tx_list), set([tx['hash'] for tx in gbt['transactions']]))
|
|
|
|
|
2021-12-19 12:49:38 -08:00
|
|
|
prevhash = int(gbt['previousblockhash'], 16)
|
|
|
|
nTime = gbt['mintime']
|
|
|
|
nBits = int(gbt['bits'], 16)
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2022-01-04 18:13:14 -08:00
|
|
|
if nu5_active:
|
|
|
|
blockcommitmentshash = int(gbt['defaultroots']['blockcommitmentshash'], 16)
|
|
|
|
else:
|
|
|
|
blockcommitmentshash = int(gbt['defaultroots']['chainhistoryroot'], 16)
|
|
|
|
assert 'blockcommitmentshash' not in gbt['defaultroots']
|
|
|
|
# Confirm that the legacy fields match this default value.
|
|
|
|
assert_equal(blockcommitmentshash, int(gbt['blockcommitmentshash'], 16))
|
|
|
|
assert_equal(blockcommitmentshash, int(gbt['lightclientroothash'], 16))
|
|
|
|
assert_equal(blockcommitmentshash, int(gbt['finalsaplingroothash'], 16))
|
|
|
|
|
2021-12-19 12:49:38 -08:00
|
|
|
f = BytesIO(hex_str_to_bytes(gbt['coinbasetxn']['data']))
|
|
|
|
coinbase = CTransaction()
|
|
|
|
coinbase.deserialize(f)
|
2022-01-04 08:46:30 -08:00
|
|
|
coinbase.calc_sha256()
|
|
|
|
assert_equal(coinbase.hash, gbt['coinbasetxn']['hash'])
|
|
|
|
assert_equal(coinbase.auth_digest_hex, gbt['coinbasetxn']['authdigest'])
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2021-12-19 12:49:38 -08:00
|
|
|
block = create_block(prevhash, coinbase, nTime, nBits, blockcommitmentshash)
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2021-12-19 12:49:38 -08:00
|
|
|
# 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)
|
2022-01-04 08:46:30 -08:00
|
|
|
tx.calc_sha256()
|
2022-05-09 19:17:23 -07:00
|
|
|
assert_equal(tx.hash, gbt_tx['hash'])
|
2022-01-04 08:46:30 -08:00
|
|
|
assert_equal(tx.auth_digest_hex, node.getrawtransaction(tx.hash, 1)['authdigest'])
|
2021-12-19 12:49:38 -08:00
|
|
|
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")
|
2022-01-04 18:13:14 -08:00
|
|
|
if nu5_active:
|
2022-05-09 19:17:23 -07:00
|
|
|
block.hashAuthDataRoot = int(gbt['defaultroots']['authdataroot'], 16)
|
|
|
|
assert_equal(block.hashAuthDataRoot, block.calc_auth_data_root(), "authdataroot")
|
2022-01-04 18:13:14 -08:00
|
|
|
else:
|
|
|
|
assert 'authdataroot' not in gbt['defaultroots']
|
2021-12-19 12:49:38 -08:00
|
|
|
block.solve()
|
2022-01-04 08:46:30 -08:00
|
|
|
block.calc_sha256()
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2022-01-04 08:46:30 -08:00
|
|
|
submitblock_reply = node.submitblock(codecs.encode(block.serialize(), 'hex_codec'))
|
2021-12-28 21:10:13 -08:00
|
|
|
assert_equal(None, submitblock_reply)
|
2022-01-04 08:46:30 -08:00
|
|
|
assert_equal(block.hash, node.getbestblockhash())
|
|
|
|
# Wait until the wallet has been notified of all blocks, so that it doesn't try to
|
|
|
|
# double-spend transparent coins in subsequent test phases.
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
def run_test(self):
|
|
|
|
node = self.node
|
|
|
|
|
|
|
|
# Generate Sprout funds before Canopy activates; using the Sprout address will
|
|
|
|
# force the generation of v4 transactions from NU5.
|
|
|
|
print("Generating pre-Canopy blocks to create sprout funds")
|
|
|
|
# coinbase only becomes mature after 100 blocks, so make one mature.
|
|
|
|
node.generate(105)
|
|
|
|
|
|
|
|
self.sprout_addr = node.z_getnewaddress('sprout')
|
|
|
|
myopid = node.z_shieldcoinbase('*', self.sprout_addr)['opid']
|
|
|
|
wait_and_assert_operationid_status(node, myopid)
|
|
|
|
|
|
|
|
self.transparent_addr = node.getnewaddress()
|
2022-05-09 19:17:23 -07:00
|
|
|
account = node.z_getnewaccount()['account']
|
|
|
|
self.unified_addr = node.z_getaddressforaccount(account)['address']
|
2022-01-04 08:46:30 -08:00
|
|
|
node.generate(15)
|
|
|
|
|
|
|
|
# at height 120, NU5 is not active
|
2022-03-23 13:28:31 -07:00
|
|
|
assert_equal(node.getblockchaininfo()['upgrades'][nustr(NU5_BRANCH_ID)]['status'], 'pending')
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
print("Testing getblocktemplate for pre-NU5")
|
|
|
|
|
|
|
|
# Only the coinbase; this covers the case where the Merkle root
|
|
|
|
# is equal to the coinbase txid.
|
|
|
|
print("- only coinbase")
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(False)
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
# Adding one transaction triggering a single Merkle digest.
|
|
|
|
print("- one transaction (plus coinbase)")
|
|
|
|
self.add_transparent_tx_to_mempool()
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(False)
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
# Adding two transactions to trigger hash Merkle root edge case.
|
|
|
|
print("- two transactions (plus coinbase)")
|
|
|
|
self.add_transparent_tx_to_mempool()
|
|
|
|
self.add_transparent_tx_to_mempool()
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(False)
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
# Activate NU5, repeat the above cases
|
|
|
|
node.generate(7)
|
2022-03-23 13:28:31 -07:00
|
|
|
assert_equal(node.getblockchaininfo()['upgrades'][nustr(NU5_BRANCH_ID)]['status'], 'active')
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
print("Testing getblocktemplate for post-NU5")
|
|
|
|
|
|
|
|
# Only the coinbase; this covers the case where the block authdata root
|
|
|
|
# is equal to the coinbase authdata
|
|
|
|
print("- only coinbase")
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(True)
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
# Adding one transaction triggering a single Merkle digest.
|
|
|
|
print("- one transaction (plus coinbase)")
|
|
|
|
self.add_transparent_tx_to_mempool()
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(True)
|
2022-01-04 08:46:30 -08:00
|
|
|
|
|
|
|
# Adding two transactions to trigger hash Merkle root edge case.
|
|
|
|
print("- two transactions (plus coinbase)")
|
|
|
|
self.add_transparent_tx_to_mempool()
|
|
|
|
self.add_transparent_tx_to_mempool()
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(True)
|
2022-01-04 08:46:30 -08:00
|
|
|
|
2022-05-09 19:17:23 -07:00
|
|
|
# Adding both v4 and v5 to cover legacy auth digest (without full auth digest subtree).
|
|
|
|
print("- both v4 and v5 transactions (plus coinbase)")
|
|
|
|
self.add_nu5_v4_tx_to_mempool()
|
|
|
|
self.add_transparent_tx_to_mempool()
|
|
|
|
self.gbt_submitblock(True)
|
|
|
|
|
|
|
|
# Adding both v4 and v5 to cover legacy auth digest (with full auth digest subtree).
|
2022-01-04 08:46:30 -08:00
|
|
|
print("- both v4 and v5 transactions (plus coinbase)")
|
|
|
|
self.add_nu5_v4_tx_to_mempool()
|
|
|
|
self.add_transparent_tx_to_mempool()
|
|
|
|
self.add_transparent_tx_to_mempool()
|
2022-01-04 18:13:14 -08:00
|
|
|
self.gbt_submitblock(True)
|
2016-10-10 13:24:00 -07:00
|
|
|
|
2022-05-09 19:17:23 -07:00
|
|
|
print("- block with 6 Orchard transactions (plus coinbase)")
|
|
|
|
for i in range(0, 6):
|
|
|
|
print(str(node.z_getbalance(self.transparent_addr)))
|
|
|
|
self.add_nu5_v5_tx_to_mempool()
|
|
|
|
self.gbt_submitblock(True)
|
|
|
|
|
|
|
|
print("- block with 7 Orchard transactions (plus coinbase)")
|
|
|
|
for i in range(0, 7):
|
|
|
|
self.add_nu5_v5_tx_to_mempool()
|
|
|
|
self.gbt_submitblock(True)
|
2018-06-01 14:47:30 -07:00
|
|
|
|
2016-10-10 13:24:00 -07:00
|
|
|
if __name__ == '__main__':
|
|
|
|
GetBlockTemplateTest().main()
|