Skip to content

Commit 3c3489d

Browse files
committed
test: add test
1 parent 41ab95d commit 3c3489d

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2018-2024 The Dash Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Tests governance checks can be skipped for blocks covered by the best chainlock."""
6+
7+
import json
8+
9+
from test_framework.messages import uint256_to_string
10+
from test_framework.test_framework import DashTestFramework
11+
from test_framework.util import assert_equal, satoshi_round
12+
13+
class DashGovernanceTest (DashTestFramework):
14+
def set_test_params(self):
15+
self.set_dash_test_params(6, 5, [["-budgetparams=10:10:10"]] * 6, fast_dip3_enforcement=True)
16+
17+
def prepare_object(self, object_type, parent_hash, creation_time, revision, name, amount, payment_address):
18+
proposal_rev = revision
19+
proposal_time = int(creation_time)
20+
proposal_template = {
21+
"type": object_type,
22+
"name": name,
23+
"start_epoch": proposal_time,
24+
"end_epoch": proposal_time + 24 * 60 * 60,
25+
"payment_amount": float(amount),
26+
"payment_address": payment_address,
27+
"url": "https://dash.org"
28+
}
29+
proposal_hex = ''.join(format(x, '02x') for x in json.dumps(proposal_template).encode())
30+
collateral_hash = self.nodes[0].gobject("prepare", parent_hash, proposal_rev, proposal_time, proposal_hex)
31+
return {
32+
"parentHash": parent_hash,
33+
"collateralHash": collateral_hash,
34+
"createdAt": proposal_time,
35+
"revision": proposal_rev,
36+
"hex": proposal_hex,
37+
"data": proposal_template,
38+
}
39+
40+
def have_trigger_for_height(self, sb_block_height, nodes = None):
41+
if nodes is None:
42+
nodes = self.nodes
43+
count = 0
44+
for node in nodes:
45+
valid_triggers = node.gobject("list", "valid", "triggers")
46+
for trigger in list(valid_triggers.values()):
47+
if json.loads(trigger["DataString"])["event_block_height"] != sb_block_height:
48+
continue
49+
if trigger['AbsoluteYesCount'] > 0:
50+
count = count + 1
51+
break
52+
return count == len(nodes)
53+
54+
def run_test(self):
55+
sb_cycle = 20
56+
57+
self.log.info("Make sure ChainLocks are active")
58+
59+
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
60+
self.wait_for_sporks_same()
61+
self.activate_v19(expected_activation_height=900)
62+
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))
63+
self.move_to_next_cycle()
64+
self.log.info("Cycle H height:" + str(self.nodes[0].getblockcount()))
65+
self.move_to_next_cycle()
66+
self.log.info("Cycle H+C height:" + str(self.nodes[0].getblockcount()))
67+
self.move_to_next_cycle()
68+
self.log.info("Cycle H+2C height:" + str(self.nodes[0].getblockcount()))
69+
70+
self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103)
71+
72+
self.sync_blocks()
73+
self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash())
74+
75+
self.nodes[0].sporkupdate("SPORK_9_SUPERBLOCKS_ENABLED", 0)
76+
self.wait_for_sporks_same()
77+
78+
self.log.info("Prepare and submit proposals")
79+
80+
proposal_time = self.mocktime
81+
self.p0_payout_address = self.nodes[0].getnewaddress()
82+
self.p1_payout_address = self.nodes[0].getnewaddress()
83+
self.p0_amount = satoshi_round("1.1")
84+
self.p1_amount = satoshi_round("3.3")
85+
86+
p0_collateral_prepare = self.prepare_object(1, uint256_to_string(0), proposal_time, 1, "Proposal_0", self.p0_amount, self.p0_payout_address)
87+
p1_collateral_prepare = self.prepare_object(1, uint256_to_string(0), proposal_time, 1, "Proposal_1", self.p1_amount, self.p1_payout_address)
88+
self.bump_mocktime(60 * 10 + 1)
89+
90+
self.nodes[0].generate(6)
91+
self.bump_mocktime(6 * 156)
92+
self.sync_blocks()
93+
94+
assert_equal(len(self.nodes[0].gobject("list-prepared")), 2)
95+
assert_equal(len(self.nodes[0].gobject("list")), 0)
96+
97+
self.p0_hash = self.nodes[0].gobject("submit", "0", 1, proposal_time, p0_collateral_prepare["hex"], p0_collateral_prepare["collateralHash"])
98+
self.p1_hash = self.nodes[0].gobject("submit", "0", 1, proposal_time, p1_collateral_prepare["hex"], p1_collateral_prepare["collateralHash"])
99+
100+
assert_equal(len(self.nodes[0].gobject("list")), 2)
101+
102+
self.log.info("Isolate a node so that it would miss votes and triggers")
103+
# Isolate a node
104+
self.isolate_node(5)
105+
106+
self.log.info("Vote proposals")
107+
108+
self.nodes[0].gobject("vote-many", self.p0_hash, "funding", "yes")
109+
self.nodes[0].gobject("vote-many", self.p1_hash, "funding", "yes")
110+
assert_equal(self.nodes[0].gobject("get", self.p0_hash)["FundingResult"]["YesCount"], self.mn_count)
111+
assert_equal(self.nodes[0].gobject("get", self.p1_hash)["FundingResult"]["YesCount"], self.mn_count)
112+
113+
assert_equal(len(self.nodes[0].gobject("list", "valid", "triggers")), 0)
114+
115+
n = sb_cycle - self.nodes[0].getblockcount() % sb_cycle
116+
assert n > 1
117+
118+
# Move remaining n blocks until the next Superblock
119+
for _ in range(n - 1):
120+
self.nodes[0].generate(1)
121+
self.bump_mocktime(156)
122+
self.sync_blocks(self.nodes[0:5])
123+
124+
self.log.info("Wait for new trigger and votes on non-isolated nodes")
125+
sb_block_height = self.nodes[0].getblockcount() + 1
126+
self.wait_until(lambda: self.have_trigger_for_height(sb_block_height, self.nodes[0:5]), timeout=5)
127+
# Mine superblock
128+
self.nodes[0].generate(1)
129+
self.bump_mocktime(156)
130+
self.sync_blocks(self.nodes[0:5])
131+
self.wait_for_chainlocked_block(self.nodes[0], self.nodes[0].getbestblockhash())
132+
133+
self.log.info("Reconnect isolated node and confirm the next ChainLock will let it sync")
134+
self.reconnect_isolated_node(5, 0)
135+
self.nodes[0].generate(1)
136+
self.bump_mocktime(156)
137+
self.sync_blocks()
138+
139+
140+
if __name__ == '__main__':
141+
DashGovernanceTest().main()

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@
280280
'feature_new_quorum_type_activation.py',
281281
'feature_governance_objects.py',
282282
'feature_governance.py --legacy-wallet',
283+
'feature_governance_cl.py --legacy-wallet',
283284
'rpc_uptime.py',
284285
'wallet_resendwallettransactions.py --legacy-wallet',
285286
'wallet_resendwallettransactions.py --descriptors',

0 commit comments

Comments
 (0)