[qa] test that invalid blocks on an invalid chain get a disconnect
This commit is contained in:
parent
015a5258ad
commit
00dcda60f6
1 changed files with 80 additions and 4 deletions
|
@ -42,16 +42,20 @@ Node1 is unused in tests 3-7:
|
|||
7. Send Node0 the missing block again.
|
||||
Node0 should process and the tip should advance.
|
||||
|
||||
8. Test Node1 is able to sync when connected to node0 (which should have sufficient
|
||||
work on its chain).
|
||||
8. Create a fork which is invalid at a height longer than the current chain
|
||||
(ie to which the node will try to reorg) but which has headers built on top
|
||||
of the invalid block. Check that we get disconnected if we send more headers
|
||||
on the chain the node now knows to be invalid.
|
||||
|
||||
9. Test Node1 is able to sync when connected to node0 (which should have sufficient
|
||||
work on its chain).
|
||||
"""
|
||||
|
||||
from test_framework.mininode import *
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
import time
|
||||
from test_framework.blocktools import create_block, create_coinbase
|
||||
from test_framework.blocktools import create_block, create_coinbase, create_transaction
|
||||
|
||||
class AcceptBlockTest(BitcoinTestFramework):
|
||||
def add_options(self, parser):
|
||||
|
@ -240,9 +244,81 @@ class AcceptBlockTest(BitcoinTestFramework):
|
|||
|
||||
test_node.sync_with_ping()
|
||||
assert_equal(self.nodes[0].getblockcount(), 290)
|
||||
self.nodes[0].getblock(all_blocks[286].hash)
|
||||
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
|
||||
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[287].hash)
|
||||
self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
|
||||
|
||||
# 8. Connect node1 to node0 and ensure it is able to sync
|
||||
# 8. Create a chain which is invalid at a height longer than the
|
||||
# current chain, but which has more blocks on top of that
|
||||
block_289f = create_block(all_blocks[284].sha256, create_coinbase(289), all_blocks[284].nTime+1)
|
||||
block_289f.solve()
|
||||
block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1)
|
||||
block_290f.solve()
|
||||
block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1)
|
||||
# block_291 spends a coinbase below maturity!
|
||||
block_291.vtx.append(create_transaction(block_290f.vtx[0], 0, b"42", 1))
|
||||
block_291.hashMerkleRoot = block_291.calc_merkle_root()
|
||||
block_291.solve()
|
||||
block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1)
|
||||
block_292.solve()
|
||||
|
||||
# Now send all the headers on the chain and enough blocks to trigger reorg
|
||||
headers_message = msg_headers()
|
||||
headers_message.headers.append(CBlockHeader(block_289f))
|
||||
headers_message.headers.append(CBlockHeader(block_290f))
|
||||
headers_message.headers.append(CBlockHeader(block_291))
|
||||
headers_message.headers.append(CBlockHeader(block_292))
|
||||
test_node.send_message(headers_message)
|
||||
|
||||
test_node.sync_with_ping()
|
||||
tip_entry_found = False
|
||||
for x in self.nodes[0].getchaintips():
|
||||
if x['hash'] == block_292.hash:
|
||||
assert_equal(x['status'], "headers-only")
|
||||
tip_entry_found = True
|
||||
assert(tip_entry_found)
|
||||
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash)
|
||||
|
||||
test_node.send_message(msg_block(block_289f))
|
||||
test_node.send_message(msg_block(block_290f))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
self.nodes[0].getblock(block_289f.hash)
|
||||
self.nodes[0].getblock(block_290f.hash)
|
||||
|
||||
test_node.send_message(msg_block(block_291))
|
||||
|
||||
# At this point we've sent an obviously-bogus block, wait for full processing
|
||||
# without assuming whether we will be disconnected or not
|
||||
try:
|
||||
# Only wait a short while so the test doesn't take forever if we do get
|
||||
# disconnected
|
||||
test_node.sync_with_ping(timeout=1)
|
||||
except AssertionError:
|
||||
test_node.wait_for_disconnect()
|
||||
|
||||
test_node = NodeConnCB() # connects to node (not whitelisted)
|
||||
connections[0] = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)
|
||||
test_node.add_connection(connections[0])
|
||||
|
||||
NetworkThread().start() # Start up network handling in another thread
|
||||
test_node.wait_for_verack()
|
||||
|
||||
# We should have failed reorg and switched back to 290 (but have block 291)
|
||||
assert_equal(self.nodes[0].getblockcount(), 290)
|
||||
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
|
||||
assert_equal(self.nodes[0].getblock(block_291.hash)["confirmations"], -1)
|
||||
|
||||
# Now send a new header on the invalid chain, indicating we're forked off, and expect to get disconnected
|
||||
block_293 = create_block(block_292.sha256, create_coinbase(293), block_292.nTime+1)
|
||||
block_293.solve()
|
||||
headers_message = msg_headers()
|
||||
headers_message.headers.append(CBlockHeader(block_293))
|
||||
test_node.send_message(headers_message)
|
||||
test_node.wait_for_disconnect()
|
||||
|
||||
# 9. Connect node1 to node0 and ensure it is able to sync
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
sync_blocks([self.nodes[0], self.nodes[1]])
|
||||
self.log.info("Successfully synced nodes 1 and 0")
|
||||
|
|
Loading…
Reference in a new issue