|
42 | 42 | 7. Send Node0 the missing block again.
|
43 | 43 | Node0 should process and the tip should advance.
|
44 | 44 |
|
45 |
| -8. Test Node1 is able to sync when connected to node0 (which should have sufficient |
46 |
| -work on its chain). |
| 45 | +8. Create a fork which is invalid at a height longer than the current chain |
| 46 | + (ie to which the node will try to reorg) but which has headers built on top |
| 47 | + of the invalid block. Check that we get disconnected if we send more headers |
| 48 | + on the chain the node now knows to be invalid. |
47 | 49 |
|
| 50 | +9. Test Node1 is able to sync when connected to node0 (which should have sufficient |
| 51 | + work on its chain). |
48 | 52 | """
|
49 | 53 |
|
50 | 54 | from test_framework.mininode import *
|
51 | 55 | from test_framework.test_framework import BitcoinTestFramework
|
52 | 56 | from test_framework.util import *
|
53 | 57 | import time
|
54 |
| -from test_framework.blocktools import create_block, create_coinbase |
| 58 | +from test_framework.blocktools import create_block, create_coinbase, create_transaction |
55 | 59 |
|
56 | 60 | class AcceptBlockTest(BitcoinTestFramework):
|
57 | 61 | def add_options(self, parser):
|
@@ -240,9 +244,81 @@ def run_test(self):
|
240 | 244 |
|
241 | 245 | test_node.sync_with_ping()
|
242 | 246 | assert_equal(self.nodes[0].getblockcount(), 290)
|
| 247 | + self.nodes[0].getblock(all_blocks[286].hash) |
| 248 | + assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) |
| 249 | + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[287].hash) |
243 | 250 | self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
|
244 | 251 |
|
245 |
| - # 8. Connect node1 to node0 and ensure it is able to sync |
| 252 | + # 8. Create a chain which is invalid at a height longer than the |
| 253 | + # current chain, but which has more blocks on top of that |
| 254 | + block_289f = create_block(all_blocks[284].sha256, create_coinbase(289), all_blocks[284].nTime+1) |
| 255 | + block_289f.solve() |
| 256 | + block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1) |
| 257 | + block_290f.solve() |
| 258 | + block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1) |
| 259 | + # block_291 spends a coinbase below maturity! |
| 260 | + block_291.vtx.append(create_transaction(block_290f.vtx[0], 0, b"42", 1)) |
| 261 | + block_291.hashMerkleRoot = block_291.calc_merkle_root() |
| 262 | + block_291.solve() |
| 263 | + block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1) |
| 264 | + block_292.solve() |
| 265 | + |
| 266 | + # Now send all the headers on the chain and enough blocks to trigger reorg |
| 267 | + headers_message = msg_headers() |
| 268 | + headers_message.headers.append(CBlockHeader(block_289f)) |
| 269 | + headers_message.headers.append(CBlockHeader(block_290f)) |
| 270 | + headers_message.headers.append(CBlockHeader(block_291)) |
| 271 | + headers_message.headers.append(CBlockHeader(block_292)) |
| 272 | + test_node.send_message(headers_message) |
| 273 | + |
| 274 | + test_node.sync_with_ping() |
| 275 | + tip_entry_found = False |
| 276 | + for x in self.nodes[0].getchaintips(): |
| 277 | + if x['hash'] == block_292.hash: |
| 278 | + assert_equal(x['status'], "headers-only") |
| 279 | + tip_entry_found = True |
| 280 | + assert(tip_entry_found) |
| 281 | + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash) |
| 282 | + |
| 283 | + test_node.send_message(msg_block(block_289f)) |
| 284 | + test_node.send_message(msg_block(block_290f)) |
| 285 | + |
| 286 | + test_node.sync_with_ping() |
| 287 | + self.nodes[0].getblock(block_289f.hash) |
| 288 | + self.nodes[0].getblock(block_290f.hash) |
| 289 | + |
| 290 | + test_node.send_message(msg_block(block_291)) |
| 291 | + |
| 292 | + # At this point we've sent an obviously-bogus block, wait for full processing |
| 293 | + # without assuming whether we will be disconnected or not |
| 294 | + try: |
| 295 | + # Only wait a short while so the test doesn't take forever if we do get |
| 296 | + # disconnected |
| 297 | + test_node.sync_with_ping(timeout=1) |
| 298 | + except AssertionError: |
| 299 | + test_node.wait_for_disconnect() |
| 300 | + |
| 301 | + test_node = NodeConnCB() # connects to node (not whitelisted) |
| 302 | + connections[0] = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node) |
| 303 | + test_node.add_connection(connections[0]) |
| 304 | + |
| 305 | + NetworkThread().start() # Start up network handling in another thread |
| 306 | + test_node.wait_for_verack() |
| 307 | + |
| 308 | + # We should have failed reorg and switched back to 290 (but have block 291) |
| 309 | + assert_equal(self.nodes[0].getblockcount(), 290) |
| 310 | + assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) |
| 311 | + assert_equal(self.nodes[0].getblock(block_291.hash)["confirmations"], -1) |
| 312 | + |
| 313 | + # Now send a new header on the invalid chain, indicating we're forked off, and expect to get disconnected |
| 314 | + block_293 = create_block(block_292.sha256, create_coinbase(293), block_292.nTime+1) |
| 315 | + block_293.solve() |
| 316 | + headers_message = msg_headers() |
| 317 | + headers_message.headers.append(CBlockHeader(block_293)) |
| 318 | + test_node.send_message(headers_message) |
| 319 | + test_node.wait_for_disconnect() |
| 320 | + |
| 321 | + # 9. Connect node1 to node0 and ensure it is able to sync |
246 | 322 | connect_nodes(self.nodes[0], 1)
|
247 | 323 | sync_blocks([self.nodes[0], self.nodes[1]])
|
248 | 324 | self.log.info("Successfully synced nodes 1 and 0")
|
|
0 commit comments