Skip to content

Commit 641be27

Browse files
committed
Regtest for update backwards compatibility.
This adds a new regtest, custom_address_update.py. The test runs two masternodes, where we explicitly set the protocol version of one of the nodes to the "old" version not supporting custom reward scripts for masternodes. With this test, we ensure that all the masternode networking works fine between "old" and "new" nodes before the update is activated, at least as closely as we can without running a real old node.
1 parent 8395f5b commit 641be27

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2020-2021 The DIVI developers
3+
# Distributed under the MIT/X11 software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
# Tests that nodes with support for custom reward addresses are compatible
7+
# to nodes without it before the change actually activates. For this,
8+
# we run two masternodes (one with and one without support) and check
9+
# that they can both see each other's masternode.
10+
#
11+
# We use five nodes:
12+
# - node 0 is a masternode with default protocol (i.e. "new")
13+
# - node 1 is a masternode with previous protocol (i.e. "old")
14+
# - nodes 2-4 are just used to get above the "three full nodes" threshold
15+
16+
from test_framework import BitcoinTestFramework
17+
from util import *
18+
from masternode import *
19+
20+
import collections
21+
import time
22+
23+
OLD_PROTOCOL = 70915
24+
NEW_PROTOCOL = 71000
25+
26+
27+
def args_for (n):
28+
base = ["-debug", "-nolistenonion", "-activeversion=%d" % OLD_PROTOCOL]
29+
if n == 1:
30+
base.extend (["-protocolversion=%d" % OLD_PROTOCOL])
31+
return base
32+
33+
34+
class CustomAddressUpdateTest (BitcoinTestFramework):
35+
36+
def setup_chain (self):
37+
for i in range (5):
38+
initialize_datadir (self.options.tmpdir, i)
39+
40+
def setup_network (self, config_line=None, extra_args=[]):
41+
self.nodes = [
42+
start_node (i, self.options.tmpdir, extra_args=args_for (i))
43+
for i in range (5)
44+
]
45+
46+
# We want to work with mock times that are beyond the genesis
47+
# block timestamp but before current time (so that nodes being
48+
# started up and before they get on mocktime aren't rejecting
49+
# the on-disk blockchain).
50+
self.time = 1580000000
51+
assert self.time < time.time ()
52+
set_node_times (self.nodes, self.time)
53+
54+
connect_nodes (self.nodes[0], 2)
55+
connect_nodes (self.nodes[1], 2)
56+
connect_nodes (self.nodes[2], 3)
57+
connect_nodes (self.nodes[2], 4)
58+
connect_nodes (self.nodes[3], 4)
59+
60+
self.is_network_split = False
61+
62+
def start_node (self, n):
63+
"""Starts node n (0 or 1) with the proper arguments
64+
and masternode config for it."""
65+
66+
assert n in [0, 1]
67+
configs = [[c.getLine ()] for c in self.cfg]
68+
69+
args = args_for (n)
70+
args.append ("-masternode")
71+
args.append ("-masternodeprivkey=%s" % self.cfg[n].privkey)
72+
args.append ("-masternodeaddr=127.0.0.1:%d" % p2p_port (n))
73+
74+
self.nodes[n] = start_node (n, self.options.tmpdir,
75+
extra_args=args, mn_config_lines=configs[n])
76+
self.nodes[n].setmocktime (self.time)
77+
78+
for i in [2, 3, 4]:
79+
connect_nodes (self.nodes[n], i)
80+
sync_blocks (self.nodes)
81+
82+
def stop_node (self, n):
83+
"""Stops node n."""
84+
85+
stop_node (self.nodes[n], n)
86+
self.nodes[n] = None
87+
88+
def advance_time (self, dt=1):
89+
"""Advances mocktime by the given number of seconds."""
90+
91+
self.time += dt
92+
set_node_times (self.nodes, self.time)
93+
94+
def mine_blocks (self, n):
95+
"""Mines blocks with node 2."""
96+
97+
self.nodes[2].setgenerate(True, n)
98+
sync_blocks (self.nodes)
99+
100+
def run_test (self):
101+
assert_equal (self.nodes[0].getnetworkinfo ()["protocolversion"], NEW_PROTOCOL)
102+
assert_equal (self.nodes[1].getnetworkinfo ()["protocolversion"], OLD_PROTOCOL)
103+
104+
self.fund_masternodes ()
105+
self.start_masternodes ()
106+
107+
def fund_masternodes (self):
108+
print ("Funding masternodes...")
109+
110+
# The collateral needs 15 confirmations, and the masternode broadcast
111+
# signature must be later than that block's timestamp. Thus we start
112+
# with a very early timestamp.
113+
genesis = self.nodes[0].getblockhash (0)
114+
genesisTime = self.nodes[0].getblockheader (genesis)["time"]
115+
assert genesisTime < self.time
116+
set_node_times (self.nodes, genesisTime)
117+
118+
self.nodes[0].setgenerate (True, 1)
119+
sync_blocks (self.nodes)
120+
self.nodes[1].setgenerate (True, 1)
121+
sync_blocks (self.nodes)
122+
self.mine_blocks (25)
123+
assert_equal (self.nodes[0].getbalance (), 1250)
124+
assert_equal (self.nodes[1].getbalance (), 1250)
125+
126+
id1 = self.nodes[0].allocatefunds ("masternode", "mn1", "copper")["txhash"]
127+
id2 = self.nodes[1].allocatefunds ("masternode", "mn2", "copper")["txhash"]
128+
sync_mempools (self.nodes)
129+
self.mine_blocks (15)
130+
set_node_times (self.nodes, self.time)
131+
self.mine_blocks (1)
132+
133+
self.cfg = [
134+
fund_masternode (self.nodes[0], "mn1", "copper", id1, "localhost:%d" % p2p_port (0)),
135+
fund_masternode (self.nodes[1], "mn2", "copper", id2, "localhost:%d" % p2p_port (1)),
136+
]
137+
138+
def start_masternodes (self):
139+
print ("Starting masternodes...")
140+
141+
for i in range (2):
142+
self.stop_node (i)
143+
self.start_node (i)
144+
145+
# Start the masternodes after the nodes are back up and connected
146+
# (so they will receive each other's broadcast).
147+
for i in range (2):
148+
res = self.nodes[i].startmasternode ("mn%d" % (i + 1))
149+
assert_equal (res, {"status": "success"})
150+
151+
# Check status of the masternodes themselves.
152+
for i in [0, 1]:
153+
data = self.nodes[i].getmasternodestatus ()
154+
assert_equal (data["status"], 4)
155+
assert_equal (data["txhash"], self.cfg[i].txid)
156+
assert_equal (data["outputidx"], self.cfg[i].vout)
157+
assert_equal (data["message"], "Masternode successfully started")
158+
159+
# Both masternodes should see each other, independent of the
160+
# protocol version used.
161+
lists = [{}] * 2
162+
for i in range (2):
163+
cur = self.nodes[i].listmasternodes ()
164+
while len (cur) < 2:
165+
time.sleep (0.1)
166+
cur = self.nodes[i].listmasternodes ()
167+
for c in cur:
168+
lists[i][c["txhash"]] = c
169+
assert_equal (lists[0], lists[1])
170+
171+
lst = lists[0]
172+
assert_equal (len (lst), 2)
173+
for val in lst.values ():
174+
assert_equal (val["tier"], "COPPER")
175+
assert_equal (val["status"], "ENABLED")
176+
177+
178+
if __name__ == '__main__':
179+
CustomAddressUpdateTest ().main ()

divi/qa/rpc-tests/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
'StakingVaultStaking.py',
7979
'StakingVaultDeactivation.py',
8080
'StakingVaultSpam.py',
81+
'custom_address_update.py',
8182
'forknotify.py',
8283
'getchaintips.py',
8384
'httpbasics.py',

0 commit comments

Comments
 (0)