Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_unrequested_blocks.py
Show First 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
# This should be accepted by node0 | # This should be accepted by node0 | ||||
blocks_h2 = [] # the height 2 blocks on each node's chain | blocks_h2 = [] # the height 2 blocks on each node's chain | ||||
block_time = int(time.time()) + 1 | block_time = int(time.time()) + 1 | ||||
for i in range(2): | for i in range(2): | ||||
blocks_h2.append(create_block( | blocks_h2.append(create_block( | ||||
tips[i], create_coinbase(2), block_time)) | tips[i], create_coinbase(2), block_time)) | ||||
blocks_h2[i].solve() | blocks_h2[i].solve() | ||||
block_time += 1 | block_time += 1 | ||||
test_node.send_message(msg_block(blocks_h2[0])) | test_node.send_and_ping(msg_block(blocks_h2[0])) | ||||
min_work_node.send_message(msg_block(blocks_h2[1])) | min_work_node.send_and_ping(msg_block(blocks_h2[1])) | ||||
for x in [test_node, min_work_node]: | |||||
x.sync_with_ping() | |||||
assert_equal(self.nodes[0].getblockcount(), 2) | assert_equal(self.nodes[0].getblockcount(), 2) | ||||
assert_equal(self.nodes[1].getblockcount(), 1) | assert_equal(self.nodes[1].getblockcount(), 1) | ||||
self.log.info( | self.log.info( | ||||
"First height 2 block accepted by node0; correctly rejected by node1") | "First height 2 block accepted by node0; correctly rejected by node1") | ||||
# 3. Send another block that builds on genesis. | # 3. Send another block that builds on genesis. | ||||
block_h1f = create_block( | block_h1f = create_block( | ||||
int("0x" + self.nodes[0].getblockhash(0), 0), create_coinbase(1), block_time) | int("0x" + self.nodes[0].getblockhash(0), 0), create_coinbase(1), block_time) | ||||
block_time += 1 | block_time += 1 | ||||
block_h1f.solve() | block_h1f.solve() | ||||
test_node.send_message(msg_block(block_h1f)) | test_node.send_and_ping(msg_block(block_h1f)) | ||||
test_node.sync_with_ping() | |||||
tip_entry_found = False | tip_entry_found = False | ||||
for x in self.nodes[0].getchaintips(): | for x in self.nodes[0].getchaintips(): | ||||
if x['hash'] == block_h1f.hash: | if x['hash'] == block_h1f.hash: | ||||
assert_equal(x['status'], "headers-only") | assert_equal(x['status'], "headers-only") | ||||
tip_entry_found = True | tip_entry_found = True | ||||
assert tip_entry_found | assert tip_entry_found | ||||
assert_raises_rpc_error(-1, "Block not found on disk", | assert_raises_rpc_error(-1, "Block not found on disk", | ||||
self.nodes[0].getblock, block_h1f.hash) | self.nodes[0].getblock, block_h1f.hash) | ||||
# 4. Send another two block that build on the fork. | # 4. Send another two block that build on the fork. | ||||
block_h2f = create_block( | block_h2f = create_block( | ||||
block_h1f.sha256, create_coinbase(2), block_time) | block_h1f.sha256, create_coinbase(2), block_time) | ||||
block_time += 1 | block_time += 1 | ||||
block_h2f.solve() | block_h2f.solve() | ||||
test_node.send_message(msg_block(block_h2f)) | test_node.send_and_ping(msg_block(block_h2f)) | ||||
test_node.sync_with_ping() | |||||
# Since the earlier block was not processed by node, the new block | # Since the earlier block was not processed by node, the new block | ||||
# can't be fully validated. | # can't be fully validated. | ||||
tip_entry_found = False | tip_entry_found = False | ||||
for x in self.nodes[0].getchaintips(): | for x in self.nodes[0].getchaintips(): | ||||
if x['hash'] == block_h2f.hash: | if x['hash'] == block_h2f.hash: | ||||
assert_equal(x['status'], "headers-only") | assert_equal(x['status'], "headers-only") | ||||
tip_entry_found = True | tip_entry_found = True | ||||
assert tip_entry_found | assert tip_entry_found | ||||
# But this block should be accepted by node since it has equal work. | # But this block should be accepted by node since it has equal work. | ||||
self.nodes[0].getblock(block_h2f.hash) | self.nodes[0].getblock(block_h2f.hash) | ||||
self.log.info("Second height 2 block accepted, but not reorg'ed to") | self.log.info("Second height 2 block accepted, but not reorg'ed to") | ||||
# 4b. Now send another block that builds on the forking chain. | # 4b. Now send another block that builds on the forking chain. | ||||
block_h3 = create_block( | block_h3 = create_block( | ||||
block_h2f.sha256, create_coinbase(3), block_h2f.nTime + 1) | block_h2f.sha256, create_coinbase(3), block_h2f.nTime + 1) | ||||
block_h3.solve() | block_h3.solve() | ||||
test_node.send_message(msg_block(block_h3)) | test_node.send_and_ping(msg_block(block_h3)) | ||||
test_node.sync_with_ping() | |||||
# Since the earlier block was not processed by node, the new block | # Since the earlier block was not processed by node, the new block | ||||
# can't be fully validated. | # can't be fully validated. | ||||
tip_entry_found = False | tip_entry_found = False | ||||
for x in self.nodes[0].getchaintips(): | for x in self.nodes[0].getchaintips(): | ||||
if x['hash'] == block_h3.hash: | if x['hash'] == block_h3.hash: | ||||
assert_equal(x['status'], "headers-only") | assert_equal(x['status'], "headers-only") | ||||
tip_entry_found = True | tip_entry_found = True | ||||
assert tip_entry_found | assert tip_entry_found | ||||
Show All 12 Lines | def run_test(self): | ||||
next_block = create_block( | next_block = create_block( | ||||
tip.sha256, create_coinbase(i + 4), tip.nTime + 1) | tip.sha256, create_coinbase(i + 4), tip.nTime + 1) | ||||
next_block.solve() | next_block.solve() | ||||
all_blocks.append(next_block) | all_blocks.append(next_block) | ||||
tip = next_block | tip = next_block | ||||
# Now send the block at height 5 and check that it wasn't accepted | # Now send the block at height 5 and check that it wasn't accepted | ||||
# (missing header) | # (missing header) | ||||
test_node.send_message(msg_block(all_blocks[1])) | test_node.send_and_ping(msg_block(all_blocks[1])) | ||||
test_node.sync_with_ping() | |||||
assert_raises_rpc_error(-5, "Block not found", | assert_raises_rpc_error(-5, "Block not found", | ||||
self.nodes[0].getblock, all_blocks[1].hash) | self.nodes[0].getblock, all_blocks[1].hash) | ||||
assert_raises_rpc_error(-5, "Block not found", | assert_raises_rpc_error(-5, "Block not found", | ||||
self.nodes[0].getblockheader, all_blocks[1].hash) | self.nodes[0].getblockheader, all_blocks[1].hash) | ||||
# The block at height 5 should be accepted if we provide the missing | # The block at height 5 should be accepted if we provide the missing | ||||
# header, though | # header, though | ||||
headers_message = msg_headers() | headers_message = msg_headers() | ||||
headers_message.headers.append(CBlockHeader(all_blocks[0])) | headers_message.headers.append(CBlockHeader(all_blocks[0])) | ||||
test_node.send_message(headers_message) | test_node.send_message(headers_message) | ||||
test_node.send_message(msg_block(all_blocks[1])) | test_node.send_and_ping(msg_block(all_blocks[1])) | ||||
test_node.sync_with_ping() | |||||
self.nodes[0].getblock(all_blocks[1].hash) | self.nodes[0].getblock(all_blocks[1].hash) | ||||
# Now send the blocks in all_blocks | # Now send the blocks in all_blocks | ||||
for i in range(288): | for i in range(288): | ||||
test_node.send_message(msg_block(all_blocks[i])) | test_node.send_message(msg_block(all_blocks[i])) | ||||
test_node.sync_with_ping() | test_node.sync_with_ping() | ||||
# Blocks 1-287 should be accepted, block 288 should be ignored because | # Blocks 1-287 should be accepted, block 288 should be ignored because | ||||
Show All 9 Lines | def run_test(self): | ||||
# The node should have requested the blocks at some point, so | # The node should have requested the blocks at some point, so | ||||
# disconnect/reconnect first | # disconnect/reconnect first | ||||
self.nodes[0].disconnect_p2ps() | self.nodes[0].disconnect_p2ps() | ||||
self.nodes[1].disconnect_p2ps() | self.nodes[1].disconnect_p2ps() | ||||
test_node = self.nodes[0].add_p2p_connection(P2PInterface()) | test_node = self.nodes[0].add_p2p_connection(P2PInterface()) | ||||
test_node.send_message(msg_block(block_h1f)) | test_node.send_and_ping(msg_block(block_h1f)) | ||||
test_node.sync_with_ping() | |||||
assert_equal(self.nodes[0].getblockcount(), 2) | assert_equal(self.nodes[0].getblockcount(), 2) | ||||
self.log.info( | self.log.info( | ||||
"Unrequested block that would complete more-work chain was ignored") | "Unrequested block that would complete more-work chain was ignored") | ||||
# 6. Try to get node to request the missing block. | # 6. Try to get node to request the missing block. | ||||
# Poke the node with an inv for block at height 3 and see if that | # Poke the node with an inv for block at height 3 and see if that | ||||
# triggers a getdata on block 2 (it should if block 2 is missing). | # triggers a getdata on block 2 (it should if block 2 is missing). | ||||
with mininode_lock: | with mininode_lock: | ||||
# Clear state so we can check the getdata request | # Clear state so we can check the getdata request | ||||
test_node.last_message.pop("getdata", None) | test_node.last_message.pop("getdata", None) | ||||
test_node.send_message(msg_inv([CInv(2, block_h3.sha256)])) | test_node.send_message(msg_inv([CInv(2, block_h3.sha256)])) | ||||
test_node.sync_with_ping() | test_node.sync_with_ping() | ||||
with mininode_lock: | with mininode_lock: | ||||
getdata = test_node.last_message["getdata"] | getdata = test_node.last_message["getdata"] | ||||
# Check that the getdata includes the right block | # Check that the getdata includes the right block | ||||
assert_equal(getdata.inv[0].hash, block_h1f.sha256) | assert_equal(getdata.inv[0].hash, block_h1f.sha256) | ||||
self.log.info("Inv at tip triggered getdata for unprocessed block") | self.log.info("Inv at tip triggered getdata for unprocessed block") | ||||
# 7. Send the missing block for the third time (now it is requested) | # 7. Send the missing block for the third time (now it is requested) | ||||
test_node.send_message(msg_block(block_h1f)) | test_node.send_and_ping(msg_block(block_h1f)) | ||||
test_node.sync_with_ping() | |||||
assert_equal(self.nodes[0].getblockcount(), 290) | assert_equal(self.nodes[0].getblockcount(), 290) | ||||
self.nodes[0].getblock(all_blocks[286].hash) | self.nodes[0].getblock(all_blocks[286].hash) | ||||
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) | assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash) | ||||
assert_raises_rpc_error(-1, "Block not found on disk", | assert_raises_rpc_error(-1, "Block not found on disk", | ||||
self.nodes[0].getblock, all_blocks[287].hash) | self.nodes[0].getblock, all_blocks[287].hash) | ||||
self.log.info( | self.log.info( | ||||
"Successfully reorged to longer chain from non-whitelisted peer") | "Successfully reorged to longer chain from non-whitelisted peer") | ||||
Show All 18 Lines | def run_test(self): | ||||
# Now send all the headers on the chain and enough blocks to trigger | # Now send all the headers on the chain and enough blocks to trigger | ||||
# reorg | # reorg | ||||
headers_message = msg_headers() | headers_message = msg_headers() | ||||
headers_message.headers.append(CBlockHeader(block_289f)) | headers_message.headers.append(CBlockHeader(block_289f)) | ||||
headers_message.headers.append(CBlockHeader(block_290f)) | headers_message.headers.append(CBlockHeader(block_290f)) | ||||
headers_message.headers.append(CBlockHeader(block_291)) | headers_message.headers.append(CBlockHeader(block_291)) | ||||
headers_message.headers.append(CBlockHeader(block_292)) | headers_message.headers.append(CBlockHeader(block_292)) | ||||
test_node.send_message(headers_message) | test_node.send_and_ping(headers_message) | ||||
test_node.sync_with_ping() | |||||
tip_entry_found = False | tip_entry_found = False | ||||
for x in self.nodes[0].getchaintips(): | for x in self.nodes[0].getchaintips(): | ||||
if x['hash'] == block_292.hash: | if x['hash'] == block_292.hash: | ||||
assert_equal(x['status'], "headers-only") | assert_equal(x['status'], "headers-only") | ||||
tip_entry_found = True | tip_entry_found = True | ||||
assert tip_entry_found | assert tip_entry_found | ||||
assert_raises_rpc_error(-1, "Block not found on disk", | assert_raises_rpc_error(-1, "Block not found on disk", | ||||
self.nodes[0].getblock, block_292.hash) | self.nodes[0].getblock, block_292.hash) | ||||
test_node.send_message(msg_block(block_289f)) | test_node.send_message(msg_block(block_289f)) | ||||
test_node.send_message(msg_block(block_290f)) | test_node.send_and_ping(msg_block(block_290f)) | ||||
test_node.sync_with_ping() | |||||
self.nodes[0].getblock(block_289f.hash) | self.nodes[0].getblock(block_289f.hash) | ||||
self.nodes[0].getblock(block_290f.hash) | self.nodes[0].getblock(block_290f.hash) | ||||
test_node.send_message(msg_block(block_291)) | test_node.send_message(msg_block(block_291)) | ||||
# At this point we've sent an obviously-bogus block, wait for full processing | # At this point we've sent an obviously-bogus block, wait for full processing | ||||
# without assuming whether we will be disconnected or not | # without assuming whether we will be disconnected or not | ||||
try: | try: | ||||
Show All 34 Lines |