Skip to content

Commit 45d55e7

Browse files
Merge #6832: test: various improvements for functional tests feature_llmq_{evo,rotation,chainlocks.py}
2024c65 test: refactor sleep_time as a param (Konstantin Akimov) 2903c11 test: reduce overhead in feature_llmq_evo.py: only 2 regular nodes, only 4 evo nodes, less blocks generated (Konstantin Akimov) af768e4 test: functional tests for RPC masternodelist if mode="evo" (Konstantin Akimov) 9c6c3b9 test: simplify feature_llmq_evo.py - drop IS support to followup #6430 (Konstantin Akimov) e42e4bf test: use self.mn_rr instead user provided param in activate_mn_rr (Konstantin Akimov) 3f3a272 test: generate less blocks in llmq_rotation.py (Konstantin Akimov) db09299 refactor: simplify feature_llmq_rotation.py by excluding llmq=102 (v17 activated) (Konstantin Akimov) 6b9c9af test: remove debug logs with quorum info from helper mine_cycle_quorum (Konstantin Akimov) 0f6cf13 refactor: wait 5seconds only once but not for each node in feature_llmq_chainlocks.py (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented These functional tests are one of the slowest to run with tsan on CI: feature_llmq_chainlocks.py | ✓ Passed | 301 s feature_llmq_evo.py | ✓ Passed | 198 s feature_llmq_rotation.py | ✓ Passed | 315 s ## What was done? ### feature_llmq_chainlocks.py It waits only once for all nodes to check missing chainlock; instead of waiting 5 second for each node. Used to be: wait->check->wait->check... Become: wait->check->check->check... ### feature_llmq_evo.py - improve testing of RPC `masternodelist` by checking results of `mode=evo` - removed leftover code to enable & disable IS by spork to follow-up #6430 - reduced amount of evo nodes (5->4) and masternodes (4 -> 2) as follow-up to #6430 as no more rotation quorum is needed - generate less blocks to activate mn_rr (400 -> 320) ### feature_llmq_rotation.py - fixed instability by disabling v17-activated quorum (type 102) which forbids to activate mn_rr on earlier height than 900 - activate mn_rr on height 300 to finish #6667 (which has not been possible before due to v17-activated quorum) ### test_framework Minor improvements and refactorings: - simplified `activate_mn_rr` - simplified `wait_for_chainlocked_block_all_nodes` by removing flag `expected` - disabled excessive logging in mine_cycle_quorum ## How Has This Been Tested? Run functional tests locally multiple times. Median time is improved: - `feature_llmq_chainlocks.py`: 120s -> 75s (localhost), 301s -> 105s (CI) - `feature_llmq_evo.py`: 108s -> 74s (localhost), 198s -> 118s (CI) - `feature_llmq_rotation.py`: 154s -> 93s (localhost), 315s -> 141s (CI) ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: utACK 2024c65 Tree-SHA512: 42bada5e86824b24cc5159fc4b9c897aa968c86393364e03c873ff0276cd7c15cde729838782d2a2ffb68682afe6da66117bd619b4326721f3c1609553bcdb30
2 parents 81a03b9 + 2024c65 commit 45d55e7

File tree

5 files changed

+51
-49
lines changed

5 files changed

+51
-49
lines changed

test/functional/feature_asset_locks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ def test_withdrawal_limits(self, node_wallet, node, pubkey):
624624
def test_mn_rr(self, node_wallet, node, pubkey):
625625
self.log.info("Activate mn_rr...")
626626
locked = self.get_credit_pool_balance()
627-
self.activate_mn_rr(expected_activation_height=560)
627+
self.activate_mn_rr()
628628
self.log.info(f'mn-rr height: {node.getblockcount()} credit: {self.get_credit_pool_balance()}')
629629
assert_equal(locked, self.get_credit_pool_balance())
630630

test/functional/feature_llmq_chainlocks.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@
1616
from test_framework.test_framework import DashTestFramework
1717
from test_framework.util import assert_equal, assert_raises_rpc_error, force_finish_mnsync
1818

19+
import time
1920

2021
class LLMQChainLocksTest(DashTestFramework):
2122
def set_test_params(self):
2223
self.set_dash_test_params(5, 4)
2324
self.delay_v20_and_mn_rr(height=200)
2425

26+
def sleep_and_assert_no_cl(self, block_hash, sleep_time=5):
27+
time.sleep(sleep_time)
28+
29+
for node in self.nodes:
30+
self.log.info(f"Expecting no ChainLock for {block_hash}")
31+
block = node.getblock(block_hash)
32+
#assert_equal(block["confirmations"], 0)
33+
assert not block["chainlock"]
34+
2535
def run_test(self):
2636
# Connect all nodes to node1 so that we always have the whole network connected
2737
# Otherwise only masternode connections will be established between nodes, which won't propagate TXs/blocks
@@ -84,7 +94,7 @@ def run_test(self):
8494
previous_block_hash = self.nodes[0].getbestblockhash()
8595
for _ in range(2):
8696
block_hash = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0]
87-
self.wait_for_chainlocked_block_all_nodes(block_hash, timeout=5, expected=False)
97+
self.sleep_and_assert_no_cl(block_hash)
8898
assert self.nodes[0].getblock(previous_block_hash)["chainlock"]
8999

90100
self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 0)

test/functional/feature_llmq_evo.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ def getmnlistdiff(self, baseBlockHash, blockHash):
4949

5050
class LLMQEvoNodesTest(DashTestFramework):
5151
def set_test_params(self):
52-
self.set_dash_test_params(5, 4, evo_count=5)
53-
self.set_dash_llmq_test_params(4, 4)
54-
self.mn_rr_height = 400
52+
# we just need a couple of regular nodes to be ensured that they are not included in platform quorum, 2 is enough
53+
self.set_dash_test_params(3, 2, evo_count=4)
54+
self.mn_rr_height = 320
5555

5656
def run_test(self):
5757
# Connect all nodes to node1 so that we always have the whole network connected
@@ -62,18 +62,12 @@ def run_test(self):
6262
null_hash = format(0, "064x")
6363

6464
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
65-
self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 1)
66-
self.wait_for_sporks_same()
6765

6866
expectedUpdated = [mn.proTxHash for mn in self.mninfo]
6967
b_0 = self.nodes[0].getbestblockhash()
7068
self.test_getmnlistdiff(null_hash, b_0, {}, [], expectedUpdated)
7169

72-
self.test_masternode_count(expected_mns_count=4, expected_evo_count=0)
73-
74-
self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 0)
75-
self.wait_for_sporks_same()
76-
70+
self.test_masternode_count(expected_mns_count=2, expected_evo_count=0)
7771
evo_protxhash_list = list()
7872
for i in range(self.evo_count):
7973
evo_info: MasternodeInfo = self.dynamically_add_masternode(evo=True)
@@ -84,7 +78,7 @@ def run_test(self):
8478
b_i = self.nodes[0].getbestblockhash()
8579
self.test_getmnlistdiff(null_hash, b_i, {}, [], expectedUpdated)
8680

87-
self.test_masternode_count(expected_mns_count=4, expected_evo_count=i+1)
81+
self.test_masternode_count(expected_mns_count=2, expected_evo_count=i+1)
8882
self.dynamically_evo_update_service(evo_info)
8983

9084
self.log.info("Test llmq_platform are formed only with EvoNodes")
@@ -100,7 +94,7 @@ def run_test(self):
10094
self.test_masternode_winners()
10195

10296
self.activate_mn_rr()
103-
self.log.info("Activated MN RewardReallocation, current height:" + str(self.nodes[0].getblockcount()))
97+
self.log.info(f"Activated MN RewardReallocation, current height: {self.nodes[0].getblockcount()}")
10498

10599
# Generate a few blocks to make EvoNode/MN analysis on a pure MN RewardReallocation window
106100
self.bump_mocktime(1)
@@ -110,10 +104,6 @@ def run_test(self):
110104
self.test_evo_payments(window_analysis=48, mnrr_active=True)
111105
self.test_masternode_winners(mn_rr_active=True)
112106

113-
self.log.info(self.nodes[0].masternodelist())
114-
115-
return
116-
117107
def test_evo_payments(self, window_analysis, mnrr_active):
118108
current_evo: MasternodeInfo = None
119109
consecutive_payments = 0
@@ -183,13 +173,21 @@ def test_quorum_members_are_evo_nodes(self, quorum_hash, llmq_type):
183173

184174
def test_evo_protx_are_in_mnlist(self, evo_protx_list):
185175
mn_list = self.nodes[0].masternodelist()
176+
mn_list_evo = self.nodes[0].masternodelist(mode="evo")
186177
for evo_protx in evo_protx_list:
187-
found = False
188-
for mn in mn_list:
189-
if mn_list.get(mn)['proTxHash'] == evo_protx:
190-
found = True
191-
assert_equal(mn_list.get(mn)['type'], "Evo")
192-
assert_equal(found, True)
178+
found_in_mns = False
179+
for _, mn in mn_list.items():
180+
if mn['proTxHash'] == evo_protx:
181+
found_in_mns = True
182+
assert_equal(mn['type'], "Evo")
183+
assert_equal(found_in_mns, True)
184+
185+
found_in_evos = False
186+
for _, mn in mn_list_evo.items():
187+
assert_equal(mn['type'], "Evo")
188+
if mn['proTxHash'] == evo_protx:
189+
found_in_evos = True
190+
assert_equal(found_in_evos, True)
193191

194192
def test_masternode_count(self, expected_mns_count, expected_evo_count):
195193
mn_count = self.nodes[0].masternode('count')

test/functional/feature_llmq_rotation.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ def getmnlistdiff(self, baseBlockHash, blockHash):
5151

5252
class LLMQQuorumRotationTest(DashTestFramework):
5353
def set_test_params(self):
54-
self.set_dash_test_params(9, 8)
54+
self.set_dash_test_params(9, 8, extra_args=[["-vbparams=testdummy:999999999999:999999999999"]] * 9)
5555
self.set_dash_llmq_test_params(4, 4)
56-
self.delay_v20_and_mn_rr(height=900)
56+
self.delay_v20_and_mn_rr(height=300)
5757

5858
def run_test(self):
5959
llmq_type=103
@@ -106,14 +106,8 @@ def run_test(self):
106106
expectedNew = [h_100_0, h_100_1]
107107
quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew, testQuorumsCLSigs=False)
108108

109-
projected_activation_height = 900
110-
111-
self.activate_v20(expected_activation_height=900)
112-
self.log.info("Activated v20 at height:" + str(self.nodes[0].getblockcount()))
113-
114-
softfork_info = self.nodes[0].getblockchaininfo()['softforks']['v20']
115-
assert_equal(softfork_info['active'], True)
116-
assert_equal(projected_activation_height, softfork_info['height'])
109+
self.activate_v20(expected_activation_height=self.mn_rr_height)
110+
self.log.info(f"Activated v20 at height: {self.nodes[0].getblockcount()}")
117111

118112
# v20 is active for the next block, not for the tip
119113
self.generate(self.nodes[0], 1)
@@ -161,13 +155,12 @@ def run_test(self):
161155
self.log.info("Quorum #0_1 members: " + str(quorum_members_0_1))
162156

163157
q_100_0 = QuorumId(100, int(quorum_info_0_0["quorumHash"], 16))
164-
q_102_0 = QuorumId(102, int(quorum_info_0_0["quorumHash"], 16))
165158
q_103_0_0 = QuorumId(103, int(quorum_info_0_0["quorumHash"], 16))
166159
q_103_0_1 = QuorumId(103, int(quorum_info_0_1["quorumHash"], 16))
167160

168161
b_1 = self.nodes[0].getbestblockhash()
169162
expectedDeleted = [h_100_0]
170-
expectedNew = [q_100_0, q_102_0, q_103_0_0, q_103_0_1]
163+
expectedNew = [q_100_0, q_103_0_0, q_103_0_1]
171164
quorumList = self.test_getmnlistdiff_quorums(b_0, b_1, quorumList, expectedDeleted, expectedNew)
172165

173166
self.log.info("Wait for chainlock")
@@ -183,13 +176,12 @@ def run_test(self):
183176
self.log.info("Quorum #1_1 members: " + str(quorum_members_1_1))
184177

185178
q_100_1 = QuorumId(100, int(quorum_info_1_0["quorumHash"], 16))
186-
q_102_1 = QuorumId(102, int(quorum_info_1_0["quorumHash"], 16))
187179
q_103_1_0 = QuorumId(103, int(quorum_info_1_0["quorumHash"], 16))
188180
q_103_1_1 = QuorumId(103, int(quorum_info_1_1["quorumHash"], 16))
189181

190182
b_2 = self.nodes[0].getbestblockhash()
191183
expectedDeleted = [h_100_1, q_103_0_0, q_103_0_1]
192-
expectedNew = [q_100_1, q_102_1, q_103_1_0, q_103_1_1]
184+
expectedNew = [q_100_1, q_103_1_0, q_103_1_1]
193185
quorumList = self.test_getmnlistdiff_quorums(b_1, b_2, quorumList, expectedDeleted, expectedNew)
194186

195187
mninfos_online = self.mninfo.copy()
@@ -374,7 +366,6 @@ def compute_mn_score(self, mn, modifier):
374366
def get_llmq_size(self, llmq_type):
375367
return {
376368
100: 4, # In this test size for llmqType 100 is overwritten to 4
377-
102: 3,
378369
103: 4,
379370
106: 3
380371
}.get(llmq_type, -1)

test/functional/test_framework/test_framework.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,8 +1566,8 @@ def activate_by_name(self, name, expected_activation_height=None, slow_mode=True
15661566
def activate_v20(self, expected_activation_height=None):
15671567
self.activate_by_name('v20', expected_activation_height)
15681568

1569-
def activate_mn_rr(self, expected_activation_height=None):
1570-
self.activate_by_name('mn_rr', expected_activation_height)
1569+
def activate_mn_rr(self):
1570+
self.activate_by_name('mn_rr', self.mn_rr_height)
15711571

15721572
def set_dash_llmq_test_params(self, llmq_size, llmq_threshold):
15731573
self.llmq_size = llmq_size
@@ -1941,9 +1941,9 @@ def check_chainlocked_block():
19411941
if self.wait_until(check_chainlocked_block, timeout=timeout, do_assert=expected) and not expected:
19421942
raise AssertionError("waiting unexpectedly succeeded")
19431943

1944-
def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15, expected=True):
1944+
def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15):
19451945
for node in self.nodes:
1946-
self.wait_for_chainlocked_block(node, block_hash, expected=expected, timeout=timeout)
1946+
self.wait_for_chainlocked_block(node, block_hash, timeout=timeout)
19471947

19481948
def wait_for_best_chainlock(self, node, block_hash, timeout=15):
19491949
self.wait_until(lambda: node.getbestchainlock()["blockhash"] == block_hash, timeout=timeout)
@@ -2300,13 +2300,16 @@ def mine_cycle_quorum(self):
23002300
self.log.info("New quorum: height=%d, quorumHash=%s, quorumIndex=%d, minedBlock=%s" % (quorum_info_0["height"], q_0, quorum_info_0["quorumIndex"], quorum_info_0["minedBlock"]))
23012301
self.log.info("New quorum: height=%d, quorumHash=%s, quorumIndex=%d, minedBlock=%s" % (quorum_info_1["height"], q_1, quorum_info_1["quorumIndex"], quorum_info_1["minedBlock"]))
23022302

2303-
self.log.info("quorum_info_0:"+str(quorum_info_0))
2304-
self.log.info("quorum_info_1:"+str(quorum_info_1))
2303+
extra_debug_rotation_info = False
2304+
if extra_debug_rotation_info:
2305+
# these logs are useful to debug quorum rotation but it is not usefull for all other cases
2306+
self.log.info("quorum_info_0:"+str(quorum_info_0))
2307+
self.log.info("quorum_info_1:"+str(quorum_info_1))
23052308

2306-
best_block_hash = self.nodes[0].getbestblockhash()
2307-
block_height = self.nodes[0].getblockcount()
2308-
quorum_rotation_info = self.nodes[0].quorum("rotationinfo", best_block_hash)
2309-
self.log.info("h("+str(block_height)+"):"+str(quorum_rotation_info))
2309+
best_block_hash = self.nodes[0].getbestblockhash()
2310+
block_height = self.nodes[0].getblockcount()
2311+
quorum_rotation_info = self.nodes[0].quorum("rotationinfo", best_block_hash)
2312+
self.log.info("h("+str(block_height)+"):"+str(quorum_rotation_info))
23102313

23112314
return (quorum_info_0, quorum_info_1)
23122315

0 commit comments

Comments
 (0)