|
|
|
@ -83,16 +83,32 @@ d. Announce 49 headers that don't connect.
@@ -83,16 +83,32 @@ d. Announce 49 headers that don't connect.
|
|
|
|
|
e. Announce one more that doesn't connect. |
|
|
|
|
Expect: disconnect. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
from test_framework.mininode import * |
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework |
|
|
|
|
from test_framework.util import * |
|
|
|
|
from test_framework.blocktools import create_block, create_coinbase |
|
|
|
|
from test_framework.mininode import ( |
|
|
|
|
CBlockHeader, |
|
|
|
|
CInv, |
|
|
|
|
NODE_WITNESS, |
|
|
|
|
NetworkThread, |
|
|
|
|
NodeConnCB, |
|
|
|
|
mininode_lock, |
|
|
|
|
msg_block, |
|
|
|
|
msg_getblocks, |
|
|
|
|
msg_getdata, |
|
|
|
|
msg_getheaders, |
|
|
|
|
msg_headers, |
|
|
|
|
msg_inv, |
|
|
|
|
msg_sendheaders, |
|
|
|
|
) |
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework |
|
|
|
|
from test_framework.util import ( |
|
|
|
|
assert_equal, |
|
|
|
|
sync_blocks, |
|
|
|
|
wait_until, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
DIRECT_FETCH_RESPONSE_TIME = 0.05 |
|
|
|
|
|
|
|
|
|
direct_fetch_response_time = 0.05 |
|
|
|
|
|
|
|
|
|
class TestNode(NodeConnCB): |
|
|
|
|
class BaseNode(NodeConnCB): |
|
|
|
|
def __init__(self): |
|
|
|
|
super().__init__() |
|
|
|
|
self.block_announced = False |
|
|
|
@ -136,8 +152,8 @@ class TestNode(NodeConnCB):
@@ -136,8 +152,8 @@ class TestNode(NodeConnCB):
|
|
|
|
|
# right header or the right inv |
|
|
|
|
# inv and headers should be lists of block hashes |
|
|
|
|
def check_last_announcement(self, headers=None, inv=None): |
|
|
|
|
expect_headers = headers if headers != None else [] |
|
|
|
|
expect_inv = inv if inv != None else [] |
|
|
|
|
expect_headers = headers if headers is not None else [] |
|
|
|
|
expect_inv = inv if inv is not None else [] |
|
|
|
|
test_function = lambda: self.block_announced |
|
|
|
|
wait_until(test_function, timeout=60, lock=mininode_lock) |
|
|
|
|
with mininode_lock: |
|
|
|
@ -153,7 +169,7 @@ class TestNode(NodeConnCB):
@@ -153,7 +169,7 @@ class TestNode(NodeConnCB):
|
|
|
|
|
hash_headers = [] |
|
|
|
|
if "headers" in self.last_message: |
|
|
|
|
# treat headers as a list of block hashes |
|
|
|
|
hash_headers = [ x.sha256 for x in self.last_message["headers"].headers ] |
|
|
|
|
hash_headers = [x.sha256 for x in self.last_message["headers"].headers] |
|
|
|
|
if hash_headers != expect_headers: |
|
|
|
|
success = False |
|
|
|
|
|
|
|
|
@ -176,7 +192,7 @@ class TestNode(NodeConnCB):
@@ -176,7 +192,7 @@ class TestNode(NodeConnCB):
|
|
|
|
|
|
|
|
|
|
def send_header_for_blocks(self, new_blocks): |
|
|
|
|
headers_message = msg_headers() |
|
|
|
|
headers_message.headers = [ CBlockHeader(b) for b in new_blocks ] |
|
|
|
|
headers_message.headers = [CBlockHeader(b) for b in new_blocks] |
|
|
|
|
self.send_message(headers_message) |
|
|
|
|
|
|
|
|
|
def send_getblocks(self, locator): |
|
|
|
@ -202,27 +218,27 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -202,27 +218,27 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
# to-be-reorged-out blocks are mined, so that we don't break later tests. |
|
|
|
|
# return the list of block hashes newly mined |
|
|
|
|
def mine_reorg(self, length): |
|
|
|
|
self.nodes[0].generate(length) # make sure all invalidated blocks are node0's |
|
|
|
|
self.nodes[0].generate(length) # make sure all invalidated blocks are node0's |
|
|
|
|
sync_blocks(self.nodes, wait=0.1) |
|
|
|
|
for x in self.nodes[0].p2ps: |
|
|
|
|
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16)) |
|
|
|
|
x.clear_last_announcement() |
|
|
|
|
|
|
|
|
|
tip_height = self.nodes[1].getblockcount() |
|
|
|
|
hash_to_invalidate = self.nodes[1].getblockhash(tip_height-(length-1)) |
|
|
|
|
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1)) |
|
|
|
|
self.nodes[1].invalidateblock(hash_to_invalidate) |
|
|
|
|
all_hashes = self.nodes[1].generate(length+1) # Must be longer than the orig chain |
|
|
|
|
all_hashes = self.nodes[1].generate(length + 1) # Must be longer than the orig chain |
|
|
|
|
sync_blocks(self.nodes, wait=0.1) |
|
|
|
|
return [int(x, 16) for x in all_hashes] |
|
|
|
|
|
|
|
|
|
def run_test(self): |
|
|
|
|
# Setup the p2p connections and start up the network thread. |
|
|
|
|
inv_node = self.nodes[0].add_p2p_connection(TestNode()) |
|
|
|
|
inv_node = self.nodes[0].add_p2p_connection(BaseNode()) |
|
|
|
|
# Set nServices to 0 for test_node, so no block download will occur outside of |
|
|
|
|
# direct fetching |
|
|
|
|
test_node = self.nodes[0].add_p2p_connection(TestNode(), services=NODE_WITNESS) |
|
|
|
|
test_node = self.nodes[0].add_p2p_connection(BaseNode(), services=NODE_WITNESS) |
|
|
|
|
|
|
|
|
|
NetworkThread().start() # Start up network handling in another thread |
|
|
|
|
NetworkThread().start() # Start up network handling in another thread |
|
|
|
|
|
|
|
|
|
# Test logic begins here |
|
|
|
|
inv_node.wait_for_verack() |
|
|
|
@ -275,18 +291,18 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -275,18 +291,18 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
test_node.get_headers(locator=[old_tip], hashstop=tip) |
|
|
|
|
test_node.get_data([tip]) |
|
|
|
|
test_node.wait_for_block(tip) |
|
|
|
|
test_node.clear_last_announcement() # since we requested headers... |
|
|
|
|
test_node.clear_last_announcement() # since we requested headers... |
|
|
|
|
elif i == 2: |
|
|
|
|
# this time announce own block via headers |
|
|
|
|
height = self.nodes[0].getblockcount() |
|
|
|
|
last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] |
|
|
|
|
block_time = last_time + 1 |
|
|
|
|
new_block = create_block(tip, create_coinbase(height+1), block_time) |
|
|
|
|
new_block = create_block(tip, create_coinbase(height + 1), block_time) |
|
|
|
|
new_block.solve() |
|
|
|
|
test_node.send_header_for_blocks([new_block]) |
|
|
|
|
test_node.wait_for_getdata([new_block.sha256]) |
|
|
|
|
test_node.send_message(msg_block(new_block)) |
|
|
|
|
test_node.sync_with_ping() # make sure this block is processed |
|
|
|
|
test_node.sync_with_ping() # make sure this block is processed |
|
|
|
|
inv_node.clear_last_announcement() |
|
|
|
|
test_node.clear_last_announcement() |
|
|
|
|
|
|
|
|
@ -305,7 +321,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -305,7 +321,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
assert_equal(inv_node.check_last_announcement(inv=[tip]), True) |
|
|
|
|
assert_equal(test_node.check_last_announcement(headers=[tip]), True) |
|
|
|
|
|
|
|
|
|
height = self.nodes[0].getblockcount()+1 |
|
|
|
|
height = self.nodes[0].getblockcount() + 1 |
|
|
|
|
block_time += 10 # Advance far enough ahead |
|
|
|
|
for i in range(10): |
|
|
|
|
# Mine i blocks, and alternate announcing either via |
|
|
|
@ -314,7 +330,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -314,7 +330,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
# with block header, even though the blocks are never requested |
|
|
|
|
for j in range(2): |
|
|
|
|
blocks = [] |
|
|
|
|
for b in range(i+1): |
|
|
|
|
for b in range(i + 1): |
|
|
|
|
blocks.append(create_block(tip, create_coinbase(height), block_time)) |
|
|
|
|
blocks[-1].solve() |
|
|
|
|
tip = blocks[-1].sha256 |
|
|
|
@ -328,7 +344,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -328,7 +344,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
test_node.send_header_for_blocks(blocks) |
|
|
|
|
# Test that duplicate inv's won't result in duplicate |
|
|
|
|
# getdata requests, or duplicate headers announcements |
|
|
|
|
[ inv_node.send_block_inv(x.sha256) for x in blocks ] |
|
|
|
|
[inv_node.send_block_inv(x.sha256) for x in blocks] |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks]) |
|
|
|
|
inv_node.sync_with_ping() |
|
|
|
|
else: |
|
|
|
@ -339,7 +355,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -339,7 +355,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
# getdata requests (the check is further down) |
|
|
|
|
inv_node.send_header_for_blocks(blocks) |
|
|
|
|
inv_node.sync_with_ping() |
|
|
|
|
[ test_node.send_message(msg_block(x)) for x in blocks ] |
|
|
|
|
[test_node.send_message(msg_block(x)) for x in blocks] |
|
|
|
|
test_node.sync_with_ping() |
|
|
|
|
inv_node.sync_with_ping() |
|
|
|
|
# This block should not be announced to the inv node (since it also |
|
|
|
@ -379,7 +395,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -379,7 +395,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
fork_point = int(fork_point, 16) |
|
|
|
|
|
|
|
|
|
# Use getblocks/getdata |
|
|
|
|
test_node.send_getblocks(locator = [fork_point]) |
|
|
|
|
test_node.send_getblocks(locator=[fork_point]) |
|
|
|
|
assert_equal(test_node.check_last_announcement(inv=new_block_hashes), True) |
|
|
|
|
test_node.get_data(new_block_hashes) |
|
|
|
|
test_node.wait_for_block(new_block_hashes[-1]) |
|
|
|
@ -434,7 +450,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -434,7 +450,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
height += 1 |
|
|
|
|
inv_node.send_message(msg_block(blocks[-1])) |
|
|
|
|
|
|
|
|
|
inv_node.sync_with_ping() # Make sure blocks are processed |
|
|
|
|
inv_node.sync_with_ping() # Make sure blocks are processed |
|
|
|
|
test_node.last_message.pop("getdata", None) |
|
|
|
|
test_node.send_header_for_blocks(blocks) |
|
|
|
|
test_node.sync_with_ping() |
|
|
|
@ -453,9 +469,9 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -453,9 +469,9 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
|
|
|
|
|
test_node.send_header_for_blocks(blocks) |
|
|
|
|
test_node.sync_with_ping() |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=direct_fetch_response_time) |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=DIRECT_FETCH_RESPONSE_TIME) |
|
|
|
|
|
|
|
|
|
[ test_node.send_message(msg_block(x)) for x in blocks ] |
|
|
|
|
[test_node.send_message(msg_block(x)) for x in blocks] |
|
|
|
|
|
|
|
|
|
test_node.sync_with_ping() |
|
|
|
|
|
|
|
|
@ -484,13 +500,13 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -484,13 +500,13 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
# both blocks (same work as tip) |
|
|
|
|
test_node.send_header_for_blocks(blocks[1:2]) |
|
|
|
|
test_node.sync_with_ping() |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=direct_fetch_response_time) |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=DIRECT_FETCH_RESPONSE_TIME) |
|
|
|
|
|
|
|
|
|
# Announcing 16 more headers should trigger direct fetch for 14 more |
|
|
|
|
# blocks |
|
|
|
|
test_node.send_header_for_blocks(blocks[2:18]) |
|
|
|
|
test_node.sync_with_ping() |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=direct_fetch_response_time) |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=DIRECT_FETCH_RESPONSE_TIME) |
|
|
|
|
|
|
|
|
|
# Announcing 1 more header should not trigger any response |
|
|
|
|
test_node.last_message.pop("getdata", None) |
|
|
|
@ -502,7 +518,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -502,7 +518,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
self.log.info("Part 4: success!") |
|
|
|
|
|
|
|
|
|
# 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") |
|
|
|
|
# First we test that receipt of an unconnecting header doesn't prevent |
|
|
|
@ -524,7 +540,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -524,7 +540,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
test_node.wait_for_getheaders() |
|
|
|
|
test_node.send_header_for_blocks(blocks) |
|
|
|
|
test_node.wait_for_getdata([x.sha256 for x in blocks]) |
|
|
|
|
[ test_node.send_message(msg_block(x)) for x in blocks ] |
|
|
|
|
[test_node.send_message(msg_block(x)) for x in blocks] |
|
|
|
|
test_node.sync_with_ping() |
|
|
|
|
assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) |
|
|
|
|
|
|
|
|
@ -532,7 +548,7 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -532,7 +548,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
# Now we test that if we repeatedly don't send connecting headers, we |
|
|
|
|
# don't go into an infinite loop trying to get them to connect. |
|
|
|
|
MAX_UNCONNECTING_HEADERS = 10 |
|
|
|
|
for j in range(MAX_UNCONNECTING_HEADERS+1): |
|
|
|
|
for j in range(MAX_UNCONNECTING_HEADERS + 1): |
|
|
|
|
blocks.append(create_block(tip, create_coinbase(height), block_time)) |
|
|
|
|
blocks[-1].solve() |
|
|
|
|
tip = blocks[-1].sha256 |
|
|
|
@ -554,11 +570,11 @@ class SendHeadersTest(BitcoinTestFramework):
@@ -554,11 +570,11 @@ class SendHeadersTest(BitcoinTestFramework):
|
|
|
|
|
|
|
|
|
|
# Now try to see how many unconnecting headers we can send |
|
|
|
|
# before we get disconnected. Should be 5*MAX_UNCONNECTING_HEADERS |
|
|
|
|
for i in range(5*MAX_UNCONNECTING_HEADERS - 1): |
|
|
|
|
for i in range(5 * MAX_UNCONNECTING_HEADERS - 1): |
|
|
|
|
# Send a header that doesn't connect, check that we get a getheaders. |
|
|
|
|
with mininode_lock: |
|
|
|
|
test_node.last_message.pop("getheaders", None) |
|
|
|
|
test_node.send_header_for_blocks([blocks[i%len(blocks)]]) |
|
|
|
|
test_node.send_header_for_blocks([blocks[i % len(blocks)]]) |
|
|
|
|
test_node.wait_for_getheaders() |
|
|
|
|
|
|
|
|
|
# Eventually this stops working. |
|
|
|
|