From 2d0a8f1f3ac86369bf1ae879b39cdffb83247d92 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 15 Jun 2021 18:52:39 +0100 Subject: [PATCH] test: Check for valid hashBlockCommitments construction post-NU5 --- qa/pull-tester/rpc-tests.py | 1 + .../feature_zip244_blockcommitments.py | 61 +++++++++++++++++++ qa/rpc-tests/test_framework/blocktools.py | 11 ++++ src/rpc/blockchain.cpp | 2 + 4 files changed, 75 insertions(+) create mode 100755 qa/rpc-tests/feature_zip244_blockcommitments.py diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 67cf1268d..d451eca11 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -116,6 +116,7 @@ BASE_SCRIPTS= [ 'framework.py', 'sapling_rewind_check.py', 'feature_zip221.py', + 'feature_zip244_blockcommitments.py', 'upgrade_golden.py', 'post_heartwood_rollback.py', 'feature_logging.py', diff --git a/qa/rpc-tests/feature_zip244_blockcommitments.py b/qa/rpc-tests/feature_zip244_blockcommitments.py new file mode 100755 index 000000000..785dbf1a0 --- /dev/null +++ b/qa/rpc-tests/feature_zip244_blockcommitments.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://www.opensource.org/licenses/mit-license.php . + + +from test_framework.blocktools import derive_block_commitments_hash +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + bytes_to_hex_str, + hex_str_to_bytes, + start_nodes, +) + +TERMINATOR = b'\x00' * 32 + +# Verify block header field 'hashLightClientRoot' is set correctly for NU5 blocks. +class AuthDataRootTest(BitcoinTestFramework): + + def __init__(self): + super().__init__() + self.num_nodes = 4 + + def setup_nodes(self): + return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[ + '-nuparams=5ba81b19:1', # Overwinter + '-nuparams=76b809bb:1', # Sapling + '-nuparams=2bb40e60:201', # Blossom + '-nuparams=f5b9230b:201', # Heartwood + '-nuparams=e9ff75a6:201', # Canopy + '-nuparams=f919a198:205', # NU5 + '-nurejectoldversions=false', + ]] * self.num_nodes) + + def run_test(self): + # Generate a block so we are on Canopy rules. + self.nodes[0].generate(2) + self.sync_all() + + # Before NU5 activation, the hashBlockCommitments field of the block + # header contains the root of the ZIP 221 history tree. + block_before = self.nodes[0].getblock('202') + assert_equal(block_before['blockcommitments'], block_before['chainhistoryroot']) + + # Generate blocks until we are on NU5 rules. + self.nodes[0].generate(3) + self.sync_all() + + # From NU5 activation, the hashBlockCommitments field of the block + # header contains a hash of various block commitments (per ZIP 244). + block_after = self.nodes[0].getblock('205') + block_commitments = bytes_to_hex_str(derive_block_commitments_hash( + hex_str_to_bytes(block_after['chainhistoryroot'])[::-1], + hex_str_to_bytes(block_after['authdataroot'])[::-1], + )[::-1]) + assert_equal(block_after['blockcommitments'], block_commitments) + + +if __name__ == '__main__': + AuthDataRootTest().main() diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py index fba86848a..6cf7d8d2b 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/qa/rpc-tests/test_framework/blocktools.py @@ -4,6 +4,8 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or https://www.opensource.org/licenses/mit-license.php . +from pyblake2 import blake2b + from .mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint from .script import CScript, OP_0, OP_EQUAL, OP_HASH160, OP_TRUE, OP_CHECKSIG @@ -29,6 +31,15 @@ def create_block(hashprev, coinbase, nTime=None, nBits=None, hashFinalSaplingRoo block.calc_sha256() return block +def derive_block_commitments_hash(chain_history_root, auth_data_root): + digest = blake2b( + digest_size=32, + person=b'ZcashBlockCommit') + digest.update(chain_history_root) + digest.update(auth_data_root) + digest.update(b'\x00' * 32) + return digest.digest() + def serialize_script_num(value): r = bytearray(0) if value == 0: diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 5930b7a7e..834de7462 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -233,6 +233,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.pushKV("height", blockindex->nHeight); result.pushKV("version", block.nVersion); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); + result.pushKV("blockcommitments", blockindex->hashBlockCommitments.GetHex()); + result.pushKV("authdataroot", blockindex->hashAuthDataRoot.GetHex()); result.pushKV("finalsaplingroot", blockindex->hashFinalSaplingRoot.GetHex()); result.pushKV("chainhistoryroot", blockindex->hashChainHistoryRoot.GetHex()); UniValue txs(UniValue::VARR);