Skip to content

Commit ab42708

Browse files
committed
feat: use single-node quorum for feature_llmq_chainlocks_automatic; isolate node-1 (NOT Masternode) to avoid intermittent random failures
1 parent 2e60be9 commit ab42708

File tree

3 files changed

+25
-41
lines changed

3 files changed

+25
-41
lines changed

test/functional/feature_llmq_chainlocks_automatic.py

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,11 @@
1919

2020
class LLMQChainLocksAutomaticTest(DashTestFramework):
2121
def set_test_params(self):
22-
self.set_dash_test_params(6, 5)
22+
self.set_dash_test_params(3, 1)
23+
self.set_dash_llmq_test_params(1, 1)
2324
self.delay_v20_and_mn_rr(height=200)
2425

2526
def run_test(self):
26-
# Connect all nodes to node1 so that we always have the whole network connected
27-
for i in range(2, len(self.nodes)):
28-
self.connect_nodes(i, 1)
29-
3027
self.log.info("Wait for initial sync and activate v20")
3128
self.test_coinbase_best_cl(self.nodes[0], expected_cl_in_cb=False)
3229
self.activate_v20(expected_activation_height=200)
@@ -39,7 +36,7 @@ def run_test(self):
3936

4037
# Mine enough blocks to create a quorum
4138
self.log.info("Mine blocks to create first quorum")
42-
self.mine_quorum()
39+
self.mine_single_node_quorum()
4340

4441
self.log.info("Test automatic chainlock detection from coinbase transactions")
4542
self.test_automatic_chainlock_detection()
@@ -54,6 +51,7 @@ def test_automatic_chainlock_detection(self):
5451
"""Test that chainlocks embedded in coinbase transactions are automatically detected and processed"""
5552

5653
# Get the current chain state
54+
self.wait_for_chainlocked_block(self.nodes[0], self.nodes[0].getbestblockhash())
5755
initial_best_cl = self.nodes[0].getbestchainlock()
5856
initial_height = self.nodes[0].getblockcount()
5957

@@ -62,8 +60,8 @@ def test_automatic_chainlock_detection(self):
6260
# Mine a few blocks to generate some chainlocks
6361
self.log.info("Mining blocks to generate chainlocks...")
6462
for i in range(5):
65-
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
66-
time.sleep(0.1) # Small delay to allow chainlock processing
63+
h = self.generate(self.nodes[0], 1, sync_fun=self.no_op)
64+
self.wait_for_chainlocked_block(self.nodes[0], h[0])
6765

6866
# Wait for chainlocks to be created and processed
6967
self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash())
@@ -145,12 +143,12 @@ def test_automatic_detection_edge_cases(self):
145143
# Test with node isolation and reconnection
146144
self.log.info("Testing automatic detection with node isolation...")
147145

148-
# Isolate node 5 and mine some blocks
149-
self.isolate_node(5)
150-
isolated_blocks = self.generate(self.nodes[5], 2, sync_fun=self.no_op)
146+
# Isolate node 1 and mine some blocks
147+
self.isolate_node(1)
148+
isolated_blocks = self.generate(self.nodes[1], 2, sync_fun=self.no_op)
151149

152150
# Reconnect and see if automatic detection still works
153-
self.reconnect_isolated_node(5, 1)
151+
self.reconnect_isolated_node(1, 0)
154152

155153
# Mine a block on the main chain that should cause reorganization
156154
main_block = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0]
@@ -188,19 +186,5 @@ def test_coinbase_best_cl(self, node, expected_cl_in_cb=True, expected_null_cl=F
188186
# Verify CL signature
189187
assert node.verifychainlock(target_block_hash, best_cl_signature, best_cl_height)
190188

191-
def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15):
192-
"""Wait for a specific block to be chainlocked on all nodes"""
193-
for node in self.nodes:
194-
wait_until_helper(lambda: self.is_block_chainlocked(node, block_hash), timeout=timeout)
195-
196-
def is_block_chainlocked(self, node, block_hash):
197-
"""Check if a block is chainlocked on a specific node"""
198-
try:
199-
block = node.getblock(block_hash, 1)
200-
return block.get("chainlock", False)
201-
except:
202-
return False
203-
204-
205189
if __name__ == '__main__':
206190
LLMQChainLocksAutomaticTest().main()

test/functional/feature_llmq_singlenode.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,6 @@ def set_test_params(self):
3838
self.set_dash_llmq_test_params(1, 1)
3939

4040

41-
def mine_single_node_quorum(self):
42-
node = self.nodes[0]
43-
quorums = node.quorum('list')['llmq_test']
44-
45-
skip_count = 24 - (self.nodes[0].getblockcount() % 24)
46-
if skip_count != 0:
47-
self.bump_mocktime(1)
48-
self.generate(self.nodes[0], skip_count)
49-
time.sleep(1)
50-
self.generate(self.nodes[0], 30)
51-
new_quorums_list = node.quorum('list')['llmq_test']
52-
53-
self.log.info(f"Test Quorums at height={node.getblockcount()} : {new_quorums_list}")
54-
assert new_quorums_list != quorums
55-
5641
def check_sigs(self, hasrecsigs, isconflicting1, isconflicting2):
5742
has_sig = False
5843
conflicting_1 = False

test/functional/test_framework/test_framework.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,21 @@ def move_blocks(self, nodes, num_blocks):
20972097
self.bump_mocktime(1, nodes=nodes)
20982098
self.generate(self.nodes[0], num_blocks, sync_fun=lambda: self.sync_blocks(nodes))
20992099

2100+
def mine_single_node_quorum(self):
2101+
node = self.nodes[0]
2102+
quorums = node.quorum('list')['llmq_test']
2103+
2104+
skip_count = 24 - (self.nodes[0].getblockcount() % 24)
2105+
if skip_count != 0:
2106+
self.bump_mocktime(1)
2107+
self.generate(self.nodes[0], skip_count)
2108+
time.sleep(1)
2109+
self.generate(self.nodes[0], 30)
2110+
new_quorums_list = node.quorum('list')['llmq_test']
2111+
2112+
self.log.info(f"Test Quorums at height={node.getblockcount()} : {new_quorums_list}")
2113+
assert new_quorums_list != quorums
2114+
21002115
def mine_quorum(self, llmq_type_name="llmq_test", llmq_type=100, expected_connections=None, expected_members=None, expected_contributions=None, expected_complaints=0, expected_justifications=0, expected_commitments=None, mninfos_online=None, mninfos_valid=None, skip_maturity=False):
21012116
spork21_active = self.nodes[0].spork('show')['SPORK_21_QUORUM_ALL_CONNECTED'] <= 1
21022117
spork23_active = self.nodes[0].spork('show')['SPORK_23_QUORUM_POSE'] <= 1

0 commit comments

Comments
 (0)