Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_compactblocks.py
Show All 37 Lines | from test_framework.messages import ( | ||||
msg_sendheaders, | msg_sendheaders, | ||||
msg_tx, | msg_tx, | ||||
NODE_NETWORK, | NODE_NETWORK, | ||||
P2PHeaderAndShortIDs, | P2PHeaderAndShortIDs, | ||||
PrefilledTransaction, | PrefilledTransaction, | ||||
ToHex, | ToHex, | ||||
) | ) | ||||
from test_framework.mininode import ( | from test_framework.mininode import ( | ||||
mininode_lock, | p2p_lock, | ||||
P2PInterface, | P2PInterface, | ||||
) | ) | ||||
from test_framework.script import CScript, OP_TRUE | from test_framework.script import CScript, OP_TRUE | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.txtools import pad_tx | from test_framework.txtools import pad_tx | ||||
from test_framework.util import ( | from test_framework.util import ( | ||||
assert_equal, | assert_equal, | ||||
wait_until, | wait_until, | ||||
Show All 28 Lines | def on_headers(self, message): | ||||
self.announced_blockhashes.add(x.sha256) | self.announced_blockhashes.add(x.sha256) | ||||
def on_inv(self, message): | def on_inv(self, message): | ||||
for x in self.last_message["inv"].inv: | for x in self.last_message["inv"].inv: | ||||
if x.type == MSG_BLOCK: | if x.type == MSG_BLOCK: | ||||
self.block_announced = True | self.block_announced = True | ||||
self.announced_blockhashes.add(x.hash) | self.announced_blockhashes.add(x.hash) | ||||
# Requires caller to hold mininode_lock | # Requires caller to hold p2p_lock | ||||
def received_block_announcement(self): | def received_block_announcement(self): | ||||
return self.block_announced | return self.block_announced | ||||
def clear_block_announcement(self): | def clear_block_announcement(self): | ||||
with mininode_lock: | with p2p_lock: | ||||
self.block_announced = False | self.block_announced = False | ||||
self.last_message.pop("inv", None) | self.last_message.pop("inv", None) | ||||
self.last_message.pop("headers", None) | self.last_message.pop("headers", None) | ||||
self.last_message.pop("cmpctblock", None) | self.last_message.pop("cmpctblock", None) | ||||
def get_headers(self, locator, hashstop): | def get_headers(self, locator, hashstop): | ||||
msg = msg_getheaders() | msg = msg_getheaders() | ||||
msg.locator.vHave = locator | msg.locator.vHave = locator | ||||
msg.hashstop = hashstop | msg.hashstop = hashstop | ||||
self.send_message(msg) | self.send_message(msg) | ||||
def send_header_for_blocks(self, new_blocks): | def send_header_for_blocks(self, new_blocks): | ||||
headers_message = msg_headers() | 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) | self.send_message(headers_message) | ||||
def request_headers_and_sync(self, locator, hashstop=0): | def request_headers_and_sync(self, locator, hashstop=0): | ||||
self.clear_block_announcement() | self.clear_block_announcement() | ||||
self.get_headers(locator, hashstop) | self.get_headers(locator, hashstop) | ||||
wait_until(self.received_block_announcement, | wait_until(self.received_block_announcement, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
self.clear_block_announcement() | self.clear_block_announcement() | ||||
# Block until a block announcement for a particular block hash is | # Block until a block announcement for a particular block hash is | ||||
# received. | # received. | ||||
def wait_for_block_announcement(self, block_hash, timeout=30): | def wait_for_block_announcement(self, block_hash, timeout=30): | ||||
def received_hash(): | def received_hash(): | ||||
return (block_hash in self.announced_blockhashes) | return (block_hash in self.announced_blockhashes) | ||||
wait_until(received_hash, timeout=timeout, lock=mininode_lock) | wait_until(received_hash, timeout=timeout, lock=p2p_lock) | ||||
def send_await_disconnect(self, message, timeout=30): | def send_await_disconnect(self, message, timeout=30): | ||||
"""Sends a message to the node and wait for disconnect. | """Sends a message to the node and wait for disconnect. | ||||
This is used when we want to send a message into the node that we expect | This is used when we want to send a message into the node that we expect | ||||
will get us disconnected, eg an invalid block.""" | will get us disconnected, eg an invalid block.""" | ||||
self.send_message(message) | self.send_message(message) | ||||
wait_until(lambda: not self.is_connected, | wait_until(lambda: not self.is_connected, | ||||
timeout=timeout, lock=mininode_lock) | timeout=timeout, lock=p2p_lock) | ||||
class CompactBlocksTest(BitcoinTestFramework): | class CompactBlocksTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.num_nodes = 2 | self.num_nodes = 2 | ||||
self.extra_args = [["-acceptnonstdtxn=1"], | self.extra_args = [["-acceptnonstdtxn=1"], | ||||
["-txindex", "-acceptnonstdtxn=1"]] | ["-txindex", "-acceptnonstdtxn=1"]] | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | class CompactBlocksTest(BitcoinTestFramework): | ||||
# are made with compact blocks. | # are made with compact blocks. | ||||
# If old_node is passed in, request compact blocks with version=preferred-1 | # If old_node is passed in, request compact blocks with version=preferred-1 | ||||
# and verify that it receives block announcements via compact block. | # and verify that it receives block announcements via compact block. | ||||
def test_sendcmpct(self, node, test_node, | def test_sendcmpct(self, node, test_node, | ||||
preferred_version, old_node=None): | preferred_version, old_node=None): | ||||
# Make sure we get a SENDCMPCT message from our peer | # Make sure we get a SENDCMPCT message from our peer | ||||
def received_sendcmpct(): | def received_sendcmpct(): | ||||
return (len(test_node.last_sendcmpct) > 0) | return (len(test_node.last_sendcmpct) > 0) | ||||
wait_until(received_sendcmpct, timeout=30, lock=mininode_lock) | wait_until(received_sendcmpct, timeout=30, lock=p2p_lock) | ||||
with mininode_lock: | with p2p_lock: | ||||
# Check that the first version received is the preferred one | # Check that the first version received is the preferred one | ||||
assert_equal( | assert_equal( | ||||
test_node.last_sendcmpct[0].version, preferred_version) | test_node.last_sendcmpct[0].version, preferred_version) | ||||
# And that we receive versions down to 1. | # And that we receive versions down to 1. | ||||
assert_equal(test_node.last_sendcmpct[-1].version, 1) | assert_equal(test_node.last_sendcmpct[-1].version, 1) | ||||
test_node.last_sendcmpct = [] | test_node.last_sendcmpct = [] | ||||
tip = int(node.getbestblockhash(), 16) | tip = int(node.getbestblockhash(), 16) | ||||
def check_announcement_of_new_block(node, peer, predicate): | def check_announcement_of_new_block(node, peer, predicate): | ||||
peer.clear_block_announcement() | peer.clear_block_announcement() | ||||
block_hash = int(node.generate(1)[0], 16) | block_hash = int(node.generate(1)[0], 16) | ||||
peer.wait_for_block_announcement(block_hash, timeout=30) | peer.wait_for_block_announcement(block_hash, timeout=30) | ||||
assert peer.block_announced | assert peer.block_announced | ||||
with mininode_lock: | with p2p_lock: | ||||
assert predicate(peer), ( | assert predicate(peer), ( | ||||
"block_hash={!r}, cmpctblock={!r}, inv={!r}".format( | "block_hash={!r}, cmpctblock={!r}, inv={!r}".format( | ||||
block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None))) | block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None))) | ||||
# We shouldn't get any block announcements via cmpctblock yet. | # We shouldn't get any block announcements via cmpctblock yet. | ||||
check_announcement_of_new_block( | check_announcement_of_new_block( | ||||
node, test_node, lambda p: "cmpctblock" not in p.last_message) | node, test_node, lambda p: "cmpctblock" not in p.last_message) | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | def test_compactblock_construction(self, node, test_node): | ||||
block = FromHex(CBlock(), node.getblock( | block = FromHex(CBlock(), node.getblock( | ||||
"{:064x}".format(block_hash), False)) | "{:064x}".format(block_hash), False)) | ||||
for tx in block.vtx: | for tx in block.vtx: | ||||
tx.calc_sha256() | tx.calc_sha256() | ||||
block.rehash() | block.rehash() | ||||
# Wait until the block was announced (via compact blocks) | # Wait until the block was announced (via compact blocks) | ||||
wait_until(test_node.received_block_announcement, | wait_until(test_node.received_block_announcement, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
# Now fetch and check the compact block | # Now fetch and check the compact block | ||||
header_and_shortids = None | header_and_shortids = None | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "cmpctblock" in test_node.last_message | assert "cmpctblock" in test_node.last_message | ||||
# Convert the on-the-wire representation to absolute indexes | # Convert the on-the-wire representation to absolute indexes | ||||
header_and_shortids = HeaderAndShortIDs( | header_and_shortids = HeaderAndShortIDs( | ||||
test_node.last_message["cmpctblock"].header_and_shortids) | test_node.last_message["cmpctblock"].header_and_shortids) | ||||
self.check_compactblock_construction_from_block( | self.check_compactblock_construction_from_block( | ||||
header_and_shortids, block_hash, block) | header_and_shortids, block_hash, block) | ||||
# Now fetch the compact block using a normal non-announce getdata | # Now fetch the compact block using a normal non-announce getdata | ||||
test_node.clear_block_announcement() | test_node.clear_block_announcement() | ||||
inv = CInv(MSG_CMPCT_BLOCK, block_hash) | inv = CInv(MSG_CMPCT_BLOCK, block_hash) | ||||
test_node.send_message(msg_getdata([inv])) | test_node.send_message(msg_getdata([inv])) | ||||
wait_until(test_node.received_block_announcement, | wait_until(test_node.received_block_announcement, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
# Now fetch and check the compact block | # Now fetch and check the compact block | ||||
header_and_shortids = None | header_and_shortids = None | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "cmpctblock" in test_node.last_message | assert "cmpctblock" in test_node.last_message | ||||
# Convert the on-the-wire representation to absolute indexes | # Convert the on-the-wire representation to absolute indexes | ||||
header_and_shortids = HeaderAndShortIDs( | header_and_shortids = HeaderAndShortIDs( | ||||
test_node.last_message["cmpctblock"].header_and_shortids) | test_node.last_message["cmpctblock"].header_and_shortids) | ||||
self.check_compactblock_construction_from_block( | self.check_compactblock_construction_from_block( | ||||
header_and_shortids, block_hash, block) | header_and_shortids, block_hash, block) | ||||
def check_compactblock_construction_from_block( | def check_compactblock_construction_from_block( | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | def test_compactblock_requests(self, node, test_node, version): | ||||
# request | # request | ||||
for announce in ["inv", "header"]: | for announce in ["inv", "header"]: | ||||
block = self.build_block_on_tip(node) | block = self.build_block_on_tip(node) | ||||
if announce == "inv": | if announce == "inv": | ||||
test_node.send_message( | test_node.send_message( | ||||
msg_inv([CInv(MSG_BLOCK, block.sha256)])) | msg_inv([CInv(MSG_BLOCK, block.sha256)])) | ||||
wait_until(lambda: "getheaders" in test_node.last_message, | wait_until(lambda: "getheaders" in test_node.last_message, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
test_node.send_header_for_blocks([block]) | test_node.send_header_for_blocks([block]) | ||||
else: | else: | ||||
test_node.send_header_for_blocks([block]) | test_node.send_header_for_blocks([block]) | ||||
test_node.wait_for_getdata([block.sha256], timeout=30) | test_node.wait_for_getdata([block.sha256], timeout=30) | ||||
assert_equal(test_node.last_message["getdata"].inv[0].type, 4) | assert_equal(test_node.last_message["getdata"].inv[0].type, 4) | ||||
# Send back a compactblock message that omits the coinbase | # Send back a compactblock message that omits the coinbase | ||||
comp_block = HeaderAndShortIDs() | comp_block = HeaderAndShortIDs() | ||||
comp_block.header = CBlockHeader(block) | comp_block.header = CBlockHeader(block) | ||||
comp_block.nonce = 0 | comp_block.nonce = 0 | ||||
[k0, k1] = comp_block.get_siphash_keys() | [k0, k1] = comp_block.get_siphash_keys() | ||||
coinbase_hash = block.vtx[0].sha256 | coinbase_hash = block.vtx[0].sha256 | ||||
comp_block.shortids = [ | comp_block.shortids = [ | ||||
calculate_shortid(k0, k1, coinbase_hash)] | calculate_shortid(k0, k1, coinbase_hash)] | ||||
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) | test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) | ||||
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) | assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) | ||||
# Expect a getblocktxn message. | # Expect a getblocktxn message. | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "getblocktxn" in test_node.last_message | assert "getblocktxn" in test_node.last_message | ||||
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute( | absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute( | ||||
) | ) | ||||
assert_equal(absolute_indexes, [0]) # should be a coinbase request | assert_equal(absolute_indexes, [0]) # should be a coinbase request | ||||
# Send the coinbase, and verify that the tip advances. | # Send the coinbase, and verify that the tip advances. | ||||
msg = msg_blocktxn() | msg = msg_blocktxn() | ||||
msg.block_transactions.blockhash = block.sha256 | msg.block_transactions.blockhash = block.sha256 | ||||
Show All 25 Lines | class CompactBlocksTest(BitcoinTestFramework): | ||||
# Test that we only receive getblocktxn requests for transactions that the | # Test that we only receive getblocktxn requests for transactions that the | ||||
# node needs, and that responding to them causes the block to be | # node needs, and that responding to them causes the block to be | ||||
# reconstructed. | # reconstructed. | ||||
def test_getblocktxn_requests(self, node, test_node, version): | def test_getblocktxn_requests(self, node, test_node, version): | ||||
def test_getblocktxn_response(compact_block, peer, expected_result): | def test_getblocktxn_response(compact_block, peer, expected_result): | ||||
msg = msg_cmpctblock(compact_block.to_p2p()) | msg = msg_cmpctblock(compact_block.to_p2p()) | ||||
peer.send_and_ping(msg) | peer.send_and_ping(msg) | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "getblocktxn" in peer.last_message | assert "getblocktxn" in peer.last_message | ||||
absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute( | absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute( | ||||
) | ) | ||||
assert_equal(absolute_indexes, expected_result) | assert_equal(absolute_indexes, expected_result) | ||||
def test_tip_after_message(node, peer, msg, tip): | def test_tip_after_message(node, peer, msg, tip): | ||||
peer.send_and_ping(msg) | peer.send_and_ping(msg) | ||||
assert_equal(int(node.getbestblockhash(), 16), tip) | assert_equal(int(node.getbestblockhash(), 16), tip) | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | def test_getblocktxn_requests(self, node, test_node, version): | ||||
test_node.send_message(msg_tx(tx)) | test_node.send_message(msg_tx(tx)) | ||||
test_node.sync_with_ping() | test_node.sync_with_ping() | ||||
# Make sure all transactions were accepted. | # Make sure all transactions were accepted. | ||||
mempool = node.getrawmempool() | mempool = node.getrawmempool() | ||||
for tx in block.vtx[1:]: | for tx in block.vtx[1:]: | ||||
assert tx.hash in mempool | assert tx.hash in mempool | ||||
# Clear out last request. | # Clear out last request. | ||||
with mininode_lock: | with p2p_lock: | ||||
test_node.last_message.pop("getblocktxn", None) | test_node.last_message.pop("getblocktxn", None) | ||||
# Send compact block | # Send compact block | ||||
comp_block.initialize_from_block(block, prefill_list=[0]) | comp_block.initialize_from_block(block, prefill_list=[0]) | ||||
test_tip_after_message( | test_tip_after_message( | ||||
node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256) | node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256) | ||||
with mininode_lock: | with p2p_lock: | ||||
# Shouldn't have gotten a request for any transaction | # Shouldn't have gotten a request for any transaction | ||||
assert "getblocktxn" not in test_node.last_message | assert "getblocktxn" not in test_node.last_message | ||||
# Incorrectly responding to a getblocktxn shouldn't cause the block to be | # Incorrectly responding to a getblocktxn shouldn't cause the block to be | ||||
# permanently failed. | # permanently failed. | ||||
def test_incorrect_blocktxn_response(self, node, test_node, version): | def test_incorrect_blocktxn_response(self, node, test_node, version): | ||||
if (len(self.utxos) == 0): | if (len(self.utxos) == 0): | ||||
self.make_utxos() | self.make_utxos() | ||||
Show All 11 Lines | def test_incorrect_blocktxn_response(self, node, test_node, version): | ||||
for tx in ordered_txs[1:6]: | for tx in ordered_txs[1:6]: | ||||
assert tx.hash in mempool | assert tx.hash in mempool | ||||
# Send compact block | # Send compact block | ||||
comp_block = HeaderAndShortIDs() | comp_block = HeaderAndShortIDs() | ||||
comp_block.initialize_from_block(block, prefill_list=[0]) | comp_block.initialize_from_block(block, prefill_list=[0]) | ||||
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) | test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) | ||||
absolute_indices = [] | absolute_indices = [] | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "getblocktxn" in test_node.last_message | assert "getblocktxn" in test_node.last_message | ||||
absolute_indices = test_node.last_message["getblocktxn"].block_txn_request.to_absolute( | absolute_indices = test_node.last_message["getblocktxn"].block_txn_request.to_absolute( | ||||
) | ) | ||||
expected_indices = [] | expected_indices = [] | ||||
for i in [6, 7, 8, 9, 10]: | for i in [6, 7, 8, 9, 10]: | ||||
expected_indices.append(block.vtx.index(ordered_txs[i])) | expected_indices.append(block.vtx.index(ordered_txs[i])) | ||||
assert_equal(absolute_indices, sorted(expected_indices)) | assert_equal(absolute_indices, sorted(expected_indices)) | ||||
Show All 34 Lines | def test_getblocktxn_handler(self, node, test_node, version): | ||||
msg = msg_getblocktxn() | msg = msg_getblocktxn() | ||||
msg.block_txn_request = BlockTransactionsRequest( | msg.block_txn_request = BlockTransactionsRequest( | ||||
int(block_hash, 16), []) | int(block_hash, 16), []) | ||||
num_to_request = random.randint(1, len(block.vtx)) | num_to_request = random.randint(1, len(block.vtx)) | ||||
msg.block_txn_request.from_absolute( | msg.block_txn_request.from_absolute( | ||||
sorted(random.sample(range(len(block.vtx)), num_to_request))) | sorted(random.sample(range(len(block.vtx)), num_to_request))) | ||||
test_node.send_message(msg) | test_node.send_message(msg) | ||||
wait_until(lambda: "blocktxn" in test_node.last_message, | wait_until(lambda: "blocktxn" in test_node.last_message, | ||||
timeout=10, lock=mininode_lock) | timeout=10, lock=p2p_lock) | ||||
[tx.calc_sha256() for tx in block.vtx] | [tx.calc_sha256() for tx in block.vtx] | ||||
with mininode_lock: | with p2p_lock: | ||||
assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int( | assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int( | ||||
block_hash, 16)) | block_hash, 16)) | ||||
all_indices = msg.block_txn_request.to_absolute() | all_indices = msg.block_txn_request.to_absolute() | ||||
for index in all_indices: | for index in all_indices: | ||||
tx = test_node.last_message["blocktxn"].block_transactions.transactions.pop( | tx = test_node.last_message["blocktxn"].block_transactions.transactions.pop( | ||||
0) | 0) | ||||
tx.calc_sha256() | tx.calc_sha256() | ||||
assert_equal(tx.sha256, block.vtx[index].sha256) | assert_equal(tx.sha256, block.vtx[index].sha256) | ||||
test_node.last_message.pop("blocktxn", None) | test_node.last_message.pop("blocktxn", None) | ||||
current_height -= 1 | current_height -= 1 | ||||
# Next request should send a full block response, as we're past the | # Next request should send a full block response, as we're past the | ||||
# allowed depth for a blocktxn response. | # allowed depth for a blocktxn response. | ||||
block_hash = node.getblockhash(current_height) | block_hash = node.getblockhash(current_height) | ||||
msg.block_txn_request = BlockTransactionsRequest( | msg.block_txn_request = BlockTransactionsRequest( | ||||
int(block_hash, 16), [0]) | int(block_hash, 16), [0]) | ||||
with mininode_lock: | with p2p_lock: | ||||
test_node.last_message.pop("block", None) | test_node.last_message.pop("block", None) | ||||
test_node.last_message.pop("blocktxn", None) | test_node.last_message.pop("blocktxn", None) | ||||
test_node.send_and_ping(msg) | test_node.send_and_ping(msg) | ||||
with mininode_lock: | with p2p_lock: | ||||
test_node.last_message["block"].block.calc_sha256() | test_node.last_message["block"].block.calc_sha256() | ||||
assert_equal( | assert_equal( | ||||
test_node.last_message["block"].block.sha256, int(block_hash, 16)) | test_node.last_message["block"].block.sha256, int(block_hash, 16)) | ||||
assert "blocktxn" not in test_node.last_message | assert "blocktxn" not in test_node.last_message | ||||
def test_compactblocks_not_at_tip(self, node, test_node): | def test_compactblocks_not_at_tip(self, node, test_node): | ||||
# Test that requesting old compactblocks doesn't work. | # Test that requesting old compactblocks doesn't work. | ||||
MAX_CMPCTBLOCK_DEPTH = 5 | MAX_CMPCTBLOCK_DEPTH = 5 | ||||
new_blocks = [] | new_blocks = [] | ||||
for i in range(MAX_CMPCTBLOCK_DEPTH + 1): | for i in range(MAX_CMPCTBLOCK_DEPTH + 1): | ||||
test_node.clear_block_announcement() | test_node.clear_block_announcement() | ||||
new_blocks.append(node.generate(1)[0]) | new_blocks.append(node.generate(1)[0]) | ||||
wait_until(test_node.received_block_announcement, | wait_until(test_node.received_block_announcement, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
test_node.clear_block_announcement() | test_node.clear_block_announcement() | ||||
test_node.send_message(msg_getdata( | test_node.send_message(msg_getdata( | ||||
[CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) | [CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) | ||||
wait_until(lambda: "cmpctblock" in test_node.last_message, | wait_until(lambda: "cmpctblock" in test_node.last_message, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
test_node.clear_block_announcement() | test_node.clear_block_announcement() | ||||
node.generate(1) | node.generate(1) | ||||
wait_until(test_node.received_block_announcement, | wait_until(test_node.received_block_announcement, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
test_node.clear_block_announcement() | test_node.clear_block_announcement() | ||||
with mininode_lock: | with p2p_lock: | ||||
test_node.last_message.pop("block", None) | test_node.last_message.pop("block", None) | ||||
test_node.send_message(msg_getdata( | test_node.send_message(msg_getdata( | ||||
[CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) | [CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) | ||||
wait_until(lambda: "block" in test_node.last_message, | wait_until(lambda: "block" in test_node.last_message, | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
with mininode_lock: | with p2p_lock: | ||||
test_node.last_message["block"].block.calc_sha256() | test_node.last_message["block"].block.calc_sha256() | ||||
assert_equal( | assert_equal( | ||||
test_node.last_message["block"].block.sha256, int(new_blocks[0], 16)) | test_node.last_message["block"].block.sha256, int(new_blocks[0], 16)) | ||||
# Generate an old compactblock, and verify that it's not accepted. | # Generate an old compactblock, and verify that it's not accepted. | ||||
cur_height = node.getblockcount() | cur_height = node.getblockcount() | ||||
hashPrevBlock = int(node.getblockhash(cur_height - 5), 16) | hashPrevBlock = int(node.getblockhash(cur_height - 5), 16) | ||||
block = self.build_block_on_tip(node) | block = self.build_block_on_tip(node) | ||||
Show All 12 Lines | def test_compactblocks_not_at_tip(self, node, test_node): | ||||
found = True | found = True | ||||
break | break | ||||
assert found | assert found | ||||
# Requesting this block via getblocktxn should silently fail | # Requesting this block via getblocktxn should silently fail | ||||
# (to avoid fingerprinting attacks). | # (to avoid fingerprinting attacks). | ||||
msg = msg_getblocktxn() | msg = msg_getblocktxn() | ||||
msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0]) | msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0]) | ||||
with mininode_lock: | with p2p_lock: | ||||
test_node.last_message.pop("blocktxn", None) | test_node.last_message.pop("blocktxn", None) | ||||
test_node.send_and_ping(msg) | test_node.send_and_ping(msg) | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "blocktxn" not in test_node.last_message | assert "blocktxn" not in test_node.last_message | ||||
def test_end_to_end_block_relay(self, node, listeners): | def test_end_to_end_block_relay(self, node, listeners): | ||||
utxo = self.utxos.pop(0) | utxo = self.utxos.pop(0) | ||||
block, _ = self.build_block_with_transactions(node, utxo, 10) | block, _ = self.build_block_with_transactions(node, utxo, 10) | ||||
[listener.clear_block_announcement() for listener in listeners] | [listener.clear_block_announcement() for listener in listeners] | ||||
node.submitblock(ToHex(block)) | node.submitblock(ToHex(block)) | ||||
for listener in listeners: | for listener in listeners: | ||||
wait_until(lambda: listener.received_block_announcement(), | wait_until(lambda: listener.received_block_announcement(), | ||||
timeout=30, lock=mininode_lock) | timeout=30, lock=p2p_lock) | ||||
with mininode_lock: | with p2p_lock: | ||||
for listener in listeners: | for listener in listeners: | ||||
assert "cmpctblock" in listener.last_message | assert "cmpctblock" in listener.last_message | ||||
listener.last_message["cmpctblock"].header_and_shortids.header.calc_sha256( | listener.last_message["cmpctblock"].header_and_shortids.header.calc_sha256( | ||||
) | ) | ||||
assert_equal( | assert_equal( | ||||
listener.last_message["cmpctblock"].header_and_shortids.header.sha256, block.sha256) | listener.last_message["cmpctblock"].header_and_shortids.header.sha256, block.sha256) | ||||
# Test that we don't get disconnected if we relay a compact block with valid header, | # Test that we don't get disconnected if we relay a compact block with valid header, | ||||
Show All 36 Lines | def test_compactblock_reconstruction_multiple_peers( | ||||
def announce_cmpct_block(node, peer): | def announce_cmpct_block(node, peer): | ||||
utxo = self.utxos.pop(0) | utxo = self.utxos.pop(0) | ||||
block, _ = self.build_block_with_transactions(node, utxo, 5) | block, _ = self.build_block_with_transactions(node, utxo, 5) | ||||
cmpct_block = HeaderAndShortIDs() | cmpct_block = HeaderAndShortIDs() | ||||
cmpct_block.initialize_from_block(block) | cmpct_block.initialize_from_block(block) | ||||
msg = msg_cmpctblock(cmpct_block.to_p2p()) | msg = msg_cmpctblock(cmpct_block.to_p2p()) | ||||
peer.send_and_ping(msg) | peer.send_and_ping(msg) | ||||
with mininode_lock: | with p2p_lock: | ||||
assert "getblocktxn" in peer.last_message | assert "getblocktxn" in peer.last_message | ||||
return block, cmpct_block | return block, cmpct_block | ||||
block, cmpct_block = announce_cmpct_block(node, stalling_peer) | block, cmpct_block = announce_cmpct_block(node, stalling_peer) | ||||
for tx in block.vtx[1:]: | for tx in block.vtx[1:]: | ||||
delivery_peer.send_message(msg_tx(tx)) | delivery_peer.send_message(msg_tx(tx)) | ||||
delivery_peer.sync_with_ping() | delivery_peer.sync_with_ping() | ||||
▲ Show 20 Lines • Show All 119 Lines • Show Last 20 Lines |