p2p-acceptblock: add steps 8, 9 to confirm node disconnects

This commit is contained in:
Dakoda Greaves 2021-08-15 13:46:11 -07:00 committed by Patrick Lodder
parent fe1bca68da
commit fb194d7319
No known key found for this signature in database
GPG key ID: 2D3A345B98D0DC1F

View file

@ -7,7 +7,7 @@ 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
'''
AcceptBlockTest -- test processing of unrequested blocks.
@ -54,6 +54,14 @@ The test:
7. Send Node0 the missing block again.
Node0 should process and the tip should advance.
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).
'''
# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
@ -271,8 +279,85 @@ class AcceptBlockTest(BitcoinTestFramework):
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 1442)
self.nodes[0].getblock(all_blocks[1438].hash)
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[1438].hash)
assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[1439].hash)
print("Successfully reorged to longer chain from non-whitelisted peer")
# 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_1441f = create_block(all_blocks[1436].sha256, create_coinbase(1441), all_blocks[1436].nTime+1)
block_1441f.solve()
block_1442f = create_block(block_1441f.sha256, create_coinbase(1440), block_1441f.nTime+1)
block_1442f.solve()
block_1443 = create_block(block_1442f.sha256, create_coinbase(1441), block_1442f.nTime+1)
# block_1443 spends a coinbase below maturity!
block_1443.vtx.append(create_transaction(block_1442f.vtx[0], 0, b"42", 1))
block_1443.hashMerkleRoot = block_1443.calc_merkle_root()
block_1443.solve()
block_1444 = create_block(block_1443.sha256, create_coinbase(1444), block_1443.nTime+1)
block_1444.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_1441f))
headers_message.headers.append(CBlockHeader(block_1442f))
headers_message.headers.append(CBlockHeader(block_1443))
headers_message.headers.append(CBlockHeader(block_1444))
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_1444.hash:
assert_equal(x['status'], "headers-only")
tip_entry_found = True
assert(tip_entry_found)
assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, block_1444.hash)
test_node.send_message(msg_block(block_1441f))
test_node.send_message(msg_block(block_1442f))
test_node.sync_with_ping()
self.nodes[0].getblock(block_1441f.hash)
self.nodes[0].getblock(block_1442f.hash)
test_node.send_message(msg_block(block_1443))
# 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 = TestNode() # 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 1442 (but have block 1443)
assert_equal(self.nodes[0].getblockcount(), 1442)
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[1438].hash)
assert_equal(self.nodes[0].getblock(block_1443.hash)["confirmations"], -1)
# Now send a new header on the invalid chain, indicating we're forked off, and expect to get disconnected
block_1445 = create_block(block_1444.sha256, create_coinbase(1445), block_1444.nTime+1)
block_1445.solve()
headers_message = msg_headers()
headers_message.headers.append(CBlockHeader(block_1445))
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")
[ c.disconnect_node() for c in connections ]
if __name__ == '__main__':