qa: Remove never used return value of sync_with_ping
[bitcoinplatinum.git] / test / functional / p2p-acceptblock.py
blob9f61ce27da4a44f09e9355fb5587bbdd599a3e3f
1 #!/usr/bin/env python3
2 # Copyright (c) 2015-2016 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 processing of unrequested blocks.
7 Since behavior differs when receiving unrequested blocks from whitelisted peers
8 versus non-whitelisted peers, this tests the behavior of both (effectively two
9 separate tests running in parallel).
11 Setup: two nodes, node0 and node1, not connected to each other. Node0 does not
12 whitelist localhost, but node1 does. They will each be on their own chain for
13 this test.
15 We have one NodeConn connection to each, test_node and white_node respectively.
17 The test:
18 1. Generate one block on each node, to leave IBD.
20 2. Mine a new block on each tip, and deliver to each node from node's peer.
21 The tip should advance.
23 3. Mine a block that forks the previous block, and deliver to each node from
24 corresponding peer.
25 Node0 should not process this block (just accept the header), because it is
26 unrequested and doesn't have more work than the tip.
27 Node1 should process because this is coming from a whitelisted peer.
29 4. Send another block that builds on the forking block.
30 Node0 should process this block but be stuck on the shorter chain, because
31 it's missing an intermediate block.
32 Node1 should reorg to this longer chain.
34 4b.Send 288 more blocks on the longer chain.
35 Node0 should process all but the last block (too far ahead in height).
36 Send all headers to Node1, and then send the last block in that chain.
37 Node1 should accept the block because it's coming from a whitelisted peer.
39 5. Send a duplicate of the block in #3 to Node0.
40 Node0 should not process the block because it is unrequested, and stay on
41 the shorter chain.
43 6. Send Node0 an inv for the height 3 block produced in #4 above.
44 Node0 should figure out that Node0 has the missing height 2 block and send a
45 getdata.
47 7. Send Node0 the missing block again.
48 Node0 should process and the tip should advance.
49 """
51 from test_framework.mininode import *
52 from test_framework.test_framework import BitcoinTestFramework
53 from test_framework.util import *
54 import time
55 from test_framework.blocktools import create_block, create_coinbase
57 class AcceptBlockTest(BitcoinTestFramework):
58 def add_options(self, parser):
59 parser.add_option("--testbinary", dest="testbinary",
60 default=os.getenv("BITCOIND", "bitcoind"),
61 help="bitcoind binary to test")
63 def set_test_params(self):
64 self.setup_clean_chain = True
65 self.num_nodes = 2
66 self.extra_args = [[], ["-whitelist=127.0.0.1"]]
68 def setup_network(self):
69 # Node0 will be used to test behavior of processing unrequested blocks
70 # from peers which are not whitelisted, while Node1 will be used for
71 # the whitelisted case.
72 self.setup_nodes()
74 def run_test(self):
75 # Setup the p2p connections and start up the network thread.
76 test_node = NodeConnCB() # connects to node0 (not whitelisted)
77 white_node = NodeConnCB() # connects to node1 (whitelisted)
79 connections = []
80 connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
81 connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node))
82 test_node.add_connection(connections[0])
83 white_node.add_connection(connections[1])
85 NetworkThread().start() # Start up network handling in another thread
87 # Test logic begins here
88 test_node.wait_for_verack()
89 white_node.wait_for_verack()
91 # 1. Have both nodes mine a block (leave IBD)
92 [ n.generate(1) for n in self.nodes ]
93 tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ]
95 # 2. Send one block that builds on each tip.
96 # This should be accepted.
97 blocks_h2 = [] # the height 2 blocks on each node's chain
98 block_time = int(time.time()) + 1
99 for i in range(2):
100 blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time))
101 blocks_h2[i].solve()
102 block_time += 1
103 test_node.send_message(msg_block(blocks_h2[0]))
104 white_node.send_message(msg_block(blocks_h2[1]))
106 for x in [test_node, white_node]:
107 x.sync_with_ping()
108 assert_equal(self.nodes[0].getblockcount(), 2)
109 assert_equal(self.nodes[1].getblockcount(), 2)
110 self.log.info("First height 2 block accepted by both nodes")
112 # 3. Send another block that builds on the original tip.
113 blocks_h2f = [] # Blocks at height 2 that fork off the main chain
114 for i in range(2):
115 blocks_h2f.append(create_block(tips[i], create_coinbase(2), blocks_h2[i].nTime+1))
116 blocks_h2f[i].solve()
117 test_node.send_message(msg_block(blocks_h2f[0]))
118 white_node.send_message(msg_block(blocks_h2f[1]))
120 for x in [test_node, white_node]:
121 x.sync_with_ping()
122 for x in self.nodes[0].getchaintips():
123 if x['hash'] == blocks_h2f[0].hash:
124 assert_equal(x['status'], "headers-only")
126 for x in self.nodes[1].getchaintips():
127 if x['hash'] == blocks_h2f[1].hash:
128 assert_equal(x['status'], "valid-headers")
130 self.log.info("Second height 2 block accepted only from whitelisted peer")
132 # 4. Now send another block that builds on the forking chain.
133 blocks_h3 = []
134 for i in range(2):
135 blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(3), blocks_h2f[i].nTime+1))
136 blocks_h3[i].solve()
137 test_node.send_message(msg_block(blocks_h3[0]))
138 white_node.send_message(msg_block(blocks_h3[1]))
140 for x in [test_node, white_node]:
141 x.sync_with_ping()
142 # Since the earlier block was not processed by node0, the new block
143 # can't be fully validated.
144 for x in self.nodes[0].getchaintips():
145 if x['hash'] == blocks_h3[0].hash:
146 assert_equal(x['status'], "headers-only")
148 # But this block should be accepted by node0 since it has more work.
149 self.nodes[0].getblock(blocks_h3[0].hash)
150 self.log.info("Unrequested more-work block accepted from non-whitelisted peer")
152 # Node1 should have accepted and reorged.
153 assert_equal(self.nodes[1].getblockcount(), 3)
154 self.log.info("Successfully reorged to length 3 chain from whitelisted peer")
156 # 4b. Now mine 288 more blocks and deliver; all should be processed but
157 # the last (height-too-high) on node0. Node1 should process the tip if
158 # we give it the headers chain leading to the tip.
159 tips = blocks_h3
160 headers_message = msg_headers()
161 all_blocks = [] # node0's blocks
162 for j in range(2):
163 for i in range(288):
164 next_block = create_block(tips[j].sha256, create_coinbase(i + 4), tips[j].nTime+1)
165 next_block.solve()
166 if j==0:
167 test_node.send_message(msg_block(next_block))
168 all_blocks.append(next_block)
169 else:
170 headers_message.headers.append(CBlockHeader(next_block))
171 tips[j] = next_block
173 time.sleep(2)
174 # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead
175 for x in all_blocks[:-1]:
176 self.nodes[0].getblock(x.hash)
177 assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash)
179 headers_message.headers.pop() # Ensure the last block is unrequested
180 white_node.send_message(headers_message) # Send headers leading to tip
181 white_node.send_message(msg_block(tips[1])) # Now deliver the tip
182 white_node.sync_with_ping()
183 self.nodes[1].getblock(tips[1].hash)
184 self.log.info("Unrequested block far ahead of tip accepted from whitelisted peer")
186 # 5. Test handling of unrequested block on the node that didn't process
187 # Should still not be processed (even though it has a child that has more
188 # work).
189 test_node.send_message(msg_block(blocks_h2f[0]))
191 # Here, if the sleep is too short, the test could falsely succeed (if the
192 # node hasn't processed the block by the time the sleep returns, and then
193 # the node processes it and incorrectly advances the tip).
194 # But this would be caught later on, when we verify that an inv triggers
195 # a getdata request for this block.
196 test_node.sync_with_ping()
197 assert_equal(self.nodes[0].getblockcount(), 2)
198 self.log.info("Unrequested block that would complete more-work chain was ignored")
200 # 6. Try to get node to request the missing block.
201 # Poke the node with an inv for block at height 3 and see if that
202 # triggers a getdata on block 2 (it should if block 2 is missing).
203 with mininode_lock:
204 # Clear state so we can check the getdata request
205 test_node.last_message.pop("getdata", None)
206 test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))
208 test_node.sync_with_ping()
209 with mininode_lock:
210 getdata = test_node.last_message["getdata"]
212 # Check that the getdata includes the right block
213 assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
214 self.log.info("Inv at tip triggered getdata for unprocessed block")
216 # 7. Send the missing block for the third time (now it is requested)
217 test_node.send_message(msg_block(blocks_h2f[0]))
219 test_node.sync_with_ping()
220 assert_equal(self.nodes[0].getblockcount(), 290)
221 self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
223 [ c.disconnect_node() for c in connections ]
225 if __name__ == '__main__':
226 AcceptBlockTest().main()