rpc_preciousblock.py raw
1 #!/usr/bin/env python3
2 # Copyright (c) 2015-present The Bitcoin 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 the preciousblock RPC."""
6
7 from test_framework.test_framework import BitcoinTestFramework
8 from test_framework.util import (
9 assert_not_equal,
10 assert_equal,
11 )
12
13 def unidirectional_node_sync_via_rpc(node_src, node_dest):
14 blocks_to_copy = []
15 blockhash = node_src.getbestblockhash()
16 while True:
17 try:
18 assert len(node_dest.getblock(blockhash, False)) > 0
19 break
20 except Exception:
21 blocks_to_copy.append(blockhash)
22 blockhash = node_src.getblockheader(blockhash, True)['previousblockhash']
23 blocks_to_copy.reverse()
24 for blockhash in blocks_to_copy:
25 blockdata = node_src.getblock(blockhash, False)
26 assert node_dest.submitblock(blockdata) in (None, 'inconclusive')
27
28 def node_sync_via_rpc(nodes):
29 for node_src in nodes:
30 for node_dest in nodes:
31 if node_src is node_dest:
32 continue
33 unidirectional_node_sync_via_rpc(node_src, node_dest)
34
35 class PreciousTest(BitcoinTestFramework):
36 def set_test_params(self):
37 self.setup_clean_chain = True
38 self.num_nodes = 3
39
40 def setup_network(self):
41 self.setup_nodes()
42
43 def run_test(self):
44 self.log.info("Ensure submitblock can in principle reorg to a competing chain")
45 self.generate(self.nodes[0], 1, sync_fun=self.no_op)
46 assert_equal(self.nodes[0].getblockcount(), 1)
47 hashZ = self.generate(self.nodes[1], 2, sync_fun=self.no_op)[-1]
48 assert_equal(self.nodes[1].getblockcount(), 2)
49 node_sync_via_rpc(self.nodes[0:3])
50 assert_equal(self.nodes[0].getbestblockhash(), hashZ)
51
52 self.log.info("Mine blocks A-B-C on Node 0")
53 hashC = self.generate(self.nodes[0], 3, sync_fun=self.no_op)[-1]
54 assert_equal(self.nodes[0].getblockcount(), 5)
55 self.log.info("Mine competing blocks E-F-G on Node 1")
56 hashG = self.generate(self.nodes[1], 3, sync_fun=self.no_op)[-1]
57 assert_equal(self.nodes[1].getblockcount(), 5)
58 assert_not_equal(hashC, hashG)
59 self.log.info("Connect nodes and check no reorg occurs")
60 # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
61 node_sync_via_rpc(self.nodes[0:2])
62 self.connect_nodes(0, 1)
63 assert_equal(self.nodes[0].getbestblockhash(), hashC)
64 assert_equal(self.nodes[1].getbestblockhash(), hashG)
65 self.log.info("Make Node0 prefer block G")
66 self.nodes[0].preciousblock(hashG)
67 assert_equal(self.nodes[0].getbestblockhash(), hashG)
68 self.log.info("Make Node0 prefer block C again")
69 self.nodes[0].preciousblock(hashC)
70 assert_equal(self.nodes[0].getbestblockhash(), hashC)
71 self.log.info("Make Node1 prefer block C")
72 self.nodes[1].preciousblock(hashC)
73 self.sync_blocks(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC
74 assert_equal(self.nodes[1].getbestblockhash(), hashC)
75 self.log.info("Make Node1 prefer block G again")
76 self.nodes[1].preciousblock(hashG)
77 assert_equal(self.nodes[1].getbestblockhash(), hashG)
78 self.log.info("Make Node0 prefer block G again")
79 self.nodes[0].preciousblock(hashG)
80 assert_equal(self.nodes[0].getbestblockhash(), hashG)
81 self.log.info("Make Node1 prefer block C again")
82 self.nodes[1].preciousblock(hashC)
83 assert_equal(self.nodes[1].getbestblockhash(), hashC)
84 self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
85 self.generate(self.nodes[0], 1, sync_fun=self.no_op)
86 assert_equal(self.nodes[0].getblockcount(), 6)
87 self.sync_blocks(self.nodes[0:2])
88 hashH = self.nodes[0].getbestblockhash()
89 assert_equal(self.nodes[1].getbestblockhash(), hashH)
90 self.log.info("Node1 should not be able to prefer block C anymore")
91 self.nodes[1].preciousblock(hashC)
92 assert_equal(self.nodes[1].getbestblockhash(), hashH)
93 self.log.info("Mine competing blocks I-J-K-L on Node 2")
94 self.generate(self.nodes[2], 4, sync_fun=self.no_op)
95 assert_equal(self.nodes[2].getblockcount(), 6)
96 hashL = self.nodes[2].getbestblockhash()
97 self.log.info("Connect nodes and check no reorg occurs")
98 node_sync_via_rpc(self.nodes[1:3])
99 self.connect_nodes(1, 2)
100 self.connect_nodes(0, 2)
101 assert_equal(self.nodes[0].getbestblockhash(), hashH)
102 assert_equal(self.nodes[1].getbestblockhash(), hashH)
103 assert_equal(self.nodes[2].getbestblockhash(), hashL)
104 self.log.info("Make Node1 prefer block L")
105 self.nodes[1].preciousblock(hashL)
106 assert_equal(self.nodes[1].getbestblockhash(), hashL)
107 self.log.info("Make Node2 prefer block H")
108 self.nodes[2].preciousblock(hashH)
109 assert_equal(self.nodes[2].getbestblockhash(), hashH)
110
111 if __name__ == '__main__':
112 PreciousTest(__file__).main()
113