Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_sendheaders.py
Show First 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | class SendHeadersTest(BitcoinTestFramework): | ||||
def test_nonnull_locators(self, test_node, inv_node): | def test_nonnull_locators(self, test_node, inv_node): | ||||
tip = int(self.nodes[0].getbestblockhash(), 16) | tip = int(self.nodes[0].getbestblockhash(), 16) | ||||
# PART 1 | # PART 1 | ||||
# 1. Mine a block; expect inv announcements each time | # 1. Mine a block; expect inv announcements each time | ||||
self.log.info( | self.log.info( | ||||
"Part 1: headers don't start before sendheaders message...") | "Part 1: headers don't start before sendheaders message...") | ||||
for i in range(4): | for i in range(4): | ||||
self.log.debug("Part 1.{}: starting...".format(i)) | |||||
old_tip = tip | old_tip = tip | ||||
tip = self.mine_blocks(1) | tip = self.mine_blocks(1) | ||||
inv_node.check_last_inv_announcement(inv=[tip]) | inv_node.check_last_inv_announcement(inv=[tip]) | ||||
test_node.check_last_inv_announcement(inv=[tip]) | test_node.check_last_inv_announcement(inv=[tip]) | ||||
# Try a few different responses; none should affect next announcement | # Try a few different responses; none should affect next announcement | ||||
if i == 0: | if i == 0: | ||||
# first request the block | # first request the block | ||||
test_node.send_get_data([tip]) | test_node.send_get_data([tip]) | ||||
Show All 35 Lines | def test_nonnull_locators(self, test_node, inv_node): | ||||
# Now that we've synced headers, headers announcements should work | # Now that we've synced headers, headers announcements should work | ||||
tip = self.mine_blocks(1) | tip = self.mine_blocks(1) | ||||
inv_node.check_last_inv_announcement(inv=[tip]) | inv_node.check_last_inv_announcement(inv=[tip]) | ||||
test_node.check_last_headers_announcement(headers=[tip]) | test_node.check_last_headers_announcement(headers=[tip]) | ||||
height = self.nodes[0].getblockcount() + 1 | height = self.nodes[0].getblockcount() + 1 | ||||
block_time += 10 # Advance far enough ahead | block_time += 10 # Advance far enough ahead | ||||
for i in range(10): | for i in range(10): | ||||
self.log.debug("Part 2.{}: starting...".format(i)) | |||||
# Mine i blocks, and alternate announcing either via | # Mine i blocks, and alternate announcing either via | ||||
# inv (of tip) or via headers. After each, new blocks | # inv (of tip) or via headers. After each, new blocks | ||||
# mined by the node should successfully be announced | # mined by the node should successfully be announced | ||||
# with block header, even though the blocks are never requested | # with block header, even though the blocks are never requested | ||||
for j in range(2): | for j in range(2): | ||||
self.log.debug("Part 2.{}.{}: starting...".format(i, j)) | |||||
blocks = [] | blocks = [] | ||||
for b in range(i + 1): | for b in range(i + 1): | ||||
blocks.append(create_block( | blocks.append(create_block( | ||||
tip, create_coinbase(height), block_time)) | tip, create_coinbase(height), block_time)) | ||||
blocks[-1].solve() | blocks[-1].solve() | ||||
tip = blocks[-1].sha256 | tip = blocks[-1].sha256 | ||||
block_time += 1 | block_time += 1 | ||||
height += 1 | height += 1 | ||||
Show All 32 Lines | def test_nonnull_locators(self, test_node, inv_node): | ||||
self.log.info("Part 2: success!") | self.log.info("Part 2: success!") | ||||
self.log.info( | self.log.info( | ||||
"Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...") | "Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...") | ||||
# PART 3. Headers announcements can stop after large reorg, and resume after | # PART 3. Headers announcements can stop after large reorg, and resume after | ||||
# getheaders or inv from peer. | # getheaders or inv from peer. | ||||
for j in range(2): | for j in range(2): | ||||
self.log.debug("Part 3.{}: starting...".format(j)) | |||||
# First try mining a reorg that can propagate with header announcement | # First try mining a reorg that can propagate with header announcement | ||||
new_block_hashes = self.mine_reorg(length=7) | new_block_hashes = self.mine_reorg(length=7) | ||||
tip = new_block_hashes[-1] | tip = new_block_hashes[-1] | ||||
inv_node.check_last_inv_announcement(inv=[tip]) | inv_node.check_last_inv_announcement(inv=[tip]) | ||||
test_node.check_last_headers_announcement(headers=new_block_hashes) | test_node.check_last_headers_announcement(headers=new_block_hashes) | ||||
block_time += 8 | block_time += 8 | ||||
Show All 11 Lines | def test_nonnull_locators(self, test_node, inv_node): | ||||
# Use getblocks/getdata | # Use getblocks/getdata | ||||
test_node.send_getblocks(locator=[fork_point]) | test_node.send_getblocks(locator=[fork_point]) | ||||
test_node.check_last_inv_announcement(inv=new_block_hashes) | test_node.check_last_inv_announcement(inv=new_block_hashes) | ||||
test_node.send_get_data(new_block_hashes) | test_node.send_get_data(new_block_hashes) | ||||
test_node.wait_for_block(new_block_hashes[-1]) | test_node.wait_for_block(new_block_hashes[-1]) | ||||
for i in range(3): | for i in range(3): | ||||
self.log.debug("Part 3.{}.{}: starting...".format(j, i)) | |||||
# Mine another block, still should get only an inv | # Mine another block, still should get only an inv | ||||
tip = self.mine_blocks(1) | tip = self.mine_blocks(1) | ||||
inv_node.check_last_inv_announcement(inv=[tip]) | inv_node.check_last_inv_announcement(inv=[tip]) | ||||
test_node.check_last_inv_announcement(inv=[tip]) | test_node.check_last_inv_announcement(inv=[tip]) | ||||
if i == 0: | if i == 0: | ||||
self.log.debug( | # Just get the data -- shouldn't cause headers announcements to resume | ||||
"Just get the data -- shouldn't cause headers announcements to resume") | |||||
test_node.send_get_data([tip]) | test_node.send_get_data([tip]) | ||||
test_node.wait_for_block(tip) | test_node.wait_for_block(tip) | ||||
elif i == 1: | elif i == 1: | ||||
self.log.debug( | # Send a getheaders message that shouldn't trigger headers announcements | ||||
"Send a getheaders message that shouldn't trigger headers announcements to resume (best header sent will be too old)") | # to resume (best header sent will be too old) | ||||
test_node.send_get_headers( | test_node.send_get_headers( | ||||
locator=[fork_point], hashstop=new_block_hashes[1]) | locator=[fork_point], hashstop=new_block_hashes[1]) | ||||
test_node.send_get_data([tip]) | test_node.send_get_data([tip]) | ||||
test_node.wait_for_block(tip) | test_node.wait_for_block(tip) | ||||
elif i == 2: | elif i == 2: | ||||
# This time, try sending either a getheaders to trigger resumption | |||||
# of headers announcements, or mine a new block and inv it, also | |||||
# triggering resumption of headers announcements. | |||||
test_node.send_get_data([tip]) | test_node.send_get_data([tip]) | ||||
test_node.wait_for_block(tip) | test_node.wait_for_block(tip) | ||||
self.log.debug( | |||||
"This time, try sending either a getheaders to trigger resumption of headers announcements, or mine a new block and inv it, also triggering resumption of headers announcements.") | |||||
if j == 0: | if j == 0: | ||||
test_node.send_get_headers(locator=[tip], hashstop=0) | test_node.send_get_headers(locator=[tip], hashstop=0) | ||||
test_node.sync_with_ping() | test_node.sync_with_ping() | ||||
else: | else: | ||||
test_node.send_block_inv(tip) | test_node.send_block_inv(tip) | ||||
test_node.sync_with_ping() | test_node.sync_with_ping() | ||||
# New blocks should now be announced with header | # New blocks should now be announced with header | ||||
tip = self.mine_blocks(1) | tip = self.mine_blocks(1) | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | def test_nonnull_locators(self, test_node, inv_node): | ||||
# Now deliver all those blocks we announced. | # Now deliver all those blocks we announced. | ||||
[test_node.send_message(msg_block(x)) for x in blocks] | [test_node.send_message(msg_block(x)) for x in blocks] | ||||
self.log.info("Part 5: Testing handling of unconnecting headers") | self.log.info("Part 5: Testing handling of unconnecting headers") | ||||
# First we test that receipt of an unconnecting header doesn't prevent | # First we test that receipt of an unconnecting header doesn't prevent | ||||
# chain sync. | # chain sync. | ||||
for i in range(10): | for i in range(10): | ||||
self.log.debug("Part 5.{}: starting...".format(i)) | |||||
test_node.last_message.pop("getdata", None) | test_node.last_message.pop("getdata", None) | ||||
blocks = [] | blocks = [] | ||||
# Create two more blocks. | # Create two more blocks. | ||||
for j in range(2): | for j in range(2): | ||||
blocks.append(create_block( | blocks.append(create_block( | ||||
tip, create_coinbase(height), block_time)) | tip, create_coinbase(height), block_time)) | ||||
blocks[-1].solve() | blocks[-1].solve() | ||||
tip = blocks[-1].sha256 | tip = blocks[-1].sha256 | ||||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |