forked from BitcoinActivation/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeature_bip8.py
executable file
·125 lines (111 loc) · 8.44 KB
/
feature_bip8.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
#!/usr/bin/env python3
# Copyright (c) 2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test BIP 8 softforks
from collections import namedtuple
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
RestartedNodeInfo = namedtuple("RestartedNodeInfo", ("node", "extra_args", "status"))
class Bip8Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = True
self.extra_args = [
['-vbparams=testdummy:@-2:@-2'], # Node 0 has TestDummy inactive
['-vbparams=testdummy:@144:@{}:0'.format(144 * 3)], # Node 1 has regular activation window
['-vbparams=testdummy:@144:@{}:@{}:0'.format(144 * 3, 144 * 5)], # Node 2 has minimum activation height
['-vbparams=testdummy:@-2:@-2'], # Node 3 has TestDummy inactive, but will be restarted with different params
]
def setup_network(self):
self.setup_nodes()
def test_height(self, height, status, mine_from, restart):
if height > self.height:
self.log.info("Test status at height {}...".format(height))
while self.height < height:
blockhash = self.nodes[mine_from].generate(1)[0]
block = self.nodes[mine_from].getblock(blockhash, 0)
for node in self.nodes:
node.submitblock(block)
assert_equal(node.getbestblockhash(), blockhash)
self.height += 1
elif height < self.height:
assert mine_from is None
self.log.info("Roll back to height {}...".format(height))
old_block = self.nodes[0].getblockhash(height + 1)
for node in self.nodes:
node.invalidateblock(old_block)
else:
assert mine_from is None
assert height == 0 and self.height == 0
self.log.info("Test status at genesis...")
self.height = height
for (i, node), st in zip(enumerate(self.nodes), status):
self.log.debug("Node #{}...".format(i))
info = node.getblockchaininfo()
assert_equal(info["blocks"], height)
if st is None:
assert "testdummy" not in info["softforks"]
else:
assert_equal(info["softforks"]["testdummy"]["bip8"]["status"], st)
if restart:
# Restart this node and check that the status is what we expect
restart.extra_args[0] += ':0' # LockinOnTimeout
self.restart_node(restart.node, restart.extra_args)
info = self.nodes[restart.node].getblockchaininfo()
assert_equal(info["blocks"], height)
if restart.status is None:
assert "testdummy" not in info["softforks"]
else:
assert_equal(info["softforks"]["testdummy"]["bip8"]["status"], restart.status)
# Now restart again to go back to the original settings
self.restart_node(restart.node, self.extra_args[restart.node])
info = self.nodes[restart.node].getblockchaininfo()
assert_equal(info["blocks"], height)
if status[restart.node] is None:
assert "testdummy" not in info["softforks"]
else:
assert_equal(info["softforks"]["testdummy"]["bip8"]["status"], status[restart.node])
def run_test(self):
self.log.info("Checking -vbparams")
self.stop_node(3)
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@-2:@1"], expected_msg="Error: When one of startheight or timeoutheight is -2, both must be -2")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@1:@-2:0"], expected_msg="Error: When one of startheight or timeoutheight is -2, both must be -2")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@1:@1:0"], expected_msg="Error: Invalid startheight (1), must be a multiple of 144")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@144:@1:0"], expected_msg="Error: Invalid timeoutheight (1), must be a multiple of 144")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@144:@144:@-1:0"], expected_msg="Error: Invalid minimum activation height (-1), cannot be negative")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@144:@144:@1:0"], expected_msg="Error: Invalid minimum activation height (1), must be a multiple of 144")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@288:@144:0"], expected_msg="Error: Invalid timeoutheight (144), must be at least two periods greater than the startheight (288)")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@-3:@144"], expected_msg="Error: Invalid startheight (-3), cannot be negative (except for never or always active special cases)")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@144:@-1:0"], expected_msg="Error: Invalid timeoutheight (-1), cannot be negative (except for never or always active special cases)")
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@{}:@144:0".format(0x7fffffff + 1)], expected_msg="Error: Invalid startheight (@{})".format(0x7fffffff + 1))
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@144:@{}:0".format(0x7fffffff + 1)], expected_msg="Error: Invalid timeoutheight (@{})".format(0x7fffffff + 1))
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@{}:@144:0".format(-(0x7fffffff + 2))], expected_msg="Error: Invalid startheight (@{})".format(-(0x7fffffff + 2)))
self.nodes[3].assert_start_raises_init_error(extra_args=["-vbparams=testdummy:@144:@{}:0".format(-(0x7fffffff + 2))], expected_msg="Error: Invalid timeoutheight (@{})".format(-(0x7fffffff + 2)))
self.start_node(3, self.extra_args[3])
self.height = 0
self.test_height(0, [None, "defined", "defined", None], None, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "defined"))
# BIP 8 state transitions from "defined" to "started" or "failed" after
# the last block of the retargeting period has been mined. This means
# any new rules apply to transactions currently in the mempool, which
# might be mined in the next block.
#
# The next retargeting period starts at block 144, so nothing should
# happen at 142 and the state should change at 143.
self.test_height(144-2, [None, "defined", "defined", None], 0, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "defined"))
self.test_height(144-1, [None, "started", "started", None], 0, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "started"))
self.log.info("Test status when not signaling...")
self.test_height(144*2-1, [None, "started", "started", None], 0, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "started"))
self.test_height(144*3-1, [None, "failed", "failed", None], 0, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "failed"))
# The new branch has unique block hashes, because of the signalling and
# because generate uses a deterministic address that depends on the node
# index.
# Also tests that if the last period meets the threshold, the fork activates.
self.log.info("Test status when signaling...")
self.test_height(144-1, [None, "started", "started", None], None, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "started"))
self.test_height(144*2-1, [None, "started", "started", None], 3, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "started"))
self.test_height(144*3-1, [None, "locked_in", "locked_in", None], 1, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "locked_in"))
self.test_height(144*4-1, [None, "active", "locked_in", None], 1, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "active"))
self.test_height(144*5-1, [None, "active", "active", None], 1, RestartedNodeInfo(3, ["-vbparams=testdummy:@144:@{}".format(144*3)], "active"))
if __name__ == '__main__':
Bip8Test().main()