From 7e0c2ca5a50df60de1e9ae7b2b7b5d8c0c70e4dd Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 23 Nov 2024 00:56:23 +0700 Subject: [PATCH 1/5] fix: make dynamic masternode register even without is-quorum replace wait-IS to bump time in test_framework --- test/functional/test_framework/test_framework.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index eb077611c6..933cb31452 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1313,7 +1313,7 @@ class DashTestFramework(BitcoinTestFramework): collateral_amount = EVONODE_COLLATERAL if evo else MASTERNODE_COLLATERAL outputs = {collateral_address: collateral_amount, funds_address: 1} collateral_txid = self.nodes[0].sendmany("", outputs) - self.wait_for_instantlock(collateral_txid, self.nodes[0]) + self.bump_mocktime(10 * 60 + 1) # to make tx safe to include in block tip = self.generate(self.nodes[0], 1)[0] rawtx = self.nodes[0].getrawtransaction(collateral_txid, 1, tip) @@ -1334,7 +1334,7 @@ class DashTestFramework(BitcoinTestFramework): else: protx_result = self.nodes[0].protx("register", collateral_txid, collateral_vout, ipAndPort, owner_address, bls['public'], voting_address, operatorReward, reward_address, funds_address, True) - self.wait_for_instantlock(protx_result, self.nodes[0]) + self.bump_mocktime(10 * 60 + 1) # to make tx safe to include in block tip = self.generate(self.nodes[0], 1)[0] assert_equal(self.nodes[0].getrawtransaction(protx_result, 1, tip)['confirmations'], 1) @@ -1356,14 +1356,14 @@ class DashTestFramework(BitcoinTestFramework): platform_http_port = '%d' % (r + 2) fund_txid = self.nodes[0].sendtoaddress(funds_address, 1) - self.wait_for_instantlock(fund_txid, self.nodes[0]) + self.bump_mocktime(10 * 60 + 1) # to make tx safe to include in block tip = self.generate(self.nodes[0], 1)[0] assert_equal(self.nodes[0].getrawtransaction(fund_txid, 1, tip)['confirmations'], 1) protx_success = False try: protx_result = self.nodes[0].protx('update_service_evo', evo_info.proTxHash, evo_info.addr, evo_info.keyOperator, platform_node_id, platform_p2p_port, platform_http_port, operator_reward_address, funds_address) - self.wait_for_instantlock(protx_result, self.nodes[0]) + self.bump_mocktime(10 * 60 + 1) # to make tx safe to include in block tip = self.generate(self.nodes[0], 1)[0] assert_equal(self.nodes[0].getrawtransaction(protx_result, 1, tip)['confirmations'], 1) self.log.info("Updated EvoNode %s: platformNodeID=%s, platformP2PPort=%s, platformHTTPPort=%s" % (evo_info.proTxHash, platform_node_id, platform_p2p_port, platform_http_port)) From 8ea45bbf69d4625819cadb98d2cb684d9e8163d1 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 23 Nov 2024 02:42:22 +0700 Subject: [PATCH 2/5] fix: make helper get_merkle_root works with no masternodes --- test/functional/test_framework/messages.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index ae2c405e6e..2d8bf01180 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -640,6 +640,8 @@ class CBlock(CBlockHeader): # Calculate the merkle root given a vector of transaction hashes @staticmethod def get_merkle_root(hashes): + if len(hashes) == 0: + return 0 while len(hashes) > 1: newhashes = [] for i in range(0, len(hashes), 2): From 129385d3490ae4e91bee7e02053f84e66854cb79 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 23 Nov 2024 13:59:53 +0700 Subject: [PATCH 3/5] feat: remove regular masternodes from feature_asset_locks tests --- test/functional/feature_asset_locks.py | 37 +++++++++++--------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/test/functional/feature_asset_locks.py b/test/functional/feature_asset_locks.py index a6ecb4debf..a69c217d57 100755 --- a/test/functional/feature_asset_locks.py +++ b/test/functional/feature_asset_locks.py @@ -49,11 +49,11 @@ HEIGHT_DIFF_EXPIRING = 48 class AssetLocksTest(DashTestFramework): def set_test_params(self): - self.set_dash_test_params(4, 2, [[ + self.set_dash_test_params(2, 0, [[ "-whitelist=127.0.0.1", "-llmqtestinstantsenddip0024=llmq_test_instantsend", "-testactivationheight=mn_rr@1400", - ]] * 4, evo_count=2) + ]] * 2, evo_count=2) def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -231,15 +231,14 @@ class AssetLocksTest(DashTestFramework): self.log.info(f"Generating batch of blocks {count} left") batch = min(50, count) count -= batch - self.bump_mocktime(batch) + self.bump_mocktime(10 * 60 + 1) self.generate(self.nodes[1], batch) # This functional test intentionally setup only 2 MN and only 2 Evo nodes # to ensure that corner case of quorum with minimum amount of nodes as possible # does not cause any issues in Dash Core - def mine_quorum_2_nodes(self, llmq_type_name, llmq_type): - self.mine_quorum(llmq_type_name=llmq_type_name, expected_members=2, expected_connections=1, expected_contributions=2, expected_commitments=2, llmq_type=llmq_type) - + def mine_quorum_2_nodes(self): + self.mine_quorum(llmq_type_name='llmq_test_platform', expected_members=2, expected_connections=1, expected_contributions=2, expected_commitments=2, llmq_type=106) def run_test(self): node_wallet = self.nodes[0] @@ -250,17 +249,9 @@ class AssetLocksTest(DashTestFramework): self.activate_v20(expected_activation_height=900) self.log.info("Activated v20 at height:" + str(node.getblockcount())) - self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 0) - self.wait_for_sporks_same() - - self.mine_quorum_2_nodes(llmq_type_name='llmq_test_instantsend', llmq_type=104) - for _ in range(2): self.dynamically_add_masternode(evo=True) - self.generate(node, 8, sync_fun=lambda: self.sync_blocks()) - self.set_sporks() - self.generate(node, 1) self.mempool_size = 0 key = ECKey() @@ -328,7 +319,7 @@ class AssetLocksTest(DashTestFramework): self.create_and_check_block([extra_lock_tx], expected_error = 'bad-cbtx-assetlocked-amount') self.log.info("Mine a quorum...") - self.mine_quorum_2_nodes(llmq_type_name='llmq_test_platform', llmq_type=106) + self.mine_quorum_2_nodes() self.validate_credit_pool_balance(locked_1) @@ -350,6 +341,10 @@ class AssetLocksTest(DashTestFramework): asset_unlock_tx_duplicate_index.vout[0].nValue += COIN too_late_height = node.getblockcount() + HEIGHT_DIFF_EXPIRING + self.log.info("Mine block to empty mempool") + self.bump_mocktime(10 * 60 + 1) + self.generate(self.nodes[0], 1) + self.check_mempool_result(tx=asset_unlock_tx, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}}) self.check_mempool_result(tx=asset_unlock_tx_too_big_fee, result_expected={'allowed': False, 'reject-reason' : 'max-fee-exceeded'}) @@ -417,7 +412,7 @@ class AssetLocksTest(DashTestFramework): reason = "double copy") self.log.info("Mining next quorum to check tx 'asset_unlock_tx_late' is still valid...") - self.mine_quorum_2_nodes(llmq_type_name='llmq_test_platform', llmq_type=106) + self.mine_quorum_2_nodes() self.log.info("Checking credit pool amount is same...") self.validate_credit_pool_balance(locked - 1 * COIN) self.check_mempool_result(tx=asset_unlock_tx_late, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}}) @@ -435,7 +430,7 @@ class AssetLocksTest(DashTestFramework): result_expected={'allowed': False, 'reject-reason' : 'bad-assetunlock-too-late'}) self.log.info("Checking that two quorums later it is too late because quorum is not active...") - self.mine_quorum_2_nodes(llmq_type_name='llmq_test_platform', llmq_type=106) + self.mine_quorum_2_nodes() self.log.info("Expecting new reject-reason...") assert not softfork_active(self.nodes[0], 'withdrawals') self.check_mempool_result(tx=asset_unlock_tx_too_late, @@ -513,7 +508,7 @@ class AssetLocksTest(DashTestFramework): self.log.info("Fast forward to the next day to reset all current unlock limits...") self.generate_batch(blocks_in_one_day) - self.mine_quorum_2_nodes(llmq_type_name='llmq_test_platform', llmq_type=106) + self.mine_quorum_2_nodes() total = self.get_credit_pool_balance() coins = node_wallet.listunspent() @@ -669,12 +664,12 @@ class AssetLocksTest(DashTestFramework): while quorumHash_str != node_wallet.quorum('list')['llmq_test_platform'][-1]: self.log.info("Generate one more quorum until signing quorum becomes the last one in the list") - self.mine_quorum_2_nodes(llmq_type_name="llmq_test_platform", llmq_type=106) + self.mine_quorum_2_nodes() self.check_mempool_result(tx=asset_unlock_tx, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}}) self.log.info("Generate one more quorum after which signing quorum is gone but Asset Unlock tx is still valid") assert quorumHash_str in node_wallet.quorum('list')['llmq_test_platform'] - self.mine_quorum_2_nodes(llmq_type_name="llmq_test_platform", llmq_type=106) + self.mine_quorum_2_nodes() assert quorumHash_str not in node_wallet.quorum('list')['llmq_test_platform'] if asset_unlock_tx_payload.requestedHeight + HEIGHT_DIFF_EXPIRING > node_wallet.getblockcount(): @@ -686,7 +681,7 @@ class AssetLocksTest(DashTestFramework): index += 1 self.log.info("Generate one more quorum after which signing quorum becomes too old") - self.mine_quorum_2_nodes(llmq_type_name="llmq_test_platform", llmq_type=106) + self.mine_quorum_2_nodes() self.check_mempool_result(tx=asset_unlock_tx, result_expected={'allowed': False, 'reject-reason': 'bad-assetunlock-too-old-quorum'}) asset_unlock_tx = self.create_assetunlock(520, 2000 * COIN + 1, pubkey) From 70ba007f1a3983ba0ffdc0152df3590ab23951e8 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 26 Nov 2024 20:03:16 +0700 Subject: [PATCH 4/5] feat: do not mine extra quorum in feature_llmq_evo.py --- test/functional/feature_llmq_evo.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/functional/feature_llmq_evo.py b/test/functional/feature_llmq_evo.py index bc2d63707a..613e0ea58e 100755 --- a/test/functional/feature_llmq_evo.py +++ b/test/functional/feature_llmq_evo.py @@ -76,15 +76,6 @@ class LLMQEvoNodesTest(DashTestFramework): self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 0) self.wait_for_sporks_same() - self.move_to_next_cycle() - self.log.info("Cycle H height:" + str(self.nodes[0].getblockcount())) - self.move_to_next_cycle() - self.log.info("Cycle H+C height:" + str(self.nodes[0].getblockcount())) - self.move_to_next_cycle() - self.log.info("Cycle H+2C height:" + str(self.nodes[0].getblockcount())) - - self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103) - evo_protxhash_list = list() for i in range(self.evo_count): evo_info = self.dynamically_add_masternode(evo=True) From 37fbdee1d953cbb90cdd626385e91a876c19a57f Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 26 Nov 2024 20:08:50 +0700 Subject: [PATCH 5/5] feat: do not mine extra quorum in feature_dip3_v19.py --- test/functional/feature_dip3_v19.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/test/functional/feature_dip3_v19.py b/test/functional/feature_dip3_v19.py index adeec5c818..cdf4cdef36 100755 --- a/test/functional/feature_dip3_v19.py +++ b/test/functional/feature_dip3_v19.py @@ -75,18 +75,8 @@ class DIP3V19Test(DashTestFramework): self.log.info("pubkeyoperator should still be shown using legacy scheme") assert_equal(pubkeyoperator_list_before, pubkeyoperator_list_after) - self.move_to_next_cycle() - self.log.info("Cycle H height:" + str(self.nodes[0].getblockcount())) - self.move_to_next_cycle() - self.log.info("Cycle H+C height:" + str(self.nodes[0].getblockcount())) - self.move_to_next_cycle() - self.log.info("Cycle H+2C height:" + str(self.nodes[0].getblockcount())) - - self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103) - evo_info_0 = self.dynamically_add_masternode(evo=True, rnd=7) assert evo_info_0 is not None - self.generate(self.nodes[0], 8, sync_fun=lambda: self.sync_blocks()) self.log.info("Checking that protxs with duplicate EvoNodes fields are rejected") evo_info_1 = self.dynamically_add_masternode(evo=True, rnd=7, should_be_rejected=True) @@ -96,7 +86,6 @@ class DIP3V19Test(DashTestFramework): assert evo_info_2 is None evo_info_3 = self.dynamically_add_masternode(evo=True, rnd=9) assert evo_info_3 is not None - self.generate(self.nodes[0], 8, sync_fun=lambda: self.sync_blocks()) self.dynamically_evo_update_service(evo_info_0, 9, should_be_rejected=True) revoke_protx = self.mninfo[-1].proTxHash @@ -123,12 +112,12 @@ class DIP3V19Test(DashTestFramework): def test_revoke_protx(self, node_idx, revoke_protx, revoke_keyoperator): funds_address = self.nodes[0].getnewaddress() fund_txid = self.nodes[0].sendtoaddress(funds_address, 1) - self.wait_for_instantlock(fund_txid, self.nodes[0]) + self.bump_mocktime(10 * 60 + 1) # to make tx safe to include in block tip = self.generate(self.nodes[0], 1)[0] assert_equal(self.nodes[0].getrawtransaction(fund_txid, 1, tip)['confirmations'], 1) protx_result = self.nodes[0].protx('revoke', revoke_protx, revoke_keyoperator, 1, funds_address) - self.wait_for_instantlock(protx_result, self.nodes[0]) + self.bump_mocktime(10 * 60 + 1) # to make tx safe to include in block tip = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0] assert_equal(self.nodes[0].getrawtransaction(protx_result, 1, tip)['confirmations'], 1) # Revoking a MN results in disconnects. Wait for disconnects to actually happen