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