Merge #11726: Cleanups + nit fixes for walletdir PR
[bitcoinplatinum.git] / test / functional / p2p-compactblocks.py
blob1e763df2a4012862706815f21a2a1742c85a2949
1 #!/usr/bin/env python3
2 # Copyright (c) 2016 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).
7 Version 1 compact blocks are pre-segwit (txids)
8 Version 2 compact blocks are post-segwit (wtxids)
9 """
11 from test_framework.mininode import *
12 from test_framework.test_framework import BitcoinTestFramework
13 from test_framework.util import *
14 from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
15 from test_framework.script import CScript, OP_TRUE
17 # TestNode: A peer we use to send messages to bitcoind, and store responses.
18 class TestNode(P2PInterface):
19 def __init__(self):
20 super().__init__()
21 self.last_sendcmpct = []
22 self.block_announced = False
23 # Store the hashes of blocks we've seen announced.
24 # This is for synchronizing the p2p message traffic,
25 # so we can eg wait until a particular block is announced.
26 self.announced_blockhashes = set()
28 def on_sendcmpct(self, message):
29 self.last_sendcmpct.append(message)
31 def on_cmpctblock(self, message):
32 self.block_announced = True
33 self.last_message["cmpctblock"].header_and_shortids.header.calc_sha256()
34 self.announced_blockhashes.add(self.last_message["cmpctblock"].header_and_shortids.header.sha256)
36 def on_headers(self, message):
37 self.block_announced = True
38 for x in self.last_message["headers"].headers:
39 x.calc_sha256()
40 self.announced_blockhashes.add(x.sha256)
42 def on_inv(self, message):
43 for x in self.last_message["inv"].inv:
44 if x.type == 2:
45 self.block_announced = True
46 self.announced_blockhashes.add(x.hash)
48 # Requires caller to hold mininode_lock
49 def received_block_announcement(self):
50 return self.block_announced
52 def clear_block_announcement(self):
53 with mininode_lock:
54 self.block_announced = False
55 self.last_message.pop("inv", None)
56 self.last_message.pop("headers", None)
57 self.last_message.pop("cmpctblock", None)
59 def get_headers(self, locator, hashstop):
60 msg = msg_getheaders()
61 msg.locator.vHave = locator
62 msg.hashstop = hashstop
63 self.send_message(msg)
65 def send_header_for_blocks(self, new_blocks):
66 headers_message = msg_headers()
67 headers_message.headers = [CBlockHeader(b) for b in new_blocks]
68 self.send_message(headers_message)
70 def request_headers_and_sync(self, locator, hashstop=0):
71 self.clear_block_announcement()
72 self.get_headers(locator, hashstop)
73 wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock)
74 self.clear_block_announcement()
76 # Block until a block announcement for a particular block hash is
77 # received.
78 def wait_for_block_announcement(self, block_hash, timeout=30):
79 def received_hash():
80 return (block_hash in self.announced_blockhashes)
81 wait_until(received_hash, timeout=timeout, lock=mininode_lock)
83 def send_await_disconnect(self, message, timeout=30):
84 """Sends a message to the node and wait for disconnect.
86 This is used when we want to send a message into the node that we expect
87 will get us disconnected, eg an invalid block."""
88 self.send_message(message)
89 wait_until(lambda: self.state != "connected", timeout=timeout, lock=mininode_lock)
91 class CompactBlocksTest(BitcoinTestFramework):
92 def set_test_params(self):
93 self.setup_clean_chain = True
94 # Node0 = pre-segwit, node1 = segwit-aware
95 self.num_nodes = 2
96 # This test was written assuming SegWit is activated using BIP9 at height 432 (3x confirmation window).
97 # TODO: Rewrite this test to support SegWit being always active.
98 self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex"]]
99 self.utxos = []
101 def build_block_on_tip(self, node, segwit=False):
102 height = node.getblockcount()
103 tip = node.getbestblockhash()
104 mtp = node.getblockheader(tip)['mediantime']
105 block = create_block(int(tip, 16), create_coinbase(height + 1), mtp + 1)
106 block.nVersion = 4
107 if segwit:
108 add_witness_commitment(block)
109 block.solve()
110 return block
112 # Create 10 more anyone-can-spend utxo's for testing.
113 def make_utxos(self):
114 # Doesn't matter which node we use, just use node0.
115 block = self.build_block_on_tip(self.nodes[0])
116 self.test_node.send_and_ping(msg_block(block))
117 assert(int(self.nodes[0].getbestblockhash(), 16) == block.sha256)
118 self.nodes[0].generate(100)
120 total_value = block.vtx[0].vout[0].nValue
121 out_value = total_value // 10
122 tx = CTransaction()
123 tx.vin.append(CTxIn(COutPoint(block.vtx[0].sha256, 0), b''))
124 for i in range(10):
125 tx.vout.append(CTxOut(out_value, CScript([OP_TRUE])))
126 tx.rehash()
128 block2 = self.build_block_on_tip(self.nodes[0])
129 block2.vtx.append(tx)
130 block2.hashMerkleRoot = block2.calc_merkle_root()
131 block2.solve()
132 self.test_node.send_and_ping(msg_block(block2))
133 assert_equal(int(self.nodes[0].getbestblockhash(), 16), block2.sha256)
134 self.utxos.extend([[tx.sha256, i, out_value] for i in range(10)])
135 return
137 # Test "sendcmpct" (between peers preferring the same version):
138 # - No compact block announcements unless sendcmpct is sent.
139 # - If sendcmpct is sent with version > preferred_version, the message is ignored.
140 # - If sendcmpct is sent with boolean 0, then block announcements are not
141 # made with compact blocks.
142 # - If sendcmpct is then sent with boolean 1, then new block announcements
143 # are made with compact blocks.
144 # If old_node is passed in, request compact blocks with version=preferred-1
145 # and verify that it receives block announcements via compact block.
146 def test_sendcmpct(self, node, test_node, preferred_version, old_node=None):
147 # Make sure we get a SENDCMPCT message from our peer
148 def received_sendcmpct():
149 return (len(test_node.last_sendcmpct) > 0)
150 wait_until(received_sendcmpct, timeout=30, lock=mininode_lock)
151 with mininode_lock:
152 # Check that the first version received is the preferred one
153 assert_equal(test_node.last_sendcmpct[0].version, preferred_version)
154 # And that we receive versions down to 1.
155 assert_equal(test_node.last_sendcmpct[-1].version, 1)
156 test_node.last_sendcmpct = []
158 tip = int(node.getbestblockhash(), 16)
160 def check_announcement_of_new_block(node, peer, predicate):
161 peer.clear_block_announcement()
162 block_hash = int(node.generate(1)[0], 16)
163 peer.wait_for_block_announcement(block_hash, timeout=30)
164 assert(peer.block_announced)
166 with mininode_lock:
167 assert predicate(peer), (
168 "block_hash={!r}, cmpctblock={!r}, inv={!r}".format(
169 block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None)))
171 # We shouldn't get any block announcements via cmpctblock yet.
172 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
174 # Try one more time, this time after requesting headers.
175 test_node.request_headers_and_sync(locator=[tip])
176 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "inv" in p.last_message)
178 # Test a few ways of using sendcmpct that should NOT
179 # result in compact block announcements.
180 # Before each test, sync the headers chain.
181 test_node.request_headers_and_sync(locator=[tip])
183 # Now try a SENDCMPCT message with too-high version
184 sendcmpct = msg_sendcmpct()
185 sendcmpct.version = preferred_version+1
186 sendcmpct.announce = True
187 test_node.send_and_ping(sendcmpct)
188 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
190 # Headers sync before next test.
191 test_node.request_headers_and_sync(locator=[tip])
193 # Now try a SENDCMPCT message with valid version, but announce=False
194 sendcmpct.version = preferred_version
195 sendcmpct.announce = False
196 test_node.send_and_ping(sendcmpct)
197 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
199 # Headers sync before next test.
200 test_node.request_headers_and_sync(locator=[tip])
202 # Finally, try a SENDCMPCT message with announce=True
203 sendcmpct.version = preferred_version
204 sendcmpct.announce = True
205 test_node.send_and_ping(sendcmpct)
206 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
208 # Try one more time (no headers sync should be needed!)
209 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
211 # Try one more time, after turning on sendheaders
212 test_node.send_and_ping(msg_sendheaders())
213 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
215 # Try one more time, after sending a version-1, announce=false message.
216 sendcmpct.version = preferred_version-1
217 sendcmpct.announce = False
218 test_node.send_and_ping(sendcmpct)
219 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
221 # Now turn off announcements
222 sendcmpct.version = preferred_version
223 sendcmpct.announce = False
224 test_node.send_and_ping(sendcmpct)
225 check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "headers" in p.last_message)
227 if old_node is not None:
228 # Verify that a peer using an older protocol version can receive
229 # announcements from this node.
230 sendcmpct.version = preferred_version-1
231 sendcmpct.announce = True
232 old_node.send_and_ping(sendcmpct)
233 # Header sync
234 old_node.request_headers_and_sync(locator=[tip])
235 check_announcement_of_new_block(node, old_node, lambda p: "cmpctblock" in p.last_message)
237 # This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
238 def test_invalid_cmpctblock_message(self):
239 self.nodes[0].generate(101)
240 block = self.build_block_on_tip(self.nodes[0])
242 cmpct_block = P2PHeaderAndShortIDs()
243 cmpct_block.header = CBlockHeader(block)
244 cmpct_block.prefilled_txn_length = 1
245 # This index will be too high
246 prefilled_txn = PrefilledTransaction(1, block.vtx[0])
247 cmpct_block.prefilled_txn = [prefilled_txn]
248 self.test_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
249 assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
251 # Compare the generated shortids to what we expect based on BIP 152, given
252 # bitcoind's choice of nonce.
253 def test_compactblock_construction(self, node, test_node, version, use_witness_address):
254 # Generate a bunch of transactions.
255 node.generate(101)
256 num_transactions = 25
257 address = node.getnewaddress()
258 if use_witness_address:
259 # Want at least one segwit spend, so move all funds to
260 # a witness address.
261 address = node.addwitnessaddress(address)
262 value_to_send = node.getbalance()
263 node.sendtoaddress(address, satoshi_round(value_to_send-Decimal(0.1)))
264 node.generate(1)
266 segwit_tx_generated = False
267 for i in range(num_transactions):
268 txid = node.sendtoaddress(address, 0.1)
269 hex_tx = node.gettransaction(txid)["hex"]
270 tx = FromHex(CTransaction(), hex_tx)
271 if not tx.wit.is_null():
272 segwit_tx_generated = True
274 if use_witness_address:
275 assert(segwit_tx_generated) # check that our test is not broken
277 # Wait until we've seen the block announcement for the resulting tip
278 tip = int(node.getbestblockhash(), 16)
279 test_node.wait_for_block_announcement(tip)
281 # Make sure we will receive a fast-announce compact block
282 self.request_cb_announcements(test_node, node, version)
284 # Now mine a block, and look at the resulting compact block.
285 test_node.clear_block_announcement()
286 block_hash = int(node.generate(1)[0], 16)
288 # Store the raw block in our internal format.
289 block = FromHex(CBlock(), node.getblock("%02x" % block_hash, False))
290 for tx in block.vtx:
291 tx.calc_sha256()
292 block.rehash()
294 # Wait until the block was announced (via compact blocks)
295 wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
297 # Now fetch and check the compact block
298 header_and_shortids = None
299 with mininode_lock:
300 assert("cmpctblock" in test_node.last_message)
301 # Convert the on-the-wire representation to absolute indexes
302 header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
303 self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
305 # Now fetch the compact block using a normal non-announce getdata
306 with mininode_lock:
307 test_node.clear_block_announcement()
308 inv = CInv(4, block_hash) # 4 == "CompactBlock"
309 test_node.send_message(msg_getdata([inv]))
311 wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
313 # Now fetch and check the compact block
314 header_and_shortids = None
315 with mininode_lock:
316 assert("cmpctblock" in test_node.last_message)
317 # Convert the on-the-wire representation to absolute indexes
318 header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
319 self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
321 def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
322 # Check that we got the right block!
323 header_and_shortids.header.calc_sha256()
324 assert_equal(header_and_shortids.header.sha256, block_hash)
326 # Make sure the prefilled_txn appears to have included the coinbase
327 assert(len(header_and_shortids.prefilled_txn) >= 1)
328 assert_equal(header_and_shortids.prefilled_txn[0].index, 0)
330 # Check that all prefilled_txn entries match what's in the block.
331 for entry in header_and_shortids.prefilled_txn:
332 entry.tx.calc_sha256()
333 # This checks the non-witness parts of the tx agree
334 assert_equal(entry.tx.sha256, block.vtx[entry.index].sha256)
336 # And this checks the witness
337 wtxid = entry.tx.calc_sha256(True)
338 if version == 2:
339 assert_equal(wtxid, block.vtx[entry.index].calc_sha256(True))
340 else:
341 # Shouldn't have received a witness
342 assert(entry.tx.wit.is_null())
344 # Check that the cmpctblock message announced all the transactions.
345 assert_equal(len(header_and_shortids.prefilled_txn) + len(header_and_shortids.shortids), len(block.vtx))
347 # And now check that all the shortids are as expected as well.
348 # Determine the siphash keys to use.
349 [k0, k1] = header_and_shortids.get_siphash_keys()
351 index = 0
352 while index < len(block.vtx):
353 if (len(header_and_shortids.prefilled_txn) > 0 and
354 header_and_shortids.prefilled_txn[0].index == index):
355 # Already checked prefilled transactions above
356 header_and_shortids.prefilled_txn.pop(0)
357 else:
358 tx_hash = block.vtx[index].sha256
359 if version == 2:
360 tx_hash = block.vtx[index].calc_sha256(True)
361 shortid = calculate_shortid(k0, k1, tx_hash)
362 assert_equal(shortid, header_and_shortids.shortids[0])
363 header_and_shortids.shortids.pop(0)
364 index += 1
366 # Test that bitcoind requests compact blocks when we announce new blocks
367 # via header or inv, and that responding to getblocktxn causes the block
368 # to be successfully reconstructed.
369 # Post-segwit: upgraded nodes would only make this request of cb-version-2,
370 # NODE_WITNESS peers. Unupgraded nodes would still make this request of
371 # any cb-version-1-supporting peer.
372 def test_compactblock_requests(self, node, test_node, version, segwit):
373 # Try announcing a block with an inv or header, expect a compactblock
374 # request
375 for announce in ["inv", "header"]:
376 block = self.build_block_on_tip(node, segwit=segwit)
377 with mininode_lock:
378 test_node.last_message.pop("getdata", None)
380 if announce == "inv":
381 test_node.send_message(msg_inv([CInv(2, block.sha256)]))
382 wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock)
383 test_node.send_header_for_blocks([block])
384 else:
385 test_node.send_header_for_blocks([block])
386 wait_until(lambda: "getdata" in test_node.last_message, timeout=30, lock=mininode_lock)
387 assert_equal(len(test_node.last_message["getdata"].inv), 1)
388 assert_equal(test_node.last_message["getdata"].inv[0].type, 4)
389 assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
391 # Send back a compactblock message that omits the coinbase
392 comp_block = HeaderAndShortIDs()
393 comp_block.header = CBlockHeader(block)
394 comp_block.nonce = 0
395 [k0, k1] = comp_block.get_siphash_keys()
396 coinbase_hash = block.vtx[0].sha256
397 if version == 2:
398 coinbase_hash = block.vtx[0].calc_sha256(True)
399 comp_block.shortids = [
400 calculate_shortid(k0, k1, coinbase_hash) ]
401 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
402 assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
403 # Expect a getblocktxn message.
404 with mininode_lock:
405 assert("getblocktxn" in test_node.last_message)
406 absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
407 assert_equal(absolute_indexes, [0]) # should be a coinbase request
409 # Send the coinbase, and verify that the tip advances.
410 if version == 2:
411 msg = msg_witness_blocktxn()
412 else:
413 msg = msg_blocktxn()
414 msg.block_transactions.blockhash = block.sha256
415 msg.block_transactions.transactions = [block.vtx[0]]
416 test_node.send_and_ping(msg)
417 assert_equal(int(node.getbestblockhash(), 16), block.sha256)
419 # Create a chain of transactions from given utxo, and add to a new block.
420 def build_block_with_transactions(self, node, utxo, num_transactions):
421 block = self.build_block_on_tip(node)
423 for i in range(num_transactions):
424 tx = CTransaction()
425 tx.vin.append(CTxIn(COutPoint(utxo[0], utxo[1]), b''))
426 tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE])))
427 tx.rehash()
428 utxo = [tx.sha256, 0, tx.vout[0].nValue]
429 block.vtx.append(tx)
431 block.hashMerkleRoot = block.calc_merkle_root()
432 block.solve()
433 return block
435 # Test that we only receive getblocktxn requests for transactions that the
436 # node needs, and that responding to them causes the block to be
437 # reconstructed.
438 def test_getblocktxn_requests(self, node, test_node, version):
439 with_witness = (version==2)
441 def test_getblocktxn_response(compact_block, peer, expected_result):
442 msg = msg_cmpctblock(compact_block.to_p2p())
443 peer.send_and_ping(msg)
444 with mininode_lock:
445 assert("getblocktxn" in peer.last_message)
446 absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute()
447 assert_equal(absolute_indexes, expected_result)
449 def test_tip_after_message(node, peer, msg, tip):
450 peer.send_and_ping(msg)
451 assert_equal(int(node.getbestblockhash(), 16), tip)
453 # First try announcing compactblocks that won't reconstruct, and verify
454 # that we receive getblocktxn messages back.
455 utxo = self.utxos.pop(0)
457 block = self.build_block_with_transactions(node, utxo, 5)
458 self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
459 comp_block = HeaderAndShortIDs()
460 comp_block.initialize_from_block(block, use_witness=with_witness)
462 test_getblocktxn_response(comp_block, test_node, [1, 2, 3, 4, 5])
464 msg_bt = msg_blocktxn()
465 if with_witness:
466 msg_bt = msg_witness_blocktxn() # serialize with witnesses
467 msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[1:])
468 test_tip_after_message(node, test_node, msg_bt, block.sha256)
470 utxo = self.utxos.pop(0)
471 block = self.build_block_with_transactions(node, utxo, 5)
472 self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
474 # Now try interspersing the prefilled transactions
475 comp_block.initialize_from_block(block, prefill_list=[0, 1, 5], use_witness=with_witness)
476 test_getblocktxn_response(comp_block, test_node, [2, 3, 4])
477 msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[2:5])
478 test_tip_after_message(node, test_node, msg_bt, block.sha256)
480 # Now try giving one transaction ahead of time.
481 utxo = self.utxos.pop(0)
482 block = self.build_block_with_transactions(node, utxo, 5)
483 self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
484 test_node.send_and_ping(msg_tx(block.vtx[1]))
485 assert(block.vtx[1].hash in node.getrawmempool())
487 # Prefill 4 out of the 6 transactions, and verify that only the one
488 # that was not in the mempool is requested.
489 comp_block.initialize_from_block(block, prefill_list=[0, 2, 3, 4], use_witness=with_witness)
490 test_getblocktxn_response(comp_block, test_node, [5])
492 msg_bt.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]])
493 test_tip_after_message(node, test_node, msg_bt, block.sha256)
495 # Now provide all transactions to the node before the block is
496 # announced and verify reconstruction happens immediately.
497 utxo = self.utxos.pop(0)
498 block = self.build_block_with_transactions(node, utxo, 10)
499 self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
500 for tx in block.vtx[1:]:
501 test_node.send_message(msg_tx(tx))
502 test_node.sync_with_ping()
503 # Make sure all transactions were accepted.
504 mempool = node.getrawmempool()
505 for tx in block.vtx[1:]:
506 assert(tx.hash in mempool)
508 # Clear out last request.
509 with mininode_lock:
510 test_node.last_message.pop("getblocktxn", None)
512 # Send compact block
513 comp_block.initialize_from_block(block, prefill_list=[0], use_witness=with_witness)
514 test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256)
515 with mininode_lock:
516 # Shouldn't have gotten a request for any transaction
517 assert("getblocktxn" not in test_node.last_message)
519 # Incorrectly responding to a getblocktxn shouldn't cause the block to be
520 # permanently failed.
521 def test_incorrect_blocktxn_response(self, node, test_node, version):
522 if (len(self.utxos) == 0):
523 self.make_utxos()
524 utxo = self.utxos.pop(0)
526 block = self.build_block_with_transactions(node, utxo, 10)
527 self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
528 # Relay the first 5 transactions from the block in advance
529 for tx in block.vtx[1:6]:
530 test_node.send_message(msg_tx(tx))
531 test_node.sync_with_ping()
532 # Make sure all transactions were accepted.
533 mempool = node.getrawmempool()
534 for tx in block.vtx[1:6]:
535 assert(tx.hash in mempool)
537 # Send compact block
538 comp_block = HeaderAndShortIDs()
539 comp_block.initialize_from_block(block, prefill_list=[0], use_witness=(version == 2))
540 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
541 absolute_indexes = []
542 with mininode_lock:
543 assert("getblocktxn" in test_node.last_message)
544 absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
545 assert_equal(absolute_indexes, [6, 7, 8, 9, 10])
547 # Now give an incorrect response.
548 # Note that it's possible for bitcoind to be smart enough to know we're
549 # lying, since it could check to see if the shortid matches what we're
550 # sending, and eg disconnect us for misbehavior. If that behavior
551 # change were made, we could just modify this test by having a
552 # different peer provide the block further down, so that we're still
553 # verifying that the block isn't marked bad permanently. This is good
554 # enough for now.
555 msg = msg_blocktxn()
556 if version==2:
557 msg = msg_witness_blocktxn()
558 msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:])
559 test_node.send_and_ping(msg)
561 # Tip should not have updated
562 assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
564 # We should receive a getdata request
565 wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock)
566 assert_equal(len(test_node.last_message["getdata"].inv), 1)
567 assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG)
568 assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
570 # Deliver the block
571 if version==2:
572 test_node.send_and_ping(msg_witness_block(block))
573 else:
574 test_node.send_and_ping(msg_block(block))
575 assert_equal(int(node.getbestblockhash(), 16), block.sha256)
577 def test_getblocktxn_handler(self, node, test_node, version):
578 # bitcoind will not send blocktxn responses for blocks whose height is
579 # more than 10 blocks deep.
580 MAX_GETBLOCKTXN_DEPTH = 10
581 chain_height = node.getblockcount()
582 current_height = chain_height
583 while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH):
584 block_hash = node.getblockhash(current_height)
585 block = FromHex(CBlock(), node.getblock(block_hash, False))
587 msg = msg_getblocktxn()
588 msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [])
589 num_to_request = random.randint(1, len(block.vtx))
590 msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
591 test_node.send_message(msg)
592 wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10, lock=mininode_lock)
594 [tx.calc_sha256() for tx in block.vtx]
595 with mininode_lock:
596 assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int(block_hash, 16))
597 all_indices = msg.block_txn_request.to_absolute()
598 for index in all_indices:
599 tx = test_node.last_message["blocktxn"].block_transactions.transactions.pop(0)
600 tx.calc_sha256()
601 assert_equal(tx.sha256, block.vtx[index].sha256)
602 if version == 1:
603 # Witnesses should have been stripped
604 assert(tx.wit.is_null())
605 else:
606 # Check that the witness matches
607 assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True))
608 test_node.last_message.pop("blocktxn", None)
609 current_height -= 1
611 # Next request should send a full block response, as we're past the
612 # allowed depth for a blocktxn response.
613 block_hash = node.getblockhash(current_height)
614 msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])
615 with mininode_lock:
616 test_node.last_message.pop("block", None)
617 test_node.last_message.pop("blocktxn", None)
618 test_node.send_and_ping(msg)
619 with mininode_lock:
620 test_node.last_message["block"].block.calc_sha256()
621 assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16))
622 assert "blocktxn" not in test_node.last_message
624 def test_compactblocks_not_at_tip(self, node, test_node):
625 # Test that requesting old compactblocks doesn't work.
626 MAX_CMPCTBLOCK_DEPTH = 5
627 new_blocks = []
628 for i in range(MAX_CMPCTBLOCK_DEPTH + 1):
629 test_node.clear_block_announcement()
630 new_blocks.append(node.generate(1)[0])
631 wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
633 test_node.clear_block_announcement()
634 test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
635 wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock)
637 test_node.clear_block_announcement()
638 node.generate(1)
639 wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
640 test_node.clear_block_announcement()
641 with mininode_lock:
642 test_node.last_message.pop("block", None)
643 test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
644 wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock)
645 with mininode_lock:
646 test_node.last_message["block"].block.calc_sha256()
647 assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16))
649 # Generate an old compactblock, and verify that it's not accepted.
650 cur_height = node.getblockcount()
651 hashPrevBlock = int(node.getblockhash(cur_height-5), 16)
652 block = self.build_block_on_tip(node)
653 block.hashPrevBlock = hashPrevBlock
654 block.solve()
656 comp_block = HeaderAndShortIDs()
657 comp_block.initialize_from_block(block)
658 test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
660 tips = node.getchaintips()
661 found = False
662 for x in tips:
663 if x["hash"] == block.hash:
664 assert_equal(x["status"], "headers-only")
665 found = True
666 break
667 assert(found)
669 # Requesting this block via getblocktxn should silently fail
670 # (to avoid fingerprinting attacks).
671 msg = msg_getblocktxn()
672 msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0])
673 with mininode_lock:
674 test_node.last_message.pop("blocktxn", None)
675 test_node.send_and_ping(msg)
676 with mininode_lock:
677 assert "blocktxn" not in test_node.last_message
679 def activate_segwit(self, node):
680 node.generate(144*3)
681 assert_equal(get_bip9_status(node, "segwit")["status"], 'active')
683 def test_end_to_end_block_relay(self, node, listeners):
684 utxo = self.utxos.pop(0)
686 block = self.build_block_with_transactions(node, utxo, 10)
688 [l.clear_block_announcement() for l in listeners]
690 # ToHex() won't serialize with witness, but this block has no witnesses
691 # anyway. TODO: repeat this test with witness tx's to a segwit node.
692 node.submitblock(ToHex(block))
694 for l in listeners:
695 wait_until(lambda: l.received_block_announcement(), timeout=30, lock=mininode_lock)
696 with mininode_lock:
697 for l in listeners:
698 assert "cmpctblock" in l.last_message
699 l.last_message["cmpctblock"].header_and_shortids.header.calc_sha256()
700 assert_equal(l.last_message["cmpctblock"].header_and_shortids.header.sha256, block.sha256)
702 # Test that we don't get disconnected if we relay a compact block with valid header,
703 # but invalid transactions.
704 def test_invalid_tx_in_compactblock(self, node, test_node, use_segwit):
705 assert(len(self.utxos))
706 utxo = self.utxos[0]
708 block = self.build_block_with_transactions(node, utxo, 5)
709 del block.vtx[3]
710 block.hashMerkleRoot = block.calc_merkle_root()
711 if use_segwit:
712 # If we're testing with segwit, also drop the coinbase witness,
713 # but include the witness commitment.
714 add_witness_commitment(block)
715 block.vtx[0].wit.vtxinwit = []
716 block.solve()
718 # Now send the compact block with all transactions prefilled, and
719 # verify that we don't get disconnected.
720 comp_block = HeaderAndShortIDs()
721 comp_block.initialize_from_block(block, prefill_list=[0, 1, 2, 3, 4], use_witness=use_segwit)
722 msg = msg_cmpctblock(comp_block.to_p2p())
723 test_node.send_and_ping(msg)
725 # Check that the tip didn't advance
726 assert(int(node.getbestblockhash(), 16) is not block.sha256)
727 test_node.sync_with_ping()
729 # Helper for enabling cb announcements
730 # Send the sendcmpct request and sync headers
731 def request_cb_announcements(self, peer, node, version):
732 tip = node.getbestblockhash()
733 peer.get_headers(locator=[int(tip, 16)], hashstop=0)
735 msg = msg_sendcmpct()
736 msg.version = version
737 msg.announce = True
738 peer.send_and_ping(msg)
740 def test_compactblock_reconstruction_multiple_peers(self, node, stalling_peer, delivery_peer):
741 assert(len(self.utxos))
743 def announce_cmpct_block(node, peer):
744 utxo = self.utxos.pop(0)
745 block = self.build_block_with_transactions(node, utxo, 5)
747 cmpct_block = HeaderAndShortIDs()
748 cmpct_block.initialize_from_block(block)
749 msg = msg_cmpctblock(cmpct_block.to_p2p())
750 peer.send_and_ping(msg)
751 with mininode_lock:
752 assert "getblocktxn" in peer.last_message
753 return block, cmpct_block
755 block, cmpct_block = announce_cmpct_block(node, stalling_peer)
757 for tx in block.vtx[1:]:
758 delivery_peer.send_message(msg_tx(tx))
759 delivery_peer.sync_with_ping()
760 mempool = node.getrawmempool()
761 for tx in block.vtx[1:]:
762 assert(tx.hash in mempool)
764 delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
765 assert_equal(int(node.getbestblockhash(), 16), block.sha256)
767 self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
769 # Now test that delivering an invalid compact block won't break relay
771 block, cmpct_block = announce_cmpct_block(node, stalling_peer)
772 for tx in block.vtx[1:]:
773 delivery_peer.send_message(msg_tx(tx))
774 delivery_peer.sync_with_ping()
776 cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [ CTxInWitness() ]
777 cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
779 cmpct_block.use_witness = True
780 delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
781 assert(int(node.getbestblockhash(), 16) != block.sha256)
783 msg = msg_blocktxn()
784 msg.block_transactions.blockhash = block.sha256
785 msg.block_transactions.transactions = block.vtx[1:]
786 stalling_peer.send_and_ping(msg)
787 assert_equal(int(node.getbestblockhash(), 16), block.sha256)
789 def run_test(self):
790 # Setup the p2p connections and start up the network thread.
791 self.test_node = self.nodes[0].add_p2p_connection(TestNode())
792 self.segwit_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK|NODE_WITNESS)
793 self.old_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK)
795 network_thread_start()
797 self.test_node.wait_for_verack()
799 # We will need UTXOs to construct transactions in later tests.
800 self.make_utxos()
802 self.log.info("Running tests, pre-segwit activation:")
804 self.log.info("Testing SENDCMPCT p2p message... ")
805 self.test_sendcmpct(self.nodes[0], self.test_node, 1)
806 sync_blocks(self.nodes)
807 self.test_sendcmpct(self.nodes[1], self.segwit_node, 2, old_node=self.old_node)
808 sync_blocks(self.nodes)
810 self.log.info("Testing compactblock construction...")
811 self.test_compactblock_construction(self.nodes[0], self.test_node, 1, False)
812 sync_blocks(self.nodes)
813 self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, False)
814 sync_blocks(self.nodes)
816 self.log.info("Testing compactblock requests... ")
817 self.test_compactblock_requests(self.nodes[0], self.test_node, 1, False)
818 sync_blocks(self.nodes)
819 self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, False)
820 sync_blocks(self.nodes)
822 self.log.info("Testing getblocktxn requests...")
823 self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
824 sync_blocks(self.nodes)
825 self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
826 sync_blocks(self.nodes)
828 self.log.info("Testing getblocktxn handler...")
829 self.test_getblocktxn_handler(self.nodes[0], self.test_node, 1)
830 sync_blocks(self.nodes)
831 self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
832 self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
833 sync_blocks(self.nodes)
835 self.log.info("Testing compactblock requests/announcements not at chain tip...")
836 self.test_compactblocks_not_at_tip(self.nodes[0], self.test_node)
837 sync_blocks(self.nodes)
838 self.test_compactblocks_not_at_tip(self.nodes[1], self.segwit_node)
839 self.test_compactblocks_not_at_tip(self.nodes[1], self.old_node)
840 sync_blocks(self.nodes)
842 self.log.info("Testing handling of incorrect blocktxn responses...")
843 self.test_incorrect_blocktxn_response(self.nodes[0], self.test_node, 1)
844 sync_blocks(self.nodes)
845 self.test_incorrect_blocktxn_response(self.nodes[1], self.segwit_node, 2)
846 sync_blocks(self.nodes)
848 # End-to-end block relay tests
849 self.log.info("Testing end-to-end block relay...")
850 self.request_cb_announcements(self.test_node, self.nodes[0], 1)
851 self.request_cb_announcements(self.old_node, self.nodes[1], 1)
852 self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
853 self.test_end_to_end_block_relay(self.nodes[0], [self.segwit_node, self.test_node, self.old_node])
854 self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
856 self.log.info("Testing handling of invalid compact blocks...")
857 self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
858 self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False)
859 self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False)
861 self.log.info("Testing reconstructing compact blocks from all peers...")
862 self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node)
863 sync_blocks(self.nodes)
865 # Advance to segwit activation
866 self.log.info("Advancing to segwit activation")
867 self.activate_segwit(self.nodes[1])
868 self.log.info("Running tests, post-segwit activation...")
870 self.log.info("Testing compactblock construction...")
871 self.test_compactblock_construction(self.nodes[1], self.old_node, 1, True)
872 self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, True)
873 sync_blocks(self.nodes)
875 self.log.info("Testing compactblock requests (unupgraded node)... ")
876 self.test_compactblock_requests(self.nodes[0], self.test_node, 1, True)
878 self.log.info("Testing getblocktxn requests (unupgraded node)...")
879 self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
881 # Need to manually sync node0 and node1, because post-segwit activation,
882 # node1 will not download blocks from node0.
883 self.log.info("Syncing nodes...")
884 assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash())
885 while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()):
886 block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount()+1)
887 self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False))
888 assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())
890 self.log.info("Testing compactblock requests (segwit node)... ")
891 self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, True)
893 self.log.info("Testing getblocktxn requests (segwit node)...")
894 self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
895 sync_blocks(self.nodes)
897 self.log.info("Testing getblocktxn handler (segwit node should return witnesses)...")
898 self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
899 self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
901 # Test that if we submitblock to node1, we'll get a compact block
902 # announcement to all peers.
903 # (Post-segwit activation, blocks won't propagate from node0 to node1
904 # automatically, so don't bother testing a block announced to node0.)
905 self.log.info("Testing end-to-end block relay...")
906 self.request_cb_announcements(self.test_node, self.nodes[0], 1)
907 self.request_cb_announcements(self.old_node, self.nodes[1], 1)
908 self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
909 self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
911 self.log.info("Testing handling of invalid compact blocks...")
912 self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
913 self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, True)
914 self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, True)
916 self.log.info("Testing invalid index in cmpctblock message...")
917 self.test_invalid_cmpctblock_message()
920 if __name__ == '__main__':
921 CompactBlocksTest().main()