From 7fa0e1a6a94e1fc5ef2b81b3cd661e2186a6fa97 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Fri, 3 Dec 2021 13:32:40 -0700 Subject: [PATCH] test: automatically add missing nuparams This test-only change allows python (rpc) tests to specify, for example, that NU5 should be activated at height X, without having to specify all the previous network upgrades. Previous upgrades can (and must) still be specified if they activate at different block heights (than, in this example, NU5). This makes tests easier to write (and read), especially as the number of network upgrades increases over time. Note that this change only affects zcashd behavior in regtest mode. For the other network modes (testnet and mainnet), the activation heights are hard-coded in chainparams.cpp. --- qa/pull-tester/rpc-tests.py | 1 + qa/rpc-tests/nuparams.py | 217 ++++++++++++++++++++++++++++++++++++ src/init.cpp | 23 ++++ 3 files changed, 241 insertions(+) create mode 100755 qa/rpc-tests/nuparams.py diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 9f36dbc18..c7a1057e0 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -122,6 +122,7 @@ BASE_SCRIPTS= [ 'feature_zip239.py', 'feature_zip244_blockcommitments.py', 'upgrade_golden.py', + 'nuparams.py', 'post_heartwood_rollback.py', 'feature_logging.py', 'feature_walletfile.py', diff --git a/qa/rpc-tests/nuparams.py b/qa/rpc-tests/nuparams.py new file mode 100755 index 000000000..4482f116a --- /dev/null +++ b/qa/rpc-tests/nuparams.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 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.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + start_nodes, + nuparams, + HEARTWOOD_BRANCH_ID, + NU5_BRANCH_ID, +) + + +class NuparamsTest(BitcoinTestFramework): + ''' + Test that unspecified network upgrades are activated automatically; + this is really more of a test of the test framework. + ''' + + def __init__(self): + super().__init__() + self.num_nodes = 1 + self.setup_clean_chain = True + + def setup_network(self, split=False): + args = [[ + nuparams(HEARTWOOD_BRANCH_ID, 3), + nuparams(NU5_BRANCH_ID, 5), + ] * self.num_nodes] + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, args) + self.is_network_split = False + self.sync_all() + + def run_test(self): + node = self.nodes[0] + # No blocks have been created, only the genesis block exists (height 0) + bci = node.getblockchaininfo() + assert_equal(bci['blocks'], 0) + upgrades = bci['upgrades'] + + overwinter = upgrades['5ba81b19'] + assert_equal(overwinter['name'], 'Overwinter') + assert_equal(overwinter['activationheight'], 1) + assert_equal(overwinter['status'], 'pending') + + sapling = upgrades['76b809bb'] + assert_equal(sapling['name'], 'Sapling') + assert_equal(sapling['activationheight'], 1) + assert_equal(sapling['status'], 'pending') + + blossom = upgrades['2bb40e60'] + assert_equal(blossom['name'], 'Blossom') + assert_equal(blossom['activationheight'], 3) + assert_equal(blossom['status'], 'pending') + + heartwood = upgrades['f5b9230b'] + assert_equal(heartwood['name'], 'Heartwood') + assert_equal(heartwood['activationheight'], 3) + assert_equal(heartwood['status'], 'pending') + + canopy = upgrades['e9ff75a6'] + assert_equal(canopy['name'], 'Canopy') + assert_equal(canopy['activationheight'], 5) + assert_equal(canopy['status'], 'pending') + + nu5 = upgrades['37519621'] + assert_equal(nu5['name'], 'NU5') + assert_equal(nu5['activationheight'], 5) + assert_equal(nu5['status'], 'pending') + + node.generate(1) + + # start_node() hardcodes Sapling and Overwinter to activate a height 1 + bci = node.getblockchaininfo() + assert_equal(bci['blocks'], 1) + upgrades = bci['upgrades'] + + overwinter = upgrades['5ba81b19'] + assert_equal(overwinter['name'], 'Overwinter') + assert_equal(overwinter['activationheight'], 1) + assert_equal(overwinter['status'], 'active') + + sapling = upgrades['76b809bb'] + assert_equal(sapling['name'], 'Sapling') + assert_equal(sapling['activationheight'], 1) + assert_equal(sapling['status'], 'active') + + blossom = upgrades['2bb40e60'] + assert_equal(blossom['name'], 'Blossom') + assert_equal(blossom['activationheight'], 3) + assert_equal(blossom['status'], 'pending') + + heartwood = upgrades['f5b9230b'] + assert_equal(heartwood['name'], 'Heartwood') + assert_equal(heartwood['activationheight'], 3) + assert_equal(heartwood['status'], 'pending') + + canopy = upgrades['e9ff75a6'] + assert_equal(canopy['name'], 'Canopy') + assert_equal(canopy['activationheight'], 5) + assert_equal(canopy['status'], 'pending') + + nu5 = upgrades['37519621'] + assert_equal(nu5['name'], 'NU5') + assert_equal(nu5['activationheight'], 5) + assert_equal(nu5['status'], 'pending') + + node.generate(1) + bci = node.getblockchaininfo() + assert_equal(bci['blocks'], 2) + upgrades = bci['upgrades'] + + overwinter = upgrades['5ba81b19'] + assert_equal(overwinter['name'], 'Overwinter') + assert_equal(overwinter['activationheight'], 1) + assert_equal(overwinter['status'], 'active') + + sapling = upgrades['76b809bb'] + assert_equal(sapling['name'], 'Sapling') + assert_equal(sapling['activationheight'], 1) + assert_equal(sapling['status'], 'active') + + blossom = upgrades['2bb40e60'] + assert_equal(blossom['name'], 'Blossom') + assert_equal(blossom['activationheight'], 3) + assert_equal(blossom['status'], 'pending') + + heartwood = upgrades['f5b9230b'] + assert_equal(heartwood['name'], 'Heartwood') + assert_equal(heartwood['activationheight'], 3) + assert_equal(heartwood['status'], 'pending') + + canopy = upgrades['e9ff75a6'] + assert_equal(canopy['name'], 'Canopy') + assert_equal(canopy['activationheight'], 5) + assert_equal(canopy['status'], 'pending') + + nu5 = upgrades['37519621'] + assert_equal(nu5['name'], 'NU5') + assert_equal(nu5['activationheight'], 5) + assert_equal(nu5['status'], 'pending') + + node.generate(2) + bci = node.getblockchaininfo() + assert_equal(bci['blocks'], 4) + upgrades = bci['upgrades'] + + overwinter = upgrades['5ba81b19'] + assert_equal(overwinter['name'], 'Overwinter') + assert_equal(overwinter['activationheight'], 1) + assert_equal(overwinter['status'], 'active') + + sapling = upgrades['76b809bb'] + assert_equal(sapling['name'], 'Sapling') + assert_equal(sapling['activationheight'], 1) + assert_equal(sapling['status'], 'active') + + blossom = upgrades['2bb40e60'] + assert_equal(blossom['name'], 'Blossom') + assert_equal(blossom['activationheight'], 3) + assert_equal(blossom['status'], 'active') + + heartwood = upgrades['f5b9230b'] + assert_equal(heartwood['name'], 'Heartwood') + assert_equal(heartwood['activationheight'], 3) + assert_equal(heartwood['status'], 'active') + + canopy = upgrades['e9ff75a6'] + assert_equal(canopy['name'], 'Canopy') + assert_equal(canopy['activationheight'], 5) + assert_equal(canopy['status'], 'pending') + + nu5 = upgrades['37519621'] + assert_equal(nu5['name'], 'NU5') + assert_equal(nu5['activationheight'], 5) + assert_equal(nu5['status'], 'pending') + + node.generate(1) + bci = node.getblockchaininfo() + assert_equal(bci['blocks'], 5) + upgrades = bci['upgrades'] + + overwinter = upgrades['5ba81b19'] + assert_equal(overwinter['name'], 'Overwinter') + assert_equal(overwinter['activationheight'], 1) + assert_equal(overwinter['status'], 'active') + + sapling = upgrades['76b809bb'] + assert_equal(sapling['name'], 'Sapling') + assert_equal(sapling['activationheight'], 1) + assert_equal(sapling['status'], 'active') + + blossom = upgrades['2bb40e60'] + assert_equal(blossom['name'], 'Blossom') + assert_equal(blossom['activationheight'], 3) + assert_equal(blossom['status'], 'active') + + heartwood = upgrades['f5b9230b'] + assert_equal(heartwood['name'], 'Heartwood') + assert_equal(heartwood['activationheight'], 3) + assert_equal(heartwood['status'], 'active') + + canopy = upgrades['e9ff75a6'] + assert_equal(canopy['name'], 'Canopy') + assert_equal(canopy['activationheight'], 5) + assert_equal(canopy['status'], 'active') + + nu5 = upgrades['37519621'] + assert_equal(nu5['name'], 'NU5') + assert_equal(nu5['activationheight'], 5) + assert_equal(nu5['status'], 'active') + + +if __name__ == '__main__': + NuparamsTest().main() diff --git a/src/init.cpp b/src/init.cpp index 365272ebf..b632d7e2b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1143,6 +1143,29 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(strprintf("Invalid network upgrade (%s)", vDeploymentParams[0])); } } + + // To make testing easier (this code path is active only for regtest), activate missing network versions, + // so for example, if a Python (RPC) test does: + // extra_args = [ + // nuparams(BLOSSOM_BRANCH_ID, 205), + // nuparams(HEARTWOOD_BRANCH_ID, 205), + // nuparams(CANOPY_BRANCH_ID, 205), + // nuparams(NU5_BRANCH_ID, 210), + // ] + // + // This can be simplified to: + // extra_args = [ + // nuparams(CANOPY_BRANCH_ID, 205), + // nuparams(NU5_BRANCH_ID, 210), + // ] + const auto& consensus = chainparams.GetConsensus(); + int nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + for (auto i = Consensus::MAX_NETWORK_UPGRADES-1; i >= Consensus::BASE_SPROUT + 1; --i) { + if (consensus.vUpgrades[i].nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex(i), nActivationHeight); + } + nActivationHeight = consensus.vUpgrades[i].nActivationHeight; + } } if (mapArgs.count("-nurejectoldversions")) {