From 641f889faa77e6e9f77c1d5eefad1af54d0daf68 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 8 May 2025 18:28:46 +0700 Subject: [PATCH 01/10] feat: start v20 from the same block as DIP0003 on regtest --- src/chainparams.cpp | 2 +- src/test/util/setup_common.cpp | 2 +- test/functional/feature_asset_locks.py | 8 +++++--- test/functional/feature_dip4_coinbasemerkleroots.py | 2 ++ test/functional/feature_governance.py | 2 +- test/functional/feature_llmq_chainlocks.py | 5 +++-- test/functional/feature_llmq_rotation.py | 1 + test/functional/feature_llmq_simplepose.py | 1 + test/functional/feature_mnehf.py | 3 --- test/functional/test_framework/test_framework.py | 8 +++++++- 10 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9a7394fcca6c..e9cd070f24cc 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -795,7 +795,7 @@ class CRegTestParams : public CChainParams { consensus.DIP0024Height = 1; // Always have dip0024 quorums unless overridden consensus.DIP0024QuorumsHeight = 1; // Always have dip0024 quorums unless overridden consensus.V19Height = 1; // Always active unless overriden - consensus.V20Height = 900; + consensus.V20Height = consensus.DIP0003Height; // Active not earlier than dip0003. Functional tests (DashTestFramework) uses height 100 (same as coinbase maturity) consensus.MN_RRHeight = 900; consensus.MinBIP9WarningHeight = 0; consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1 diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index d005cd10ec2d..de6adc03eb52 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -399,7 +399,7 @@ TestChainSetup::TestChainSetup(int num_blocks, const std::vector& e /*TestChainBRRBeforeActivationSetup=*/ { 497, uint256S("0x0857a9b5db51835b1c828f019f4c664b5fe6c28ac44a6d868436930f832d31e5") }, /*TestChainV19BeforeActivationSetup=*/ - { 494, uint256S("0x44ee5c8a5e5cbd4437d63c54ddc1d40329be811b25c492fa901e11cdf408f905") }, + { 494, uint256S("72c5b8760d9070ca3b6402094dcea76cd25806bc20d1bf3777a7be712e17bbd2") }, } }; diff --git a/test/functional/feature_asset_locks.py b/test/functional/feature_asset_locks.py index cb2da9885ee6..7dc7dbc8d6a3 100755 --- a/test/functional/feature_asset_locks.py +++ b/test/functional/feature_asset_locks.py @@ -248,8 +248,7 @@ def run_test(self): self.set_sporks() - self.activate_v20(expected_activation_height=900) - self.log.info("Activated v20 at height:" + str(node.getblockcount())) + assert_equal(self.nodes[0].getblockchaininfo()['softforks']['v20']['active'], True) for _ in range(2): self.dynamically_add_masternode(evo=True) @@ -515,10 +514,13 @@ def test_withdrawal_limits(self, node_wallet, node, pubkey): total = self.get_credit_pool_balance() coins = node_wallet.listunspent() while total <= 10_901 * COIN: + if len(coins) == 0: + coins = node_wallet.listunspent(query_options={'minimumAmount': 1}) coin = coins.pop() to_lock = int(coin['amount'] * COIN) - tiny_amount - if to_lock > 99 * COIN: + if to_lock > 99 * COIN and total > 10_000 * COIN: to_lock = 99 * COIN + total += to_lock tx = self.create_assetlock(coin, to_lock, pubkey) self.send_tx_simple(tx) diff --git a/test/functional/feature_dip4_coinbasemerkleroots.py b/test/functional/feature_dip4_coinbasemerkleroots.py index 51563e0aa86a..002f00212e09 100755 --- a/test/functional/feature_dip4_coinbasemerkleroots.py +++ b/test/functional/feature_dip4_coinbasemerkleroots.py @@ -19,6 +19,7 @@ DIP0008_HEIGHT = 432 DIP0024_HEIGHT = 900 +V20_HEIGHT = 900 # TODO: this helper used in many tests, find a new home for it class TestP2PConn(P2PInterface): @@ -46,6 +47,7 @@ class LLMQCoinbaseCommitmentsTest(DashTestFramework): def set_test_params(self): self.extra_args = [[ f'-testactivationheight=dip0008@{DIP0008_HEIGHT}', f'-testactivationheight=dip0024@{DIP0024_HEIGHT}', "-vbparams=testdummy:999999999999:999999999999" ]] * 4 self.set_dash_test_params(4, 3, extra_args = self.extra_args) + self.delay_v20(height=V20_HEIGHT) def remove_masternode(self, idx): mn = self.mninfo[idx] diff --git a/test/functional/feature_governance.py b/test/functional/feature_governance.py index b98990f4f015..357bd2ec8e47 100755 --- a/test/functional/feature_governance.py +++ b/test/functional/feature_governance.py @@ -17,8 +17,8 @@ class DashGovernanceTest (DashTestFramework): def set_test_params(self): self.set_dash_test_params(6, 5, [[ "-budgetparams=10:10:10", - '-testactivationheight=v20@160', ]] * 6) + self.delay_v20(height=160) def check_superblockbudget(self, v20_active): v20_state = self.nodes[0].getblockchaininfo()["softforks"]["v20"] diff --git a/test/functional/feature_llmq_chainlocks.py b/test/functional/feature_llmq_chainlocks.py index 5c0bc319bb4c..eb2dbd13351f 100755 --- a/test/functional/feature_llmq_chainlocks.py +++ b/test/functional/feature_llmq_chainlocks.py @@ -20,6 +20,7 @@ class LLMQChainLocksTest(DashTestFramework): def set_test_params(self): self.set_dash_test_params(5, 4) + self.delay_v20(height=200) def run_test(self): # Connect all nodes to node1 so that we always have the whole network connected @@ -30,8 +31,8 @@ def run_test(self): self.test_coinbase_best_cl(self.nodes[0], expected_cl_in_cb=False) - self.activate_mn_rr(expected_activation_height=900) - self.log.info("Activated MN_RR at height:" + str(self.nodes[0].getblockcount())) + self.activate_v20(expected_activation_height=200) + self.log.info("Activated v20 at height:" + str(self.nodes[0].getblockcount())) # v20 is active for the next block, not for the tip self.test_coinbase_best_cl(self.nodes[0], expected_cl_in_cb=False) diff --git a/test/functional/feature_llmq_rotation.py b/test/functional/feature_llmq_rotation.py index f36838832105..6a3d1b891edb 100755 --- a/test/functional/feature_llmq_rotation.py +++ b/test/functional/feature_llmq_rotation.py @@ -53,6 +53,7 @@ class LLMQQuorumRotationTest(DashTestFramework): def set_test_params(self): self.set_dash_test_params(9, 8) self.set_dash_llmq_test_params(4, 4) + self.delay_v20(height=900) def run_test(self): llmq_type=103 diff --git a/test/functional/feature_llmq_simplepose.py b/test/functional/feature_llmq_simplepose.py index df12d4bea424..ee647250f57c 100755 --- a/test/functional/feature_llmq_simplepose.py +++ b/test/functional/feature_llmq_simplepose.py @@ -22,6 +22,7 @@ def set_test_params(self): self.extra_args = [[ '-testactivationheight=dip0024@9999' ]] * 6 self.set_dash_test_params(6, 5) self.set_dash_llmq_test_params(5, 3) + self.delay_v20(height=9999) def add_options(self, parser): parser.add_argument("--disable-spork23", dest="disable_spork23", default=False, action="store_true", diff --git a/test/functional/feature_mnehf.py b/test/functional/feature_mnehf.py index ae0585dba82c..55d3f3ec49fa 100755 --- a/test/functional/feature_mnehf.py +++ b/test/functional/feature_mnehf.py @@ -121,9 +121,6 @@ def run_test(self): node = self.nodes[0] self.set_sporks() - self.log.info("Consensus rules assume there're no EHF signal before V20") - self.activate_v20() - self.log.info("Mine a quorum...") self.mine_quorum() self.check_fork('defined') diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index ca5e1d59d55b..46c4223679e8 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -599,6 +599,7 @@ def add_dynamically_node(self, extra_args=None, *, rpchost=None, binary=None): self.nodes.append(t_node) return t_node + # TODO: move it to DashTestFramework where it belongs def dynamically_initialize_datadir(self, node_p2p_port, node_rpc_port): source_data_dir = get_datadir_path(self.options.tmpdir, 0) # use node0 as a source new_data_dir = get_datadir_path(self.options.tmpdir, len(self.nodes)) @@ -633,6 +634,7 @@ def dynamically_initialize_datadir(self, node_p2p_port, node_rpc_port): f.write("natpmp=0\n") f.write("shrinkdebugfile=0\n") f.write("dip3params=2:2\n") + f.write(f"testactivationheight=v20@{self.v20_height}\n") os.makedirs(os.path.join(new_data_dir, 'stderr'), exist_ok=True) os.makedirs(os.path.join(new_data_dir, 'stdout'), exist_ok=True) @@ -1170,7 +1172,7 @@ def add_nodes(self, num_nodes: int, extra_args=None, *, rpchost=None, binary=Non old_num_nodes = len(self.nodes) super().add_nodes(num_nodes, extra_args, rpchost=rpchost, binary=binary, binary_cli=binary_cli, versions=versions) for i in range(old_num_nodes, old_num_nodes + num_nodes): - append_config(self.nodes[i].datadir, ["dip3params=2:2"]) + append_config(self.nodes[i].datadir, ["dip3params=2:2", f"testactivationheight=v20@{self.v20_height}"]) if old_num_nodes == 0: # controller node is the only node that has an extra option allowing it to submit sporks append_config(self.nodes[0].datadir, ["sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"]) @@ -1190,6 +1192,7 @@ def set_dash_test_params(self, num_nodes, masterodes_count, extra_args=None, evo self.num_nodes = num_nodes self.mninfo = [] self.setup_clean_chain = True + self.v20_height = 100 # additional args if extra_args is None: extra_args = [[]] * num_nodes @@ -1207,6 +1210,9 @@ def set_dash_test_params(self, num_nodes, masterodes_count, extra_args=None, evo self.quorum_data_request_expiration_timeout = 360 + def delay_v20(self, height=None): + self.v20_height = height + def activate_by_name(self, name, expected_activation_height=None, slow_mode=True): assert not softfork_active(self.nodes[0], name) self.log.info("Wait for " + name + " activation") From 3d67e7daabe6b2beab65a0cf78d2c8c3f25c6731 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sun, 11 May 2025 17:25:21 +0700 Subject: [PATCH 02/10] fix: require v20 fork activated for reallocation block reward to credit pool It is appliable for test networks which could have custom height of forks --- src/evo/creditpool.cpp | 2 +- src/masternode/payments.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/evo/creditpool.cpp b/src/evo/creditpool.cpp index ce90cce4de6a..f74c4ff7d5fa 100644 --- a/src/evo/creditpool.cpp +++ b/src/evo/creditpool.cpp @@ -243,7 +243,7 @@ CCreditPoolDiff::CCreditPoolDiff(CCreditPool starter, const CBlockIndex* pindexP assert(pindexPrev); if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_MN_RR)) { - // We consider V20 active if mn_rr is active + // No credit pool exists before V20. platformReward = PlatformShare(GetMasternodePayment(pindexPrev->nHeight + 1, blockSubsidy, /*fV20Active=*/ true)); } } diff --git a/src/masternode/payments.cpp b/src/masternode/payments.cpp index b90dc4193616..b29fd3350d33 100644 --- a/src/masternode/payments.cpp +++ b/src/masternode/payments.cpp @@ -41,7 +41,9 @@ CAmount PlatformShare(const CAmount reward) bool fV20Active = DeploymentActiveAfter(pindexPrev, m_consensus_params, Consensus::DEPLOYMENT_V20); CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockSubsidy + feeReward, fV20Active); - if (DeploymentActiveAfter(pindexPrev, m_consensus_params, Consensus::DEPLOYMENT_MN_RR)) { + // Credit Pool doesn't exist before V20. If any part of reward will re-allocated to credit pool before v20 + // activation these fund will be just permanently lost. Applyable for devnets, regtest, testnet + if (fV20Active && DeploymentActiveAfter(pindexPrev, m_consensus_params, Consensus::DEPLOYMENT_MN_RR)) { CAmount masternodeSubsidyReward = GetMasternodePayment(nBlockHeight, blockSubsidy, fV20Active); const CAmount platformReward = PlatformShare(masternodeSubsidyReward); masternodeReward -= platformReward; From 080207eb878d62866aace523e6ac7166535d0d90 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sun, 11 May 2025 17:27:34 +0700 Subject: [PATCH 03/10] test: speed-up feature_asset_locks.py functional test by generating less blocks --- test/functional/feature_asset_locks.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/functional/feature_asset_locks.py b/test/functional/feature_asset_locks.py index 7dc7dbc8d6a3..d6696355e504 100755 --- a/test/functional/feature_asset_locks.py +++ b/test/functional/feature_asset_locks.py @@ -54,7 +54,7 @@ def set_test_params(self): self.set_dash_test_params(2, 0, [[ "-whitelist=127.0.0.1", "-llmqtestinstantsenddip0024=llmq_test_instantsend", - "-testactivationheight=mn_rr@1400", + "-testactivationheight=mn_rr@620", ]] * 2, evo_count=2) def skip_test_if_missing_module(self): @@ -620,10 +620,9 @@ def test_withdrawal_limits(self, node_wallet, node, pubkey): def test_mn_rr(self, node_wallet, node, pubkey): - self.log.info(node_wallet.getblockcount()) self.log.info("Activate mn_rr...") locked = self.get_credit_pool_balance() - self.activate_mn_rr(expected_activation_height=1400) + self.activate_mn_rr(expected_activation_height=620) self.log.info(f'mn-rr height: {node.getblockcount()} credit: {self.get_credit_pool_balance()}') assert_equal(locked, self.get_credit_pool_balance()) @@ -635,7 +634,7 @@ def test_mn_rr(self, node_wallet, node, pubkey): all_mn_rewards = platform_reward + owner_reward + operator_reward assert_equal(all_mn_rewards, bt['coinbasevalue'] * 3 // 4) # 75/25 mn/miner reward split assert_equal(platform_reward, all_mn_rewards * 375 // 1000) # 0.375 platform share - assert_equal(platform_reward, 57741807) + assert_equal(platform_reward, 104549943) assert_equal(locked, self.get_credit_pool_balance()) self.generate(node, 1) locked += platform_reward From 046d5eef6a56c9e6953e495b6823a211077c506c Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sun, 11 May 2025 13:27:32 +0700 Subject: [PATCH 04/10] feat: activate mn_rr fork from block 1 on RegTest --- src/chainparams.cpp | 2 +- src/test/util/setup_common.cpp | 2 +- test/functional/rpc_masternode.py | 23 +++++++++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e9cd070f24cc..19cf82e16958 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -796,7 +796,7 @@ class CRegTestParams : public CChainParams { consensus.DIP0024QuorumsHeight = 1; // Always have dip0024 quorums unless overridden consensus.V19Height = 1; // Always active unless overriden consensus.V20Height = consensus.DIP0003Height; // Active not earlier than dip0003. Functional tests (DashTestFramework) uses height 100 (same as coinbase maturity) - consensus.MN_RRHeight = 900; + consensus.MN_RRHeight = 1; consensus.MinBIP9WarningHeight = 0; consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1 consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index de6adc03eb52..54d36e8df3b0 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -399,7 +399,7 @@ TestChainSetup::TestChainSetup(int num_blocks, const std::vector& e /*TestChainBRRBeforeActivationSetup=*/ { 497, uint256S("0x0857a9b5db51835b1c828f019f4c664b5fe6c28ac44a6d868436930f832d31e5") }, /*TestChainV19BeforeActivationSetup=*/ - { 494, uint256S("72c5b8760d9070ca3b6402094dcea76cd25806bc20d1bf3777a7be712e17bbd2") }, + { 494, uint256S("0x06ec12cb5419daf83e04455a24ff8f27fef76cfdbd3e8723ca4946fab91a2f11") }, } }; diff --git a/test/functional/rpc_masternode.py b/test/functional/rpc_masternode.py index d194da8bbc61..a87b114f6adb 100755 --- a/test/functional/rpc_masternode.py +++ b/test/functional/rpc_masternode.py @@ -32,17 +32,24 @@ def run_test(self): assert_equal(len(payments), 1) payments_block = payments[0] payments_block_payees = payments_block["masternodes"][0]["payees"] + + num_payees = 0 payments_payee = "" for i in range(0, len(payments_block_payees)): + if i == 0: + assert_equal(payments_block_payees[i]['script'], '6a') + continue + payments_payee += payments_block_payees[i]["address"] if i < len(payments_block_payees) - 1: payments_payee += ", " + num_payees += 1 assert_equal(payments_block["height"], height) assert_equal(payments_block["blockhash"], blockhash) assert_equal(winners_payee, payments_payee) - if len(payments_block_payees) == 1: + if num_payees == 1: checked_0_operator_reward = True - if len(payments_block_payees) > 1: + if num_payees > 1: checked_non_0_operator_reward = True self.log.info("test various `payments` RPC options") @@ -73,15 +80,15 @@ def run_test(self): while not checked_0_operator_reward or not checked_non_0_operator_reward: payments_masternode = self.nodes[0].masternode("payments")[0]["masternodes"][0] protx_info = self.nodes[0].protx("info", payments_masternode["proTxHash"]) - if len(payments_masternode["payees"]) == 1: - assert_equal(protx_info["state"]["payoutAddress"], payments_masternode["payees"][0]["address"]) + if len(payments_masternode["payees"]) == 2: + assert_equal(protx_info["state"]["payoutAddress"], payments_masternode["payees"][1]["address"]) checked_0_operator_reward = True else: - assert_equal(len(payments_masternode["payees"]), 2) - option1 = protx_info["state"]["payoutAddress"] == payments_masternode["payees"][0]["address"] and \ + assert_equal(len(payments_masternode["payees"]), 3) + option1 = protx_info["state"]["payoutAddress"] == payments_masternode["payees"][1]["address"] and \ + protx_info["state"]["operatorPayoutAddress"] == payments_masternode["payees"][2]["address"] + option2 = protx_info["state"]["payoutAddress"] == payments_masternode["payees"][2]["address"] and \ protx_info["state"]["operatorPayoutAddress"] == payments_masternode["payees"][1]["address"] - option2 = protx_info["state"]["payoutAddress"] == payments_masternode["payees"][1]["address"] and \ - protx_info["state"]["operatorPayoutAddress"] == payments_masternode["payees"][0]["address"] assert option1 or option2 checked_non_0_operator_reward = True self.generate(self.nodes[0], 1, sync_fun=self.no_op) From 2127f997c1e378385f8b3a2b95423c6d822447b3 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 12 May 2025 03:38:52 +0700 Subject: [PATCH 05/10] test: adjust activation heights on rpc_blockchain.py for v20 and mn_rr --- test/functional/rpc_blockchain.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index c28585c61f99..602af357cb37 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -185,8 +185,8 @@ def _test_getblockchaininfo(self): '-testactivationheight=dip0024@13', '-testactivationheight=brr@14', '-testactivationheight=v19@15', - '-testactivationheight=v20@901', - '-testactivationheight=mn_rr@902', + '-testactivationheight=v20@412', # no earlier than DIP0003 + '-testactivationheight=mn_rr@16', ]) res = self.nodes[0].getblockchaininfo() @@ -212,8 +212,8 @@ def _test_getblockchaininfo(self): 'dip0024': { 'type': 'buried', 'active': True, 'height': 13}, 'realloc': { 'type': 'buried', 'active': True, 'height': 14}, 'v19': { 'type': 'buried', 'active': True, 'height': 15}, - 'v20': { 'type': 'buried', 'active': False, 'height': 901}, - 'mn_rr': { 'type': 'buried', 'active': False, 'height': 902}, + 'v20': { 'type': 'buried', 'active': False, 'height': 412}, + 'mn_rr': { 'type': 'buried', 'active': True, 'height': 16}, 'withdrawals': { 'type': 'bip9', 'bip9': { From fd32e5785f3bb21a5fcb1c52df6bced4125e1fb0 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 12 May 2025 19:24:37 +0700 Subject: [PATCH 06/10] fix: update number of blocks before pruning for feature_index_prune.py --- test/functional/feature_index_prune.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 6f8605c6075b..2df936d554e9 100755 --- a/test/functional/feature_index_prune.py +++ b/test/functional/feature_index_prune.py @@ -11,7 +11,6 @@ ) from test_framework.governance import EXPECTED_STDERR_NO_GOV_PRUNE -# TODO: remove testactivationheight=v20@3000 when it will be activated from block 1 DEPLOYMENT_ARGS = ["-testactivationheight=v20@3000", "-dip3params=3000:3000"] class FeatureIndexPruneTest(BitcoinTestFramework): @@ -145,7 +144,7 @@ def run_test(self): for node in self.nodes[:2]: with node.assert_debug_log(['limited pruning to height 2489']): pruneheight_new = node.pruneblockchain(2500) - assert_equal(pruneheight_new, 2125) + assert_equal(pruneheight_new, 2196) self.log.info("ensure that prune locks don't prevent indices from failing in a reorg scenario") with self.nodes[0].assert_debug_log(['basic block filter index prune lock moved back to 2480']): From 96e9cefab4c56339dcc9913d2f2d866896380d34 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 13 May 2025 21:07:06 +0700 Subject: [PATCH 07/10] fix: adjust rpc_blockchin.py functional test --- test/functional/rpc_blockchain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 602af357cb37..eb0bb2061ec1 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -186,7 +186,7 @@ def _test_getblockchaininfo(self): '-testactivationheight=brr@14', '-testactivationheight=v19@15', '-testactivationheight=v20@412', # no earlier than DIP0003 - '-testactivationheight=mn_rr@16', + '-testactivationheight=mn_rr@413', ]) res = self.nodes[0].getblockchaininfo() @@ -213,7 +213,7 @@ def _test_getblockchaininfo(self): 'realloc': { 'type': 'buried', 'active': True, 'height': 14}, 'v19': { 'type': 'buried', 'active': True, 'height': 15}, 'v20': { 'type': 'buried', 'active': False, 'height': 412}, - 'mn_rr': { 'type': 'buried', 'active': True, 'height': 16}, + 'mn_rr': { 'type': 'buried', 'active': False, 'height': 413}, 'withdrawals': { 'type': 'bip9', 'bip9': { From 5c3b284dd53eba3fc9a9460e58d8d601c11ad1f5 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 14 May 2025 14:04:05 +0700 Subject: [PATCH 08/10] doc: edit commentary about Credit Pool existance --- src/evo/creditpool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evo/creditpool.cpp b/src/evo/creditpool.cpp index f74c4ff7d5fa..54a0c194bab9 100644 --- a/src/evo/creditpool.cpp +++ b/src/evo/creditpool.cpp @@ -243,7 +243,7 @@ CCreditPoolDiff::CCreditPoolDiff(CCreditPool starter, const CBlockIndex* pindexP assert(pindexPrev); if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_MN_RR)) { - // No credit pool exists before V20. + // If credit pool exists, it means v20 is activated platformReward = PlatformShare(GetMasternodePayment(pindexPrev->nHeight + 1, blockSubsidy, /*fV20Active=*/ true)); } } From 1ac16283cc72be6765e98abf025cdcf0e9db7e0a Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 14 May 2025 14:32:34 +0700 Subject: [PATCH 09/10] test: simplify calculation of num payees --- test/functional/rpc_masternode.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/functional/rpc_masternode.py b/test/functional/rpc_masternode.py index a87b114f6adb..fa9799f7a7a8 100755 --- a/test/functional/rpc_masternode.py +++ b/test/functional/rpc_masternode.py @@ -33,7 +33,6 @@ def run_test(self): payments_block = payments[0] payments_block_payees = payments_block["masternodes"][0]["payees"] - num_payees = 0 payments_payee = "" for i in range(0, len(payments_block_payees)): if i == 0: @@ -43,10 +42,10 @@ def run_test(self): payments_payee += payments_block_payees[i]["address"] if i < len(payments_block_payees) - 1: payments_payee += ", " - num_payees += 1 assert_equal(payments_block["height"], height) assert_equal(payments_block["blockhash"], blockhash) assert_equal(winners_payee, payments_payee) + num_payees = len(payments_block_payees) - 1 if num_payees == 1: checked_0_operator_reward = True if num_payees > 1: From ef5cde597843203303f6daeec23b88f07df2cc7e Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Wed, 14 May 2025 16:08:31 +0300 Subject: [PATCH 10/10] feat: enforce mn_rr activation after v20 on regtest Also group Dash-specific args at the end of the list in affected tests while at it. --- src/chainparams.cpp | 3 ++- test/functional/feature_asset_locks.py | 2 +- test/functional/feature_assumevalid.py | 7 ++++++- test/functional/feature_block.py | 3 ++- test/functional/feature_cltv.py | 5 +++-- test/functional/feature_csv_activation.py | 5 +++-- test/functional/feature_dersig.py | 5 +++-- test/functional/feature_dip4_coinbasemerkleroots.py | 2 +- test/functional/feature_governance.py | 2 +- test/functional/feature_index_prune.py | 6 +++++- test/functional/feature_llmq_chainlocks.py | 2 +- test/functional/feature_llmq_evo.py | 3 ++- test/functional/feature_llmq_is_cl_conflicts.py | 3 ++- test/functional/feature_llmq_rotation.py | 2 +- test/functional/feature_llmq_simplepose.py | 2 +- test/functional/feature_pruning.py | 1 + test/functional/p2p_ibd_stalling.py | 6 +++++- test/functional/test_framework/test_framework.py | 11 +++++++++-- 18 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 19cf82e16958..e8f8353480eb 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -796,7 +796,7 @@ class CRegTestParams : public CChainParams { consensus.DIP0024QuorumsHeight = 1; // Always have dip0024 quorums unless overridden consensus.V19Height = 1; // Always active unless overriden consensus.V20Height = consensus.DIP0003Height; // Active not earlier than dip0003. Functional tests (DashTestFramework) uses height 100 (same as coinbase maturity) - consensus.MN_RRHeight = 1; + consensus.MN_RRHeight = consensus.V20Height; // MN_RR does not really have effect before v20 activation consensus.MinBIP9WarningHeight = 0; consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1 consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day @@ -922,6 +922,7 @@ class CRegTestParams : public CChainParams { UpdateLLMQTestParametersFromArgs(args, Consensus::LLMQType::LLMQ_TEST_PLATFORM); UpdateLLMQInstantSendDIP0024FromArgs(args); assert(consensus.V20Height >= consensus.DIP0003Height); + assert(consensus.MN_RRHeight >= consensus.V20Height); } /** diff --git a/test/functional/feature_asset_locks.py b/test/functional/feature_asset_locks.py index d6696355e504..e196e06e2845 100755 --- a/test/functional/feature_asset_locks.py +++ b/test/functional/feature_asset_locks.py @@ -54,8 +54,8 @@ def set_test_params(self): self.set_dash_test_params(2, 0, [[ "-whitelist=127.0.0.1", "-llmqtestinstantsenddip0024=llmq_test_instantsend", - "-testactivationheight=mn_rr@620", ]] * 2, evo_count=2) + self.mn_rr_height = 620 def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 1d0b02271187..76e95c75fc50 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -62,7 +62,12 @@ class AssumeValidTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - self.extra_args = ["-dip3params=9000:9000", '-testactivationheight=v20@9000', "-checkblockindex=0"] + self.extra_args = [ + "-dip3params=9000:9000", + '-testactivationheight=v20@9000', + '-testactivationheight=mn_rr@9000', + "-checkblockindex=0", + ] self.rpc_timeout = 120 def setup_network(self): diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 6eca88d3813c..bc7a45d7e903 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -90,11 +90,12 @@ def set_test_params(self): # which causes RPC to hang, so we need to increase RPC timeouts self.rpc_timeout = 180 self.extra_args = [[ - '-dip3params=2000:2000', # Must set '-dip3params=2000:2000' to create pre-dip3 blocks only '-acceptnonstdtxn=1', # This is a consensus block test, we don't care about tx policy '-testactivationheight=bip34@2', + '-dip3params=2000:2000', # Must set '-dip3params=2000:2000' to create pre-dip3 blocks only '-testactivationheight=dip0001@2000', '-testactivationheight=v20@2000', + '-testactivationheight=mn_rr@2000', ]] def setup_nodes(self): diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 5c4168d3a959..b5dcab324ba3 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -88,10 +88,11 @@ def set_test_params(self): self.extra_args = [[ f'-testactivationheight=cltv@{CLTV_HEIGHT}', '-whitelist=noban@127.0.0.1', - '-dip3params=9000:9000', - '-testactivationheight=v20@9000', # disabled for this test '-par=1', # Use only one script thread to get the exact reject reason for testing '-acceptnonstdtxn=1', # cltv_invalidate is nonstandard + '-dip3params=9000:9000', + '-testactivationheight=v20@9000', # disabled for this test + '-testactivationheight=mn_rr@9000', # disabled for this test ]] self.setup_clean_chain = True self.rpc_timeout = 480 diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index c4ab8027347a..a48aa5b6dc5a 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -99,10 +99,11 @@ def set_test_params(self): self.extra_args = [[ '-peertimeout=999999', # bump because mocktime might cause a disconnect otherwise '-whitelist=noban@127.0.0.1', - '-dip3params=2000:2000', - '-testactivationheight=v20@2000', f'-testactivationheight=csv@{CSV_ACTIVATION_HEIGHT}', '-par=1', # Use only one script thread to get the exact reject reason for testing + '-dip3params=2000:2000', + '-testactivationheight=v20@2000', + '-testactivationheight=mn_rr@2000', ]] self.supports_cli = False diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index e9e5cbce27f3..604a471c4da0 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -50,10 +50,11 @@ def set_test_params(self): self.num_nodes = 1 self.extra_args = [[ f'-testactivationheight=dersig@{DERSIG_HEIGHT}', - '-testactivationheight=v20@9000', # due to changes in CbTx '-whitelist=noban@127.0.0.1', - '-dip3params=9000:9000', '-par=1', # Use only one script thread to get the exact log msg for testing + '-dip3params=9000:9000', + '-testactivationheight=v20@9000', # due to changes in CbTx + '-testactivationheight=mn_rr@9000', # due to changes in CbTx ]] self.setup_clean_chain = True self.rpc_timeout = 240 diff --git a/test/functional/feature_dip4_coinbasemerkleroots.py b/test/functional/feature_dip4_coinbasemerkleroots.py index 002f00212e09..bda9d1aec008 100755 --- a/test/functional/feature_dip4_coinbasemerkleroots.py +++ b/test/functional/feature_dip4_coinbasemerkleroots.py @@ -47,7 +47,7 @@ class LLMQCoinbaseCommitmentsTest(DashTestFramework): def set_test_params(self): self.extra_args = [[ f'-testactivationheight=dip0008@{DIP0008_HEIGHT}', f'-testactivationheight=dip0024@{DIP0024_HEIGHT}', "-vbparams=testdummy:999999999999:999999999999" ]] * 4 self.set_dash_test_params(4, 3, extra_args = self.extra_args) - self.delay_v20(height=V20_HEIGHT) + self.delay_v20_and_mn_rr(height=V20_HEIGHT) def remove_masternode(self, idx): mn = self.mninfo[idx] diff --git a/test/functional/feature_governance.py b/test/functional/feature_governance.py index 357bd2ec8e47..666df3280dee 100755 --- a/test/functional/feature_governance.py +++ b/test/functional/feature_governance.py @@ -18,7 +18,7 @@ def set_test_params(self): self.set_dash_test_params(6, 5, [[ "-budgetparams=10:10:10", ]] * 6) - self.delay_v20(height=160) + self.delay_v20_and_mn_rr(height=160) def check_superblockbudget(self, v20_active): v20_state = self.nodes[0].getblockchaininfo()["softforks"]["v20"] diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 2df936d554e9..84d8bdd94e50 100755 --- a/test/functional/feature_index_prune.py +++ b/test/functional/feature_index_prune.py @@ -11,7 +11,11 @@ ) from test_framework.governance import EXPECTED_STDERR_NO_GOV_PRUNE -DEPLOYMENT_ARGS = ["-testactivationheight=v20@3000", "-dip3params=3000:3000"] +DEPLOYMENT_ARGS = [ + "-dip3params=3000:3000", + "-testactivationheight=v20@3000", + "-testactivationheight=mn_rr@3000", +] class FeatureIndexPruneTest(BitcoinTestFramework): def set_test_params(self): diff --git a/test/functional/feature_llmq_chainlocks.py b/test/functional/feature_llmq_chainlocks.py index eb2dbd13351f..b96ab4cfaef3 100755 --- a/test/functional/feature_llmq_chainlocks.py +++ b/test/functional/feature_llmq_chainlocks.py @@ -20,7 +20,7 @@ class LLMQChainLocksTest(DashTestFramework): def set_test_params(self): self.set_dash_test_params(5, 4) - self.delay_v20(height=200) + self.delay_v20_and_mn_rr(height=200) def run_test(self): # Connect all nodes to node1 so that we always have the whole network connected diff --git a/test/functional/feature_llmq_evo.py b/test/functional/feature_llmq_evo.py index 5e63dbb654e3..2263410968a5 100755 --- a/test/functional/feature_llmq_evo.py +++ b/test/functional/feature_llmq_evo.py @@ -45,8 +45,9 @@ def getmnlistdiff(self, baseBlockHash, blockHash): class LLMQEvoNodesTest(DashTestFramework): def set_test_params(self): - self.set_dash_test_params(5, 4, [["-testactivationheight=mn_rr@400"]] * 5, evo_count=5) + self.set_dash_test_params(5, 4, evo_count=5) self.set_dash_llmq_test_params(4, 4) + self.mn_rr_height = 400 def run_test(self): # Connect all nodes to node1 so that we always have the whole network connected diff --git a/test/functional/feature_llmq_is_cl_conflicts.py b/test/functional/feature_llmq_is_cl_conflicts.py index 66f98af047e2..022e0a51a376 100755 --- a/test/functional/feature_llmq_is_cl_conflicts.py +++ b/test/functional/feature_llmq_is_cl_conflicts.py @@ -49,8 +49,9 @@ def on_getdata(self, message): class LLMQ_IS_CL_Conflicts(DashTestFramework): def set_test_params(self): - self.set_dash_test_params(5, 4, [["-testactivationheight=mn_rr@2000"]] * 5) + self.set_dash_test_params(5, 4) self.set_dash_llmq_test_params(4, 4) + self.delay_v20_and_mn_rr(2000) self.supports_cli = False def run_test(self): diff --git a/test/functional/feature_llmq_rotation.py b/test/functional/feature_llmq_rotation.py index 6a3d1b891edb..984a6bb0cc6d 100755 --- a/test/functional/feature_llmq_rotation.py +++ b/test/functional/feature_llmq_rotation.py @@ -53,7 +53,7 @@ class LLMQQuorumRotationTest(DashTestFramework): def set_test_params(self): self.set_dash_test_params(9, 8) self.set_dash_llmq_test_params(4, 4) - self.delay_v20(height=900) + self.delay_v20_and_mn_rr(height=900) def run_test(self): llmq_type=103 diff --git a/test/functional/feature_llmq_simplepose.py b/test/functional/feature_llmq_simplepose.py index ee647250f57c..6d766ef80e66 100755 --- a/test/functional/feature_llmq_simplepose.py +++ b/test/functional/feature_llmq_simplepose.py @@ -22,7 +22,7 @@ def set_test_params(self): self.extra_args = [[ '-testactivationheight=dip0024@9999' ]] * 6 self.set_dash_test_params(6, 5) self.set_dash_llmq_test_params(5, 3) - self.delay_v20(height=9999) + self.delay_v20_and_mn_rr(height=9999) def add_options(self, parser): parser.add_argument("--disable-spork23", dest="disable_spork23", default=False, action="store_true", diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index 78fecfb9095e..4127fb6ff86d 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -38,6 +38,7 @@ "-testactivationheight=dip0001@2000", "-testactivationheight=dip0008@2000", "-testactivationheight=v20@2000", + "-testactivationheight=mn_rr@2000", ] def mine_large_blocks(node, n): diff --git a/test/functional/p2p_ibd_stalling.py b/test/functional/p2p_ibd_stalling.py index 58562839c3b7..8b5577374ca3 100755 --- a/test/functional/p2p_ibd_stalling.py +++ b/test/functional/p2p_ibd_stalling.py @@ -48,7 +48,11 @@ def on_getheaders(self, message): class P2PIBDStallingTest(BitcoinTestFramework): def set_test_params(self): self.disable_mocktime = True - self.extra_args = [["-dip3params=2000:2000", "-testactivationheight=v20@2000"]] + self.extra_args = [[ + "-dip3params=2000:2000", + "-testactivationheight=v20@2000", + "-testactivationheight=mn_rr@2000", + ]] self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 46c4223679e8..79c63e57361f 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -635,6 +635,7 @@ def dynamically_initialize_datadir(self, node_p2p_port, node_rpc_port): f.write("shrinkdebugfile=0\n") f.write("dip3params=2:2\n") f.write(f"testactivationheight=v20@{self.v20_height}\n") + f.write(f"testactivationheight=mn_rr@{self.mn_rr_height}\n") os.makedirs(os.path.join(new_data_dir, 'stderr'), exist_ok=True) os.makedirs(os.path.join(new_data_dir, 'stdout'), exist_ok=True) @@ -1172,7 +1173,11 @@ def add_nodes(self, num_nodes: int, extra_args=None, *, rpchost=None, binary=Non old_num_nodes = len(self.nodes) super().add_nodes(num_nodes, extra_args, rpchost=rpchost, binary=binary, binary_cli=binary_cli, versions=versions) for i in range(old_num_nodes, old_num_nodes + num_nodes): - append_config(self.nodes[i].datadir, ["dip3params=2:2", f"testactivationheight=v20@{self.v20_height}"]) + append_config(self.nodes[i].datadir, [ + "dip3params=2:2", + f"testactivationheight=v20@{self.v20_height}", + f"testactivationheight=mn_rr@{self.mn_rr_height}", + ]) if old_num_nodes == 0: # controller node is the only node that has an extra option allowing it to submit sporks append_config(self.nodes[0].datadir, ["sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"]) @@ -1193,6 +1198,7 @@ def set_dash_test_params(self, num_nodes, masterodes_count, extra_args=None, evo self.mninfo = [] self.setup_clean_chain = True self.v20_height = 100 + self.mn_rr_height = 100 # additional args if extra_args is None: extra_args = [[]] * num_nodes @@ -1210,8 +1216,9 @@ def set_dash_test_params(self, num_nodes, masterodes_count, extra_args=None, evo self.quorum_data_request_expiration_timeout = 360 - def delay_v20(self, height=None): + def delay_v20_and_mn_rr(self, height=None): self.v20_height = height + self.mn_rr_height = height def activate_by_name(self, name, expected_activation_height=None, slow_mode=True): assert not softfork_active(self.nodes[0], name)