1 #!/usr/bin/env python3
2 # Copyright (c) 2016-present The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """Test compact blocks (BIP 152)."""
6 import random
7 8 from test_framework.blocktools import (
9 COINBASE_MATURITY,
10 NORMAL_GBT_REQUEST_PARAMS,
11 add_witness_commitment,
12 create_block,
13 )
14 from test_framework.messages import (
15 BlockTransactions,
16 BlockTransactionsRequest,
17 CBlock,
18 CBlockHeader,
19 CInv,
20 COutPoint,
21 CTransaction,
22 CTxIn,
23 CTxInWitness,
24 CTxOut,
25 from_hex,
26 HeaderAndShortIDs,
27 MSG_BLOCK,
28 MSG_CMPCT_BLOCK,
29 MSG_WITNESS_FLAG,
30 P2PHeaderAndShortIDs,
31 PrefilledTransaction,
32 calculate_shortid,
33 msg_block,
34 msg_blocktxn,
35 msg_cmpctblock,
36 msg_getblocktxn,
37 msg_getdata,
38 msg_getheaders,
39 msg_headers,
40 msg_inv,
41 msg_no_witness_block,
42 msg_no_witness_blocktxn,
43 msg_sendcmpct,
44 msg_sendheaders,
45 msg_tx,
46 ser_uint256,
47 tx_from_hex,
48 )
49 from test_framework.p2p import (
50 P2PInterface,
51 p2p_lock,
52 )
53 from test_framework.script import (
54 CScript,
55 OP_DROP,
56 OP_TRUE,
57 OP_RETURN,
58 )
59 from test_framework.test_framework import BitcoinTestFramework
60 from test_framework.test_node import TestNode
61 from test_framework.util import (
62 assert_not_equal,
63 assert_equal,
64 softfork_active,
65 )
66 from test_framework.wallet import MiniWallet
67 68 69 # TestP2PConn: A peer we use to send messages to bitcoind, and store responses.
70 class TestP2PConn(P2PInterface):
71 def __init__(self):
72 super().__init__()
73 self.last_sendcmpct = []
74 self.block_announced = False
75 # Store the hashes of blocks we've seen announced.
76 # This is for synchronizing the p2p message traffic,
77 # so we can eg wait until a particular block is announced.
78 self.announced_blockhashes = set()
79 80 def on_sendcmpct(self, message):
81 self.last_sendcmpct.append(message)
82 83 def on_cmpctblock(self, message):
84 self.block_announced = True
85 self.announced_blockhashes.add(self.last_message["cmpctblock"].header_and_shortids.header.hash_int)
86 87 def on_headers(self, message):
88 self.block_announced = True
89 for x in self.last_message["headers"].headers:
90 self.announced_blockhashes.add(x.hash_int)
91 92 def on_inv(self, message):
93 for x in self.last_message["inv"].inv:
94 if x.type == MSG_BLOCK:
95 self.block_announced = True
96 self.announced_blockhashes.add(x.hash)
97 98 # Requires caller to hold p2p_lock
99 def received_block_announcement(self):
100 return self.block_announced
101 102 def clear_block_announcement(self):
103 with p2p_lock:
104 self.block_announced = False
105 self.last_message.pop("inv", None)
106 self.last_message.pop("headers", None)
107 self.last_message.pop("cmpctblock", None)
108 109 def clear_getblocktxn(self):
110 with p2p_lock:
111 self.last_message.pop("getblocktxn", None)
112 113 def get_headers(self, locator, hashstop):
114 msg = msg_getheaders()
115 msg.locator.vHave = locator
116 msg.hashstop = hashstop
117 self.send_without_ping(msg)
118 119 def send_header_for_blocks(self, new_blocks):
120 headers_message = msg_headers()
121 headers_message.headers = [CBlockHeader(b) for b in new_blocks]
122 self.send_without_ping(headers_message)
123 124 def request_headers_and_sync(self, locator, hashstop=0):
125 self.clear_block_announcement()
126 self.get_headers(locator, hashstop)
127 self.wait_until(self.received_block_announcement, timeout=30)
128 self.clear_block_announcement()
129 130 # Block until a block announcement for a particular block hash is
131 # received.
132 def wait_for_block_announcement(self, block_hash, timeout=30):
133 def received_hash():
134 return (block_hash in self.announced_blockhashes)
135 self.wait_until(received_hash, timeout=timeout)
136 137 def send_await_disconnect(self, message, timeout=30):
138 """Sends a message to the node and wait for disconnect.
139 140 This is used when we want to send a message into the node that we expect
141 will get us disconnected, eg an invalid block."""
142 self.send_without_ping(message)
143 self.wait_for_disconnect(timeout=timeout)
144 145 class CompactBlocksTest(BitcoinTestFramework):
146 def set_test_params(self):
147 self.setup_clean_chain = True
148 self.num_nodes = 1
149 self.extra_args = [[
150 "-acceptnonstdtxn=1",
151 ]]
152 self.utxos = []
153 154 def getblocktxn_expected(self, peer, blockhash, indices=None):
155 with p2p_lock:
156 assert "getblocktxn" in peer.last_message
157 gbt = peer.last_message["getblocktxn"].block_txn_request
158 159 assert_equal(gbt.blockhash, blockhash)
160 if indices is not None:
161 assert_equal(gbt.to_absolute(), indices)
162 if isinstance(peer, TestNode):
163 assert_not_equal(peer.getbestblockhash(), blockhash)
164 165 def build_block_on_tip(self, node):
166 block = create_block(tmpl=node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
167 block.solve()
168 return block
169 170 # Create 12 more anyone-can-spend utxo's for testing.
171 def make_utxos(self):
172 COUNT = 12
173 block = self.build_block_on_tip(self.nodes[0])
174 self.segwit_node.send_and_ping(msg_no_witness_block(block))
175 assert_equal(self.nodes[0].getbestblockhash(), block.hash_hex)
176 self.generate(self.wallet, COINBASE_MATURITY)
177 178 total_value = block.vtx[0].vout[0].nValue
179 out_value = total_value // COUNT
180 tx = CTransaction()
181 tx.vin.append(CTxIn(COutPoint(block.vtx[0].txid_int, 0), b''))
182 for _ in range(COUNT):
183 tx.vout.append(CTxOut(out_value, CScript([OP_TRUE])))
184 185 block2 = self.build_block_on_tip(self.nodes[0])
186 block2.vtx.append(tx)
187 block2.hashMerkleRoot = block2.calc_merkle_root()
188 block2.solve()
189 self.segwit_node.send_and_ping(msg_no_witness_block(block2))
190 assert_equal(self.nodes[0].getbestblockhash(), block2.hash_hex)
191 self.utxos.extend([[tx.txid_int, i, out_value] for i in range(COUNT)])
192 193 def announce_cmpct_block(self, node, peer, txn_count=5, solicit=False):
194 utxo = self.utxos.pop(0)
195 block = self.build_block_with_transactions(node, utxo, txn_count)
196 197 cmpct_block = HeaderAndShortIDs()
198 cmpct_block.initialize_from_block(block)
199 msg = msg_cmpctblock(cmpct_block.to_p2p())
200 if solicit:
201 peer.send_without_ping(msg_headers([block]))
202 peer.wait_for_getdata([block.hash_int], timeout=30)
203 204 peer.clear_getblocktxn()
205 peer.send_and_ping(msg)
206 self.getblocktxn_expected(peer, block.hash_int)
207 return block, cmpct_block
208 209 # Test "sendcmpct" (between peers preferring the same version):
210 # - No compact block announcements unless sendcmpct is sent.
211 # - If sendcmpct is sent with version = 1, the message is ignored.
212 # - If sendcmpct is sent with version > 2, the message is ignored.
213 # - If sendcmpct is sent with boolean 0, then block announcements are not
214 # made with compact blocks.
215 # - If sendcmpct is then sent with boolean 1, then new block announcements
216 # are made with compact blocks.
217 def test_sendcmpct(self, test_node):
218 node = self.nodes[0]
219 220 # Make sure we get a SENDCMPCT message from our peer
221 def received_sendcmpct():
222 return (len(test_node.last_sendcmpct) > 0)
223 test_node.wait_until(received_sendcmpct, timeout=30)
224 with p2p_lock:
225 # Check that version 2 is received.
226 assert_equal(test_node.last_sendcmpct[0].version, 2)
227 test_node.last_sendcmpct = []
228 229 tip = int(node.getbestblockhash(), 16)
230 231 def check_announcement_of_new_block(node, peer, predicate):
232 peer.clear_block_announcement()
233 block_hash = int(self.generate(node, 1)[0], 16)
234 peer.wait_for_block_announcement(block_hash, timeout=30)
235 assert peer.block_announced
236 237 with p2p_lock:
238 assert predicate(peer), (
239 "block_hash={!r}, cmpctblock={!r}, inv={!r}".format(
240 block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None)))
241 242 # We shouldn't get any block announcements via cmpctblock yet.
243 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
244 245 # Try one more time, this time after requesting headers.
246 test_node.request_headers_and_sync(locator=[tip])
247 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "inv" in p.last_message)
248 249 # Test a few ways of using sendcmpct that should NOT
250 # result in compact block announcements.
251 # Before each test, sync the headers chain.
252 test_node.request_headers_and_sync(locator=[tip])
253 254 # Now try a SENDCMPCT message with too-low version
255 test_node.send_and_ping(msg_sendcmpct(announce=True, version=1))
256 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
257 258 # Headers sync before next test.
259 test_node.request_headers_and_sync(locator=[tip])
260 261 # Now try a SENDCMPCT message with too-high version
262 test_node.send_and_ping(msg_sendcmpct(announce=True, version=3))
263 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
264 265 # Headers sync before next test.
266 test_node.request_headers_and_sync(locator=[tip])
267 268 # Now try a SENDCMPCT message with valid version, but announce=False
269 test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
270 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
271 272 # Headers sync before next test.
273 test_node.request_headers_and_sync(locator=[tip])
274 275 # Finally, try a SENDCMPCT message with announce=True
276 test_node.send_and_ping(msg_sendcmpct(announce=True, version=2))
277 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
278 279 # Try one more time (no headers sync should be needed!)
280 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
281 282 # Try one more time, after turning on sendheaders
283 test_node.send_and_ping(msg_sendheaders())
284 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
285 286 # Try one more time, after sending a version=1, announce=false message.
287 test_node.send_and_ping(msg_sendcmpct(announce=False, version=1))
288 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
289 290 # Now turn off announcements
291 test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
292 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "headers" in p.last_message)
293 294 # BIP152 mandates that the announce field of a sendcmpct message is a
295 # boolean and MUST have a value of either 1 or 0. Sending any other value
296 # should be treated as misbehavior and lead to a disconnect.
297 def test_invalid_sendcmpct_announce(self):
298 node = self.nodes[0]
299 bad_peer = node.add_p2p_connection(TestP2PConn())
300 msg = msg_sendcmpct(announce=2, version=2)
301 with node.assert_debug_log(['invalid sendcmpct announce field']):
302 bad_peer.send_await_disconnect(msg)
303 304 # This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
305 # Note, these are not consensus-invalid blocks, but improperly constructed cmpctblock messages.
306 def test_invalid_cmpctblock_message(self):
307 # Make a high-bandwidth peer
308 hb_peer = self.nodes[0].add_p2p_connection(TestP2PConn())
309 self.request_cb_announcements(hb_peer)
310 self.make_peer_hb_to_candidate(self.nodes[0], hb_peer)
311 self.assert_highbandwidth_states(self.nodes[0], idx=-1, hb_to=True, hb_from=True)
312 313 # Make a low-bandwidth peer
314 lb_peer = self.nodes[0].add_p2p_connection(TestP2PConn())
315 self.request_cb_announcements(lb_peer)
316 self.assert_highbandwidth_states(self.nodes[0], idx=-1, hb_to=False, hb_from=True)
317 318 # Construct an invalid cmpctblock message
319 self.generate(self.nodes[0], COINBASE_MATURITY + 1)
320 block = self.build_block_on_tip(self.nodes[0])
321 cmpct_block = P2PHeaderAndShortIDs()
322 cmpct_block.header = CBlockHeader(block)
323 cmpct_block.prefilled_txn_length = 1
324 too_high_prefill_idx = 1
325 prefilled_txn = PrefilledTransaction(too_high_prefill_idx, block.vtx[0])
326 cmpct_block.prefilled_txn = [prefilled_txn]
327 328 # Test an unsolicited invalid cmpctblock from an HB peer.
329 hb_peer.send_await_disconnect(msg_cmpctblock(cmpct_block))
330 assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
331 332 # Test a solicited invalid cmpctblock from a non-HB peer.
333 lb_peer.send_header_for_blocks([block])
334 lb_peer.wait_for_getdata([block.hash_int], timeout=30)
335 lb_peer.send_await_disconnect(msg_cmpctblock(cmpct_block))
336 assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
337 338 # Compare the generated shortids to what we expect based on BIP 152, given
339 # bitcoind's choice of nonce.
340 def test_compactblock_construction(self, test_node):
341 node = self.nodes[0]
342 # Generate a bunch of transactions.
343 self.generate(node, COINBASE_MATURITY + 1)
344 num_transactions = 25
345 346 segwit_tx_generated = False
347 for _ in range(num_transactions):
348 hex_tx = self.wallet.send_self_transfer(from_node=self.nodes[0])['hex']
349 tx = tx_from_hex(hex_tx)
350 if not tx.wit.is_null():
351 segwit_tx_generated = True
352 353 assert segwit_tx_generated # check that our test is not broken
354 355 # Wait until we've seen the block announcement for the resulting tip
356 tip = int(node.getbestblockhash(), 16)
357 test_node.wait_for_block_announcement(tip)
358 359 # Make sure we will receive a fast-announce compact block
360 self.request_cb_announcements(test_node)
361 362 # Now mine a block, and look at the resulting compact block.
363 test_node.clear_block_announcement()
364 block_hash = int(self.generate(node, 1)[0], 16)
365 366 # Store the raw block in our internal format.
367 block = from_hex(CBlock(), node.getblock("%064x" % block_hash, False))
368 369 # Wait until the block was announced (via compact blocks)
370 test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)
371 372 # Now fetch and check the compact block
373 header_and_shortids = None
374 with p2p_lock:
375 # Convert the on-the-wire representation to absolute indexes
376 header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
377 self.check_compactblock_construction_from_block(header_and_shortids, block_hash, block)
378 379 # Now fetch the compact block using a normal non-announce getdata
380 test_node.clear_block_announcement()
381 inv = CInv(MSG_CMPCT_BLOCK, block_hash)
382 test_node.send_without_ping(msg_getdata([inv]))
383 384 test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)
385 386 # Now fetch and check the compact block
387 header_and_shortids = None
388 with p2p_lock:
389 # Convert the on-the-wire representation to absolute indexes
390 header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
391 self.check_compactblock_construction_from_block(header_and_shortids, block_hash, block)
392 393 def check_compactblock_construction_from_block(self, header_and_shortids, block_hash, block):
394 # Check that we got the right block!
395 assert_equal(header_and_shortids.header.hash_int, block_hash)
396 397 # Make sure the prefilled_txn appears to have included the coinbase
398 assert len(header_and_shortids.prefilled_txn) >= 1
399 assert_equal(header_and_shortids.prefilled_txn[0].index, 0)
400 401 # Check that all prefilled_txn entries match what's in the block.
402 for entry in header_and_shortids.prefilled_txn:
403 # This checks the non-witness parts of the tx agree
404 assert_equal(entry.tx.txid_hex, block.vtx[entry.index].txid_hex)
405 406 # And this checks the witness
407 assert_equal(entry.tx.wtxid_hex, block.vtx[entry.index].wtxid_hex)
408 409 # Check that the cmpctblock message announced all the transactions.
410 assert_equal(len(header_and_shortids.prefilled_txn) + len(header_and_shortids.shortids), len(block.vtx))
411 412 # And now check that all the shortids are as expected as well.
413 # Determine the siphash keys to use.
414 [k0, k1] = header_and_shortids.get_siphash_keys()
415 416 index = 0
417 while index < len(block.vtx):
418 if (len(header_and_shortids.prefilled_txn) > 0 and
419 header_and_shortids.prefilled_txn[0].index == index):
420 # Already checked prefilled transactions above
421 header_and_shortids.prefilled_txn.pop(0)
422 else:
423 tx_hash = block.vtx[index].wtxid_int
424 shortid = calculate_shortid(k0, k1, tx_hash)
425 assert_equal(shortid, header_and_shortids.shortids[0])
426 header_and_shortids.shortids.pop(0)
427 index += 1
428 429 # Test that bitcoind requests compact blocks when we announce new blocks
430 # via header or inv, and that responding to getblocktxn causes the block
431 # to be successfully reconstructed.
432 def test_compactblock_requests(self, test_node):
433 node = self.nodes[0]
434 # Try announcing a block with an inv or header, expect a compactblock
435 # request
436 for announce in ["inv", "header"]:
437 block = self.build_block_on_tip(node)
438 439 if announce == "inv":
440 test_node.send_without_ping(msg_inv([CInv(MSG_BLOCK, block.hash_int)]))
441 test_node.wait_for_getheaders(timeout=30)
442 test_node.send_header_for_blocks([block])
443 else:
444 test_node.send_header_for_blocks([block])
445 test_node.wait_for_getdata([block.hash_int], timeout=30)
446 assert_equal(test_node.last_message["getdata"].inv[0].type, 4)
447 448 # Send back a compactblock message that omits the coinbase
449 comp_block = HeaderAndShortIDs()
450 comp_block.header = CBlockHeader(block)
451 comp_block.nonce = 0
452 [k0, k1] = comp_block.get_siphash_keys()
453 coinbase_hash = block.vtx[0].wtxid_int
454 comp_block.shortids = [calculate_shortid(k0, k1, coinbase_hash)]
455 test_node.clear_getblocktxn()
456 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
457 assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
458 # Expect a getblocktxn message that requests the coinbase.
459 self.getblocktxn_expected(test_node, block.hash_int, indices=[0])
460 461 # Send the coinbase, and verify that the tip advances.
462 msg = msg_blocktxn()
463 msg.block_transactions.blockhash = block.hash_int
464 msg.block_transactions.transactions = [block.vtx[0]]
465 test_node.send_and_ping(msg)
466 assert_equal(node.getbestblockhash(), block.hash_hex)
467 468 # Create a chain of transactions from given utxo, and add to a new block.
469 def build_block_with_transactions(self, node, utxo, num_transactions):
470 block = self.build_block_on_tip(node)
471 472 for _ in range(num_transactions):
473 tx = CTransaction()
474 tx.vin.append(CTxIn(COutPoint(utxo[0], utxo[1]), b''))
475 tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
476 utxo = [tx.txid_int, 0, tx.vout[0].nValue]
477 block.vtx.append(tx)
478 479 block.hashMerkleRoot = block.calc_merkle_root()
480 block.solve()
481 return block
482 483 # Test that we only receive getblocktxn requests for transactions that the
484 # node needs, and that responding to them causes the block to be
485 # reconstructed.
486 def test_getblocktxn_requests(self, test_node):
487 node = self.nodes[0]
488 489 def test_getblocktxn_response(compact_block, peer, expected_result):
490 msg = msg_cmpctblock(compact_block.to_p2p())
491 peer.clear_getblocktxn()
492 peer.send_and_ping(msg)
493 self.getblocktxn_expected(peer, compact_block.header.hash_int, expected_result)
494 495 def test_tip_after_message(node, peer, msg, tip):
496 peer.send_and_ping(msg)
497 assert_equal(int(node.getbestblockhash(), 16), tip)
498 499 # First try announcing compactblocks that won't reconstruct, and verify
500 # that we receive getblocktxn messages back.
501 utxo = self.utxos.pop(0)
502 503 block = self.build_block_with_transactions(node, utxo, 5)
504 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
505 comp_block = HeaderAndShortIDs()
506 comp_block.initialize_from_block(block, use_witness=True)
507 508 test_getblocktxn_response(comp_block, test_node, [1, 2, 3, 4, 5])
509 510 msg_bt = msg_no_witness_blocktxn()
511 msg_bt = msg_blocktxn() # serialize with witnesses
512 msg_bt.block_transactions = BlockTransactions(block.hash_int, block.vtx[1:])
513 test_tip_after_message(node, test_node, msg_bt, block.hash_int)
514 515 utxo = self.utxos.pop(0)
516 block = self.build_block_with_transactions(node, utxo, 5)
517 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
518 519 # Now try interspersing the prefilled transactions
520 comp_block.initialize_from_block(block, prefill_list=[0, 1, 5], use_witness=True)
521 test_getblocktxn_response(comp_block, test_node, [2, 3, 4])
522 msg_bt.block_transactions = BlockTransactions(block.hash_int, block.vtx[2:5])
523 test_tip_after_message(node, test_node, msg_bt, block.hash_int)
524 525 # Now try giving one transaction ahead of time.
526 utxo = self.utxos.pop(0)
527 block = self.build_block_with_transactions(node, utxo, 5)
528 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
529 test_node.send_and_ping(msg_tx(block.vtx[1]))
530 assert block.vtx[1].txid_hex in node.getrawmempool()
531 532 # Prefill 4 out of the 6 transactions, and verify that only the one
533 # that was not in the mempool is requested.
534 comp_block.initialize_from_block(block, prefill_list=[0, 2, 3, 4], use_witness=True)
535 test_getblocktxn_response(comp_block, test_node, [5])
536 537 msg_bt.block_transactions = BlockTransactions(block.hash_int, [block.vtx[5]])
538 test_tip_after_message(node, test_node, msg_bt, block.hash_int)
539 540 # Now provide all transactions to the node before the block is
541 # announced and verify reconstruction happens immediately.
542 utxo = self.utxos.pop(0)
543 block = self.build_block_with_transactions(node, utxo, 10)
544 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
545 for tx in block.vtx[1:]:
546 test_node.send_without_ping(msg_tx(tx))
547 test_node.sync_with_ping()
548 # Make sure all transactions were accepted.
549 mempool = node.getrawmempool()
550 for tx in block.vtx[1:]:
551 assert tx.txid_hex in mempool
552 553 # Clear out last request.
554 test_node.clear_getblocktxn()
555 556 # Send compact block
557 comp_block.initialize_from_block(block, prefill_list=[0], use_witness=True)
558 test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.hash_int)
559 with p2p_lock:
560 # Shouldn't have gotten a request for any transaction
561 assert "getblocktxn" not in test_node.last_message
562 563 # Incorrectly responding to a getblocktxn shouldn't cause the block to be
564 # permanently failed.
565 def test_incorrect_blocktxn_response(self, test_node):
566 node = self.nodes[0]
567 utxo = self.utxos.pop(0)
568 569 block = self.build_block_with_transactions(node, utxo, 10)
570 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
571 # Relay the first 5 transactions from the block in advance
572 for tx in block.vtx[1:6]:
573 test_node.send_without_ping(msg_tx(tx))
574 test_node.sync_with_ping()
575 # Make sure all transactions were accepted.
576 mempool = node.getrawmempool()
577 for tx in block.vtx[1:6]:
578 assert tx.txid_hex in mempool
579 580 # Send compact block
581 comp_block = HeaderAndShortIDs()
582 comp_block.initialize_from_block(block, prefill_list=[0], use_witness=True)
583 test_node.clear_getblocktxn()
584 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
585 expected_indices = [6, 7, 8, 9, 10]
586 self.getblocktxn_expected(test_node, block.hash_int, expected_indices)
587 588 # Now give an incorrect response.
589 # Note that it's possible for bitcoind to be smart enough to know we're
590 # lying, since it could check to see if the shortid matches what we're
591 # sending, and eg disconnect us for misbehavior. If that behavior
592 # change was made, we could just modify this test by having a
593 # different peer provide the block further down, so that we're still
594 # verifying that the block isn't marked bad permanently. This is good
595 # enough for now.
596 msg = msg_blocktxn()
597 msg.block_transactions = BlockTransactions(block.hash_int, [block.vtx[5]] + block.vtx[7:])
598 test_node.send_and_ping(msg)
599 600 # Tip should not have updated
601 assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
602 603 # We should receive a getdata request
604 test_node.wait_for_getdata([block.hash_int], timeout=10)
605 assert test_node.last_message["getdata"].inv[0].type in (MSG_BLOCK, MSG_BLOCK | MSG_WITNESS_FLAG)
606 607 # Deliver the block
608 test_node.send_and_ping(msg_block(block))
609 assert_equal(node.getbestblockhash(), block.hash_hex)
610 611 # Multiple blocktxn responses will cause a node to get disconnected.
612 def test_multiple_blocktxn_response(self, test_node):
613 node = self.nodes[0]
614 utxo = self.utxos.pop(0)
615 616 block = self.build_block_with_transactions(node, utxo, 2)
617 618 # The attacker sends the block header so that we request it.
619 test_node.send_without_ping(msg_headers([block]))
620 test_node.wait_for_getdata([block.hash_int], timeout=30)
621 622 # Send compact block
623 comp_block = HeaderAndShortIDs()
624 comp_block.initialize_from_block(block, prefill_list=[0], use_witness=True)
625 test_node.clear_getblocktxn()
626 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
627 self.getblocktxn_expected(test_node, block.hash_int, indices=[1,2])
628 629 # Send a blocktxn that does not succeed in reconstruction, triggering
630 # getdata fallback.
631 msg = msg_blocktxn()
632 msg.block_transactions = BlockTransactions(block.hash_int, [block.vtx[2]] + [block.vtx[1]])
633 test_node.send_and_ping(msg)
634 635 # Tip should not have updated
636 assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
637 638 # We should receive a getdata request
639 test_node.wait_for_getdata([block.hash_int], timeout=10)
640 assert test_node.last_message["getdata"].inv[0].type in (MSG_BLOCK, MSG_BLOCK | MSG_WITNESS_FLAG)
641 642 # Send the same blocktxn and assert the sender gets disconnected.
643 with node.assert_debug_log(['previous compact block reconstruction attempt failed']):
644 test_node.send_without_ping(msg)
645 test_node.wait_for_disconnect()
646 647 def test_getblocktxn_handler(self, test_node):
648 node = self.nodes[0]
649 # bitcoind will not send blocktxn responses for blocks whose height is
650 # more than 10 blocks deep.
651 MAX_GETBLOCKTXN_DEPTH = 10
652 chain_height = node.getblockcount()
653 current_height = chain_height
654 while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH):
655 block_hash = node.getblockhash(current_height)
656 block = from_hex(CBlock(), node.getblock(block_hash, False))
657 658 msg = msg_getblocktxn()
659 msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [])
660 num_to_request = random.randint(1, len(block.vtx))
661 msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
662 test_node.send_without_ping(msg)
663 test_node.wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10)
664 665 with p2p_lock:
666 assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int(block_hash, 16))
667 all_indices = msg.block_txn_request.to_absolute()
668 for index in all_indices:
669 tx = test_node.last_message["blocktxn"].block_transactions.transactions.pop(0)
670 assert_equal(tx.txid_hex, block.vtx[index].txid_hex)
671 # Check that the witness matches
672 assert_equal(tx.wtxid_hex, block.vtx[index].wtxid_hex)
673 test_node.last_message.pop("blocktxn", None)
674 current_height -= 1
675 676 # Next request should send a full block response, as we're past the
677 # allowed depth for a blocktxn response.
678 block_hash = node.getblockhash(current_height)
679 msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])
680 with p2p_lock:
681 test_node.last_message.pop("block", None)
682 test_node.last_message.pop("blocktxn", None)
683 test_node.send_and_ping(msg)
684 with p2p_lock:
685 assert_equal(test_node.last_message["block"].block.hash_hex, block_hash)
686 assert "blocktxn" not in test_node.last_message
687 688 # Request with out-of-bounds tx index results in disconnect
689 bad_peer = self.nodes[0].add_p2p_connection(TestP2PConn())
690 block_hash = node.getblockhash(chain_height)
691 block = from_hex(CBlock(), node.getblock(block_hash, False))
692 msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [len(block.vtx)])
693 with node.assert_debug_log(['getblocktxn with out-of-bounds tx indices']):
694 bad_peer.send_without_ping(msg)
695 bad_peer.wait_for_disconnect()
696 697 def test_low_work_compactblocks(self, test_node):
698 # A compactblock with insufficient work won't get its header included
699 node = self.nodes[0]
700 hashPrevBlock = int(node.getblockhash(node.getblockcount() - 150), 16)
701 block = self.build_block_on_tip(node)
702 block.hashPrevBlock = hashPrevBlock
703 block.solve()
704 705 comp_block = HeaderAndShortIDs()
706 comp_block.initialize_from_block(block)
707 with self.nodes[0].assert_debug_log(['[net] Ignoring low-work compact block from peer 0']):
708 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
709 710 tips = node.getchaintips()
711 found = False
712 for x in tips:
713 if x["hash"] == block.hash_hex:
714 found = True
715 break
716 assert not found
717 718 def test_compactblocks_not_at_tip(self, test_node):
719 node = self.nodes[0]
720 # Test that requesting old compactblocks doesn't work.
721 MAX_CMPCTBLOCK_DEPTH = 5
722 new_blocks = []
723 for _ in range(MAX_CMPCTBLOCK_DEPTH + 1):
724 test_node.clear_block_announcement()
725 new_blocks.append(self.generate(node, 1)[0])
726 test_node.wait_until(test_node.received_block_announcement, timeout=30)
727 728 test_node.clear_block_announcement()
729 test_node.send_without_ping(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))]))
730 test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)
731 732 test_node.clear_block_announcement()
733 self.generate(node, 1)
734 test_node.wait_until(test_node.received_block_announcement, timeout=30)
735 test_node.clear_block_announcement()
736 with p2p_lock:
737 test_node.last_message.pop("block", None)
738 test_node.send_without_ping(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))]))
739 test_node.wait_until(lambda: "block" in test_node.last_message, timeout=30)
740 with p2p_lock:
741 assert_equal(test_node.last_message["block"].block.hash_hex, new_blocks[0])
742 743 # Generate an old compactblock, and verify that it's not accepted.
744 cur_height = node.getblockcount()
745 hashPrevBlock = int(node.getblockhash(cur_height - 5), 16)
746 block = self.build_block_on_tip(node)
747 block.hashPrevBlock = hashPrevBlock
748 block.solve()
749 750 comp_block = HeaderAndShortIDs()
751 comp_block.initialize_from_block(block)
752 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
753 754 tips = node.getchaintips()
755 found = False
756 for x in tips:
757 if x["hash"] == block.hash_hex:
758 assert_equal(x["status"], "headers-only")
759 found = True
760 break
761 assert found
762 763 # Requesting this block via getblocktxn should silently fail
764 # (to avoid fingerprinting attacks).
765 msg = msg_getblocktxn()
766 msg.block_txn_request = BlockTransactionsRequest(block.hash_int, [0])
767 with p2p_lock:
768 test_node.last_message.pop("blocktxn", None)
769 test_node.send_and_ping(msg)
770 with p2p_lock:
771 assert "blocktxn" not in test_node.last_message
772 773 def test_end_to_end_block_relay(self, listeners):
774 node = self.nodes[0]
775 utxo = self.utxos.pop(0)
776 777 block = self.build_block_with_transactions(node, utxo, 10)
778 779 [l.clear_block_announcement() for l in listeners]
780 781 # serialize without witness (this block has no witnesses anyway).
782 # TODO: repeat this test with witness tx's to a segwit node.
783 node.submitblock(block.serialize().hex())
784 785 for l in listeners:
786 l.wait_until(lambda: "cmpctblock" in l.last_message, timeout=30)
787 with p2p_lock:
788 for l in listeners:
789 assert_equal(l.last_message["cmpctblock"].header_and_shortids.header.hash_int, block.hash_int)
790 791 # Test that we don't get disconnected if we relay a compact block with valid header,
792 # but invalid transactions.
793 def test_invalid_tx_in_compactblock(self, test_node):
794 node = self.nodes[0]
795 utxo = self.utxos.pop(0)
796 797 block = self.build_block_with_transactions(node, utxo, 5)
798 block.hashMerkleRoot = block.calc_merkle_root()
799 # Drop the coinbase witness but include the witness commitment.
800 add_witness_commitment(block)
801 block.vtx[0].wit.vtxinwit = []
802 block.solve()
803 804 # Now send the compact block with all transactions prefilled, and
805 # verify that we don't get disconnected.
806 comp_block = HeaderAndShortIDs()
807 comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)
808 msg = msg_cmpctblock(comp_block.to_p2p())
809 test_node.send_and_ping(msg)
810 811 # Check that the tip didn't advance
812 assert_not_equal(node.getbestblockhash(), block.hash_hex)
813 test_node.sync_with_ping()
814 815 # Re-establish a proper witness commitment with the coinbase witness, but
816 # invalidate the last tx in the block.
817 block.vtx[4].vin[0].scriptSig = CScript([OP_RETURN])
818 block.hashMerkleRoot = block.calc_merkle_root()
819 add_witness_commitment(block)
820 block.solve()
821 822 # This will lead to a consensus failure for which we also won't be disconnected but which
823 # will be cached.
824 comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)
825 msg = msg_cmpctblock(comp_block.to_p2p())
826 test_node.send_and_ping(msg)
827 828 # The tip still didn't advance.
829 assert_not_equal(node.getbestblockhash(), block.hash_hex)
830 test_node.sync_with_ping()
831 832 # The failure above was cached. Submitting the compact block again will return a cached
833 # consensus error (the code path is different) and still not get us disconnected (nor
834 # advance the tip).
835 test_node.send_and_ping(msg)
836 assert_not_equal(node.getbestblockhash(), block.hash_hex)
837 test_node.sync_with_ping()
838 839 # Now, announcing a second block building on top of the invalid one will get us disconnected.
840 block.hashPrevBlock = block.hash_int
841 block.solve()
842 comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)
843 msg = msg_cmpctblock(comp_block.to_p2p())
844 test_node.send_await_disconnect(msg)
845 846 # peer generates a block and sends it to node, which makes the peer a
847 # candidate for high-bandwidth 'to' (up to 3 peers according to BIP 152)
848 def make_peer_hb_to_candidate(self, node, peer):
849 block = self.build_block_on_tip(node)
850 peer.send_and_ping(msg_block(block))
851 852 # Helper for enabling cb announcements
853 # Send the sendcmpct request and sync headers
854 def request_cb_announcements(self, peer):
855 node = self.nodes[0]
856 tip = node.getbestblockhash()
857 peer.get_headers(locator=[int(tip, 16)], hashstop=0)
858 peer.send_and_ping(msg_sendcmpct(announce=True, version=2))
859 860 def test_compactblock_reconstruction_stalling_peer(self, stalling_peer, delivery_peer):
861 node = self.nodes[0]
862 863 self.make_peer_hb_to_candidate(node, delivery_peer)
864 block, cmpct_block = self.announce_cmpct_block(node, stalling_peer)
865 866 for tx in block.vtx[1:]:
867 delivery_peer.send_without_ping(msg_tx(tx))
868 delivery_peer.sync_with_ping()
869 mempool = node.getrawmempool()
870 for tx in block.vtx[1:]:
871 assert tx.txid_hex in mempool
872 873 delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
874 assert_equal(node.getbestblockhash(), block.hash_hex)
875 876 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
877 878 # Now test that delivering an invalid compact block won't break relay
879 880 block, cmpct_block = self.announce_cmpct_block(node, stalling_peer)
881 for tx in block.vtx[1:]:
882 delivery_peer.send_without_ping(msg_tx(tx))
883 delivery_peer.sync_with_ping()
884 885 cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()]
886 cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
887 888 cmpct_block.use_witness = True
889 delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
890 assert_not_equal(node.getbestblockhash(), block.hash_hex)
891 892 msg = msg_no_witness_blocktxn()
893 msg.block_transactions.blockhash = block.hash_int
894 msg.block_transactions.transactions = block.vtx[1:]
895 stalling_peer.send_and_ping(msg)
896 assert_equal(node.getbestblockhash(), block.hash_hex)
897 898 # assert the RPC getpeerinfo boolean fields `bip152_hb_{to, from}`
899 # match the given parameters for the peer at idx of a given node
900 @staticmethod
901 def assert_highbandwidth_states(node, idx, hb_to, hb_from):
902 peerinfo = node.getpeerinfo()[idx]
903 assert_equal(peerinfo['bip152_hb_to'], hb_to)
904 assert_equal(peerinfo['bip152_hb_from'], hb_from)
905 906 def test_highbandwidth_mode_states_via_getpeerinfo(self):
907 # create new p2p connection for a fresh state w/o any prior sendcmpct messages sent
908 hb_test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
909 910 # Newly created hb_test_node is the last connection.
911 hb_test_node_idx = -1
912 913 # initially, neither node has selected the other peer as high-bandwidth yet
914 self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=False, hb_from=False)
915 916 # peer requests high-bandwidth mode by sending sendcmpct(1)
917 hb_test_node.send_and_ping(msg_sendcmpct(announce=True, version=2))
918 self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=False, hb_from=True)
919 920 # peer generates a block and sends it to node, which should
921 # select the peer as high-bandwidth (up to 3 peers according to BIP 152)
922 block = self.build_block_on_tip(self.nodes[0])
923 hb_test_node.send_and_ping(msg_block(block))
924 self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=True, hb_from=True)
925 926 # peer requests low-bandwidth mode by sending sendcmpct(0)
927 hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
928 self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=True, hb_from=False)
929 930 def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):
931 """ All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot
932 can only be taken by an outbound node unless prior attempts were done by an outbound
933 """
934 node = self.nodes[0]
935 936 for name, peer in [("delivery", delivery_peer), ("inbound", inbound_peer), ("outbound", outbound_peer)]:
937 self.log.info(f"Setting {name} as high bandwidth peer")
938 self.make_peer_hb_to_candidate(node, peer)
939 block, cmpct_block = self.announce_cmpct_block(node, peer, 1)
940 msg = msg_blocktxn()
941 msg.block_transactions.blockhash = block.hash_int
942 msg.block_transactions.transactions = block.vtx[1:]
943 peer.send_and_ping(msg)
944 assert_equal(node.getbestblockhash(), block.hash_hex)
945 peer.clear_getblocktxn()
946 947 # Test the simple parallel download case...
948 for num_missing in [1, 5, 20]:
949 delivery_peer.clear_getblocktxn()
950 inbound_peer.clear_getblocktxn()
951 outbound_peer.clear_getblocktxn()
952 953 # Remaining low-bandwidth peer is stalling_peer, who announces first
954 assert_equal([peer['bip152_hb_to'] for peer in node.getpeerinfo()], [False, True, True, True])
955 956 block, cmpct_block = self.announce_cmpct_block(node, stalling_peer, num_missing, solicit=True)
957 958 delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
959 # The second peer to announce should still get a getblocktxn
960 self.getblocktxn_expected(delivery_peer, block.hash_int)
961 962 inbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
963 with p2p_lock:
964 # The third inbound peer to announce should *not* get a getblocktxn
965 assert "getblocktxn" not in inbound_peer.last_message
966 assert_not_equal(node.getbestblockhash(), block.hash_hex)
967 968 outbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
969 # The third peer to announce should get a getblocktxn if outbound
970 self.getblocktxn_expected(outbound_peer, block.hash_int)
971 972 # Second peer completes the compact block first
973 msg = msg_blocktxn()
974 msg.block_transactions.blockhash = block.hash_int
975 msg.block_transactions.transactions = block.vtx[1:]
976 delivery_peer.send_and_ping(msg)
977 assert_equal(node.getbestblockhash(), block.hash_hex)
978 979 # Nothing bad should happen if we get a late fill from the first peer...
980 stalling_peer.send_and_ping(msg)
981 self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])
982 983 def test_compact_blocks_ignored(self):
984 node = self.nodes[0]
985 986 def build_compact_block():
987 # generate a compact block to send that will force a GETBLOCKTXN
988 utxo = self.utxos.pop(0)
989 block = self.build_block_with_transactions(node, utxo, 10)
990 cmpct_block = HeaderAndShortIDs()
991 cmpct_block.initialize_from_block(block)
992 msg = msg_cmpctblock(cmpct_block.to_p2p())
993 return block, msg
994 995 # Sends a compact block, uses presence of GETBLOCKTXN as a heuristic
996 # for whether or not the node processed the CMPCTBLOCK.
997 # Note: since we never fulfill the GETBLOCKTXN, this will never change
998 # the HB status of a connection.
999 def ignores_compact_block(conn, solicited=False):
1000 block, msg = build_compact_block()
1001 conn.clear_getblocktxn()
1002 if solicited:
1003 conn.send_without_ping(msg_headers([block]))
1004 conn.wait_for_getdata([block.hash_int], timeout=30)
1005 conn.send_and_ping(msg)
1006 with p2p_lock:
1007 return "getblocktxn" not in conn.last_message
1008 1009 # create new p2p connection for a fresh state w/o any prior sendcmpct messages sent
1010 unsolicited_peer = self.nodes[0].add_p2p_connection(TestP2PConn())
1011 self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
1012 1013 self.log.info("Test that a node ignores unsolicited CMPCTBLOCK messages from peers that have not sent SENDCMPCT.")
1014 assert ignores_compact_block(unsolicited_peer, solicited=False)
1015 1016 self.log.info("Test that a node ignores solicited CMPCTBLOCK messages from peers that have not sent SENDCMPCT.")
1017 assert ignores_compact_block(unsolicited_peer, solicited=True)
1018 1019 # Unsolicited peer announces CMPCTBLOCK support with SENDCMPCT message,
1020 # but still non-HB.
1021 unsolicited_peer.send_and_ping(msg_sendcmpct())
1022 self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
1023 1024 self.log.info("Test that a node ignores unsolicited CMPCTBLOCK messages from non-HB peers.")
1025 assert ignores_compact_block(unsolicited_peer, solicited=False)
1026 self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
1027 1028 self.log.info("Test that a node does not ignore solicited CMPCTBLOCK messages from non-HB peers.")
1029 assert not ignores_compact_block(unsolicited_peer, solicited=True)
1030 self.assert_highbandwidth_states(node, idx=-1, hb_to=False, hb_from=False)
1031 1032 # The node will ask for transactions from an unsolicited compact block
1033 # it receives from a high bandwidth peer, we need to use one set up earlier,
1034 # since all the slots are full.
1035 self.log.info("Test that a node does not ignore unsolicited CMPCTBLOCK messages from HB peers.")
1036 1037 hb_peer_idx = -2
1038 self.assert_highbandwidth_states(node, idx=hb_peer_idx, hb_to=True, hb_from=False)
1039 hb_peer = self.nodes[0].p2ps[hb_peer_idx]
1040 assert not ignores_compact_block(hb_peer, solicited=False)
1041 1042 def run_test(self):
1043 self.wallet = MiniWallet(self.nodes[0])
1044 1045 # Setup the p2p connections
1046 self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
1047 self.additional_segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
1048 self.onemore_inbound_node = self.nodes[0].add_p2p_connection(TestP2PConn())
1049 self.outbound_node = self.nodes[0].add_outbound_p2p_connection(TestP2PConn(), p2p_idx=3, connection_type="outbound-full-relay")
1050 1051 # We will need UTXOs to construct transactions in later tests.
1052 self.make_utxos()
1053 1054 assert softfork_active(self.nodes[0], "segwit")
1055 1056 self.log.info("Testing SENDCMPCT p2p message... ")
1057 self.test_sendcmpct(self.segwit_node)
1058 self.test_sendcmpct(self.additional_segwit_node)
1059 self.test_sendcmpct(self.onemore_inbound_node)
1060 self.test_sendcmpct(self.outbound_node)
1061 1062 self.log.info("Testing compactblock construction...")
1063 self.test_compactblock_construction(self.segwit_node)
1064 1065 self.log.info("Testing compactblock requests (segwit node)... ")
1066 self.test_compactblock_requests(self.segwit_node)
1067 1068 self.log.info("Testing getblocktxn requests (segwit node)...")
1069 self.test_getblocktxn_requests(self.segwit_node)
1070 1071 self.log.info("Testing getblocktxn handler (segwit node should return witnesses)...")
1072 self.test_getblocktxn_handler(self.segwit_node)
1073 1074 self.log.info("Testing compactblock requests/announcements not at chain tip...")
1075 self.test_compactblocks_not_at_tip(self.segwit_node)
1076 1077 self.log.info("Testing handling of low-work compact blocks...")
1078 self.test_low_work_compactblocks(self.segwit_node)
1079 1080 self.log.info("Testing handling of incorrect blocktxn responses...")
1081 self.test_incorrect_blocktxn_response(self.segwit_node)
1082 1083 self.log.info("Testing reconstructing compact blocks with a stalling peer...")
1084 self.test_compactblock_reconstruction_stalling_peer(self.segwit_node, self.additional_segwit_node)
1085 1086 self.log.info("Testing reconstructing compact blocks from multiple peers...")
1087 self.test_compactblock_reconstruction_parallel_reconstruction(stalling_peer=self.segwit_node, inbound_peer=self.onemore_inbound_node, delivery_peer=self.additional_segwit_node, outbound_peer=self.outbound_node)
1088 1089 # Test that if we submitblock to node1, we'll get a compact block
1090 # announcement to all peers.
1091 # (Post-segwit activation, blocks won't propagate from node0 to node1
1092 # automatically, so don't bother testing a block announced to node0.)
1093 self.log.info("Testing end-to-end block relay...")
1094 self.request_cb_announcements(self.segwit_node)
1095 self.request_cb_announcements(self.additional_segwit_node)
1096 self.test_end_to_end_block_relay([self.segwit_node, self.additional_segwit_node])
1097 1098 self.log.info("Testing handling of invalid compact blocks...")
1099 self.test_invalid_tx_in_compactblock(self.segwit_node)
1100 1101 # The previous test will lead to a disconnection. Reconnect before continuing.
1102 self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
1103 self.segwit_node.send_and_ping(msg_sendcmpct())
1104 1105 self.log.info("Testing handling of multiple blocktxn responses...")
1106 self.test_multiple_blocktxn_response(self.segwit_node)
1107 1108 # The previous test will lead to a disconnection. Reconnect before continuing.
1109 self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
1110 self.segwit_node.send_and_ping(msg_sendcmpct())
1111 1112 self.log.info("Testing invalid announce field in sendcmpct message...")
1113 self.test_invalid_sendcmpct_announce()
1114 1115 self.log.info("Testing invalid index in cmpctblock message...")
1116 self.test_invalid_cmpctblock_message()
1117 1118 self.log.info("Testing high-bandwidth mode states via getpeerinfo...")
1119 self.test_highbandwidth_mode_states_via_getpeerinfo()
1120 1121 self.log.info("Testing CMPCTBLOCK messages are ignored when expected...")
1122 self.test_compact_blocks_ignored()
1123 1124 1125 if __name__ == '__main__':
1126 CompactBlocksTest(__file__).main()
1127