Skip to content

Commit bf11238

Browse files
committed
QA: Implement tiertwo_dkg_errors functional test
1 parent 2e1d0c9 commit bf11238

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
TIERTWO_SCRIPTS = [
161161
# Longest test should go first, to favor running tests in parallel
162162
'tiertwo_governance_sync_basic.py', # ~ 1160 sec
163+
'tiertwo_dkg_errors.py', # ~ 486 sec
163164
'tiertwo_dkg_pose.py', # ~ 444 sec
164165
'tiertwo_mn_compatibility.py', # ~ 413 sec
165166
'tiertwo_deterministicmns.py', # ~ 366 sec
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2021 The PIVX 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+
"""Test errors during DKG phases"""
6+
7+
from test_framework.test_framework import PivxDMNTestFramework, ExpectedDKGMessages
8+
from test_framework.util import (
9+
assert_equal,
10+
assert_raises_rpc_error,
11+
)
12+
13+
14+
class DkgErrorsTest(PivxDMNTestFramework):
15+
16+
def set_test_params(self):
17+
self.set_base_test_params()
18+
self.extra_args = [["-nuparams=v5_shield:1", "-nuparams=v6_evo:130", "-debug=llmq", "-debug=dkg", "-debug=net"]] * self.num_nodes
19+
self.extra_args[0].append("-sporkkey=932HEevBSujW2ud7RfB1YF91AFygbBRQj3de3LyaCRqNzKKgWXi")
20+
21+
def reset_simerror(self, node):
22+
node.quorumdkgsimerror("contribution-omit", 0)
23+
node.quorumdkgsimerror("contribution-lie", 0)
24+
node.quorumdkgsimerror("complain-lie", 0)
25+
node.quorumdkgsimerror("justify-lie", 0)
26+
node.quorumdkgsimerror("justify-omit", 0)
27+
node.quorumdkgsimerror("commit-omit", 0)
28+
node.quorumdkgsimerror("commit-lie", 0)
29+
30+
def no_contrib(self, node):
31+
node.quorumdkgsimerror("contribution-omit", 1)
32+
33+
def invalid_contrib(self, node):
34+
node.quorumdkgsimerror("contribution-lie", 1)
35+
36+
def invalid_contrib_no_justif(self, node):
37+
node.quorumdkgsimerror("contribution-lie", 1)
38+
node.quorumdkgsimerror("justify-omit", 1)
39+
40+
def invalid_contrib_invalid_justif(self, node):
41+
node.quorumdkgsimerror("contribution-lie", 1)
42+
node.quorumdkgsimerror("justify-lie", 1)
43+
44+
def invalid_complaint(self, node):
45+
node.quorumdkgsimerror("complain-lie", 1)
46+
47+
def no_commit(self, node):
48+
node.quorumdkgsimerror("commit-omit", 1)
49+
50+
def invalid_commit(self, node):
51+
node.quorumdkgsimerror("commit-lie", 1)
52+
53+
def repair_mn(self, mnode, blocks=None):
54+
if blocks is None:
55+
blocks = self.nodes[0].listmasternodes(mnode.proTx)[0]["dmnstate"]["PoSePenalty"]
56+
self.log.info("Mining %d blocks to repair MN (node %d)..." % (blocks, mnode.idx))
57+
self.nodes[0].generate(blocks)
58+
self.sync_blocks()
59+
60+
def is_punished(self, proTx, expected_penalty):
61+
return self.nodes[0].listmasternodes(proTx)[0]["dmnstate"]["PoSePenalty"] == expected_penalty
62+
63+
def is_not_punished(self, proTx):
64+
return self.nodes[0].listmasternodes(proTx)[0]["dmnstate"]["PoSePenalty"] == 0
65+
66+
def run_test(self):
67+
miner = self.nodes[self.minerPos]
68+
69+
# initialize and start masternodes
70+
self.setup_test()
71+
assert_equal(len(self.mns), 6)
72+
73+
# Mine a LLMQ final commitment regularly with 3 signers
74+
self.log.info("----------------------------------")
75+
self.log.info("----- (0) DKG with no errors -----")
76+
self.log.info("----------------------------------")
77+
self.mine_quorum()
78+
assert_equal(171, miner.getblockcount())
79+
80+
# RPC: quorumdkgsimerror - invalid parameters
81+
self.log.info("Trying invalid parameters for quorumdkgsimerror")
82+
assert_raises_rpc_error(-8, "invalid rate. Must be between 0 and 1",
83+
miner.quorumdkgsimerror, "contribution-omit", -0.01)
84+
assert_raises_rpc_error(-8, "invalid rate. Must be between 0 and 1",
85+
miner.quorumdkgsimerror, "contribution-omit", 1.01)
86+
assert_raises_rpc_error(-8, "invalid error_type: foo",
87+
miner.quorumdkgsimerror, "foo", 0.5)
88+
89+
self.log.info("-------------------------------------")
90+
self.log.info("----- (1) Omit the contribution -----")
91+
self.log.info("-------------------------------------")
92+
dkg_msgs = [ExpectedDKGMessages(s_contrib=(i != 2), s_complaint=True, s_justif=False, s_commit=True,
93+
r_contrib=2, r_complaint=3, r_justif=0, r_commit=3) for i in range(3)]
94+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.no_contrib,
95+
expected_messages=dkg_msgs)
96+
self.check_final_commitment(qfc, valid=[1, 1, 0], signers=[1, 1, 1])
97+
assert self.is_punished(bad_mnode.proTx, 66)
98+
self.log.info("Node %d punished." % bad_mnode.idx)
99+
self.reset_simerror(self.nodes[bad_mnode.idx])
100+
self.repair_mn(bad_mnode, 66)
101+
102+
self.log.info("-------------------------------------------------------------")
103+
self.log.info("----- (2) Lie on contribution but provide justification -----")
104+
self.log.info("-------------------------------------------------------------")
105+
dkg_msgs = [ExpectedDKGMessages(s_contrib=True, s_complaint=(i != 2), s_justif=(i == 2), s_commit=True,
106+
r_contrib=3, r_complaint=2, r_justif=1, r_commit=3) for i in range(3)]
107+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.invalid_contrib,
108+
expected_messages=dkg_msgs)
109+
self.check_final_commitment(qfc, valid=[1, 1, 1], signers=[1, 1, 1])
110+
assert self.is_not_punished(bad_mnode.proTx)
111+
self.log.info("Node %d justified." % bad_mnode.idx)
112+
self.reset_simerror(self.nodes[bad_mnode.idx])
113+
114+
self.log.info("----------------------------------------------------------")
115+
self.log.info("----- (3) Lie on contribution and omit justification -----")
116+
self.log.info("----------------------------------------------------------")
117+
dkg_msgs = [ExpectedDKGMessages(s_contrib=True, s_complaint=(i != 2), s_justif=False, s_commit=True,
118+
r_contrib=3, r_complaint=2, r_justif=0, r_commit=3) for i in range(3)]
119+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.invalid_contrib_no_justif,
120+
expected_messages=dkg_msgs)
121+
self.check_final_commitment(qfc, valid=[1, 1, 0], signers=[1, 1, 1])
122+
assert self.is_punished(bad_mnode.proTx, 66)
123+
self.log.info("Node %d punished." % bad_mnode.idx)
124+
self.reset_simerror(self.nodes[bad_mnode.idx])
125+
self.repair_mn(bad_mnode, 66)
126+
127+
self.log.info("------------------------------------------------------------")
128+
self.log.info("----- (4) Lie on contribution and lie on justification -----")
129+
self.log.info("------------------------------------------------------------")
130+
dkg_msgs = [ExpectedDKGMessages(s_contrib=True, s_complaint=(i != 2), s_justif=(i == 2), s_commit=True,
131+
r_contrib=3, r_complaint=2, r_justif=1, r_commit=3) for i in range(3)]
132+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.invalid_contrib_invalid_justif,
133+
expected_messages=dkg_msgs)
134+
self.check_final_commitment(qfc, valid=[1, 1, 0], signers=[1, 1, 1])
135+
assert self.is_punished(bad_mnode.proTx, 66)
136+
self.log.info("Node %d punished." % bad_mnode.idx)
137+
self.reset_simerror(self.nodes[bad_mnode.idx])
138+
self.repair_mn(bad_mnode, 66)
139+
140+
self.log.info("---------------------------------------------------")
141+
self.log.info("----- (5) Lie on complaints for other members -----")
142+
self.log.info("---------------------------------------------------")
143+
dkg_msgs = [ExpectedDKGMessages(s_contrib=True, s_complaint=(i == 2), s_justif=(i != 2), s_commit=True,
144+
r_contrib=3, r_complaint=1, r_justif=2, r_commit=3) for i in range(3)]
145+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.invalid_complaint,
146+
expected_messages=dkg_msgs)
147+
self.check_final_commitment(qfc, valid=[1, 1, 1], signers=[1, 1, 1])
148+
assert self.is_not_punished(bad_mnode.proTx)
149+
self.log.info("Invalid complaint from %d justified." % bad_mnode.idx)
150+
self.reset_simerror(self.nodes[bad_mnode.idx])
151+
152+
self.log.info("---------------------------------------------")
153+
self.log.info("----- (6) Omit the premature commitment -----")
154+
self.log.info("---------------------------------------------")
155+
dkg_msgs = [ExpectedDKGMessages(s_contrib=True, s_complaint=False, s_justif=False, s_commit=(i != 2),
156+
r_contrib=3, r_complaint=0, r_justif=0, r_commit=2) for i in range(3)]
157+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.no_commit,
158+
expected_messages=dkg_msgs)
159+
self.check_final_commitment(qfc, valid=[1, 1, 1], signers=[1, 1, 0])
160+
assert self.is_not_punished(bad_mnode.proTx)
161+
self.log.info("Mined final commitment without node %d signature" % bad_mnode.idx)
162+
self.reset_simerror(self.nodes[bad_mnode.idx])
163+
164+
self.log.info("-------------------------------------------")
165+
self.log.info("----- (7) Lie on premature commitment -----")
166+
self.log.info("-------------------------------------------")
167+
dkg_msgs = [ExpectedDKGMessages(s_contrib=True, s_complaint=False, s_justif=False, s_commit=True,
168+
r_contrib=3, r_complaint=0, r_justif=0, r_commit=2) for _ in range(3)]
169+
qfc, bad_mnode = self.mine_quorum(invalidate_func=self.invalid_commit,
170+
expected_messages=dkg_msgs)
171+
self.check_final_commitment(qfc, valid=[1, 1, 1], signers=[1, 1, 0])
172+
assert self.is_not_punished(bad_mnode.proTx)
173+
self.log.info("Mined final commitment without node %d signature" % bad_mnode.idx)
174+
self.reset_simerror(self.nodes[bad_mnode.idx])
175+
176+
177+
if __name__ == '__main__':
178+
DkgErrorsTest().main()

0 commit comments

Comments
 (0)