def test_muhash_implementation(self): self.log.info("Test MuHash implementation consistency") node = self.nodes[0] wallet = MiniWallet(node) mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) # Generate 100 blocks and remove the first since we plan to spend its # coinbase block_hashes = self.generate(wallet, 1) + self.generate(node, 99) blocks = list( map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes)) blocks.pop(0) # Create a spending transaction and mine a block which includes it txid = wallet.send_self_transfer(from_node=node)['txid'] tx_block = self.generateblock(node, output=wallet.get_address(), transactions=[txid]) blocks.append( from_hex(CBlock(), node.getblock(tx_block['hash'], False))) # Serialize the outputs that should be in the UTXO set and add them to # a MuHash object muhash = MuHash3072() for height, block in enumerate(blocks): # The Genesis block coinbase is not part of the UTXO set and we # spent the first mined block height += 2 for tx in block.vtx: for n, tx_out in enumerate(tx.vout): coinbase = 1 if not tx.vin[0].prevout.hash else 0 # Skip witness commitment if (coinbase and n > 0): continue data = COutPoint(int(tx.rehash(), 16), n).serialize() data += struct.pack("<i", height * 2 + coinbase) data += tx_out.serialize() muhash.insert(data) finalized = muhash.digest() node_muhash = node.gettxoutsetinfo("muhash")['muhash'] assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") assert_equal( node.gettxoutsetinfo()['hash_serialized_2'], "1ec3e58b0be79fca5917c7c30b9761f12adb609d0233cf2b42fa17ec419f0056") assert_equal( node.gettxoutsetinfo("muhash")['muhash'], "faee25ca4765facb643b7a2d96531c568cb52ad84de5ae3d420a92967621ec17")
def test_muhash_implementation(self): self.log.info("Test MuHash implementation consistency") node = self.nodes[0] wallet = MiniWallet(node) mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) # Generate 100 blocks and remove the first since we plan to spend its # coinbase block_hashes = self.generate(wallet, 1) + self.generate(node, 99) blocks = list( map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes)) blocks.pop(0) # Create a spending transaction and mine a block which includes it txid = wallet.send_self_transfer(from_node=node)['txid'] tx_block = self.generateblock(node, output=wallet.get_address(), transactions=[txid]) blocks.append( from_hex(CBlock(), node.getblock(tx_block['hash'], False))) # Serialize the outputs that should be in the UTXO set and add them to # a MuHash object muhash = MuHash3072() for height, block in enumerate(blocks): # The Genesis block coinbase is not part of the UTXO set and we # spent the first mined block height += 2 for tx in block.vtx: for n, tx_out in enumerate(tx.vout): coinbase = 1 if not tx.vin[0].prevout.hash else 0 # Skip witness commitment if (coinbase and n > 0): continue data = COutPoint(int(tx.rehash(), 16), n).serialize() data += struct.pack("<i", height * 2 + coinbase) data += tx_out.serialize() muhash.insert(data) finalized = muhash.digest() node_muhash = node.gettxoutsetinfo("muhash")['muhash'] assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") assert_equal( node.gettxoutsetinfo()['hash_serialized_2'], "5b1b44097406226c0eb8e1362cd17a1f346522cf9390a8175a57a5262cb1963f") assert_equal( node.gettxoutsetinfo("muhash")['muhash'], "4b8803075d7151d06fad3e88b68ba726886794873fbfa841d12aefb2cc2b881b")
def test_muhash_implementation(self): self.log.info("Test MuHash implementation consistency") node = self.nodes[0] wallet = MiniWallet(node) mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) # Generate 100 blocks and remove the first since we plan to spend its # coinbase block_hashes = self.generate(wallet, 1) + self.generate(node, 99) blocks = list( map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes)) blocks.pop(0) # Create a spending transaction and mine a block which includes it txid = wallet.send_self_transfer(from_node=node)['txid'] tx_block = self.generateblock(node, output=wallet.get_address(), transactions=[txid]) blocks.append( from_hex(CBlock(), node.getblock(tx_block['hash'], False))) # Serialize the outputs that should be in the UTXO set and add them to # a MuHash object muhash = MuHash3072() for height, block in enumerate(blocks): # The Genesis block coinbase is not part of the UTXO set and we # spent the first mined block height += 2 for tx in block.vtx: for n, tx_out in enumerate(tx.vout): coinbase = 1 if not tx.vin[0].prevout.hash else 0 # Skip witness commitment if (coinbase and n > 0): continue data = COutPoint(int(tx.rehash(), 16), n).serialize() data += struct.pack("<i", height * 2 + coinbase) data += tx_out.serialize() muhash.insert(data) finalized = muhash.digest() node_muhash = node.gettxoutsetinfo("muhash")['muhash'] assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") assert_equal( node.gettxoutsetinfo()['hash_serialized_2'], "3a570529b4c32e77268de1f81b903c75cc2da53c48df0d125c1e697ba7c8c7b7") assert_equal( node.gettxoutsetinfo("muhash")['muhash'], "a13e0e70eb8acc786549596e3bc154623f1a5a622ba2f70715f6773ec745f435")
def test_muhash_implementation(self): self.log.info("Test MuHash implementation consistency") node = self.nodes[0] wallet = MiniWallet(node) mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) # Generate 100 blocks and remove the first since we plan to spend its # coinbase block_hashes = self.generate(wallet, 1) + self.generate(node, 99) blocks = list( map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes)) blocks.pop(0) # Create a spending transaction and mine a block which includes it txid = wallet.send_self_transfer(from_node=node)['txid'] tx_block = self.generateblock(node, output=wallet.get_address(), transactions=[txid]) blocks.append( from_hex(CBlock(), node.getblock(tx_block['hash'], False))) # Serialize the outputs that should be in the UTXO set and add them to # a MuHash object muhash = MuHash3072() for height, block in enumerate(blocks): # The Genesis block coinbase is not part of the UTXO set and we # spent the first mined block height += 2 for tx in block.vtx: for n, tx_out in enumerate(tx.vout): coinbase = 1 if not tx.vin[0].prevout.hash else 0 # Skip witness commitment if (coinbase and n > 0): continue data = COutPoint(int(tx.rehash(), 16), n).serialize() data += struct.pack("<i", height * 2 + coinbase) data += tx_out.serialize() muhash.insert(data) finalized = muhash.digest() node_muhash = node.gettxoutsetinfo("muhash")['muhash'] assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") assert_equal( node.gettxoutsetinfo()['hash_serialized_2'], "221f245cf4c9010eeb7f5183d342c002ae6c1c27e98aa357dccb788c21d98049") assert_equal( node.gettxoutsetinfo("muhash")['muhash'], "7c0890c68501f7630d36aeb3999dc924e63af084ae1bbfba11dd462144637635")
def test_muhash_implementation(self): self.log.info("Test MuHash implementation consistency") node = self.nodes[0] wallet = MiniWallet(node) mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) # Generate 100 blocks and remove the first since we plan to spend its # coinbase block_hashes = wallet.generate(1) + node.generate(99) blocks = list( map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes)) blocks.pop(0) # Create a spending transaction and mine a block which includes it txid = wallet.send_self_transfer(from_node=node)['txid'] tx_block = node.generateblock(output=wallet.get_address(), transactions=[txid]) blocks.append( from_hex(CBlock(), node.getblock(tx_block['hash'], False))) # Serialize the outputs that should be in the UTXO set and add them to # a MuHash object muhash = MuHash3072() for height, block in enumerate(blocks): # The Genesis block coinbase is not part of the UTXO set and we # spent the first mined block height += 2 for tx in block.vtx: for n, tx_out in enumerate(tx.vout): coinbase = 1 if not tx.vin[0].prevout.hash else 0 # Skip witness commitment if (coinbase and n > 0): continue data = COutPoint(int(tx.rehash(), 16), n).serialize() data += struct.pack("<i", height * 2 + coinbase) data += tx_out.serialize() muhash.insert(data) finalized = muhash.digest() node_muhash = node.gettxoutsetinfo("muhash")['muhash'] assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") assert_equal( node.gettxoutsetinfo()['hash_serialized_2'], "03f3bedef7a3e64686e13b57ec08b1ada40528d8e01f64e077750e225ddb8c07") assert_equal( node.gettxoutsetinfo("muhash")['muhash'], "69ebd7142d443a89c227637ef9a21c05287a98f0acdd40ba7e3ef79d1f4e412d")
def run_test(self): self.log.info("Read headers data") self.headers_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile) with open(self.headers_file_path, encoding='utf-8') as headers_data: h_lines = [l.strip() for l in headers_data.readlines()] # The headers data is taken from testnet3 for early blocks from genesis until the first checkpoint. There are # two headers with valid POW at height 1 and 2, forking off from genesis. They are indicated by the FORK_PREFIX. FORK_PREFIX = 'fork:' self.headers = [l for l in h_lines if not l.startswith(FORK_PREFIX)] self.headers_fork = [l[len(FORK_PREFIX):] for l in h_lines if l.startswith(FORK_PREFIX)] self.headers = [from_hex(CBlockHeader(), h) for h in self.headers] self.headers_fork = [from_hex(CBlockHeader(), h) for h in self.headers_fork] self.log.info("Feed all non-fork headers, including and up to the first checkpoint") peer_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface()) peer_checkpoint.send_and_ping(msg_headers(self.headers)) assert { 'height': 546, 'hash': '000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70', 'branchlen': 546, 'status': 'headers-only', } in self.nodes[0].getchaintips() self.log.info("Feed all fork headers (fails due to checkpoint)") with self.nodes[0].assert_debug_log(['bad-fork-prior-to-checkpoint']): peer_checkpoint.send_message(msg_headers(self.headers_fork)) peer_checkpoint.wait_for_disconnect() self.log.info("Feed all fork headers (succeeds without checkpoint)") # On node 0 it succeeds because checkpoints are disabled self.restart_node(0, extra_args=['-nocheckpoints', "-minimumchainwork=0x0"]) peer_no_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface()) peer_no_checkpoint.send_and_ping(msg_headers(self.headers_fork)) assert { "height": 2, "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", "branchlen": 2, "status": "headers-only", } in self.nodes[0].getchaintips() # On node 1 it succeeds because no checkpoint has been reached yet by a chain tip peer_before_checkpoint = self.nodes[1].add_p2p_connection(P2PInterface()) peer_before_checkpoint.send_and_ping(msg_headers(self.headers_fork)) assert { "height": 2, "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", "branchlen": 2, "status": "headers-only", } in self.nodes[1].getchaintips()
def test_muhash_implementation(self): self.log.info("Test MuHash implementation consistency") node = self.nodes[0] wallet = MiniWallet(node) mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1 node.setmocktime(mocktime) # Generate 100 blocks and remove the first since we plan to spend its # coinbase block_hashes = self.generate(wallet, 1) + self.generate(node, 99) blocks = list(map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes)) blocks.pop(0) # Create a spending transaction and mine a block which includes it txid = wallet.send_self_transfer(from_node=node)['txid'] tx_block = self.generateblock(node, output=wallet.get_address(), transactions=[txid]) blocks.append(from_hex(CBlock(), node.getblock(tx_block['hash'], False))) # Serialize the outputs that should be in the UTXO set and add them to # a MuHash object muhash = MuHash3072() for height, block in enumerate(blocks): # The Genesis block coinbase is not part of the UTXO set and we # spent the first mined block height += 2 for tx in block.vtx: for n, tx_out in enumerate(tx.vout): coinbase = 1 if not tx.vin[0].prevout.hash else 0 # Skip witness commitment if (coinbase and n > 0): continue data = COutPoint(int(tx.rehash(), 16), n).serialize() data += struct.pack("<i", height * 2 + coinbase) data += tx_out.serialize() muhash.insert(data) finalized = muhash.digest() node_muhash = node.gettxoutsetinfo("muhash")['muhash'] assert_equal(finalized[::-1].hex(), node_muhash) self.log.info("Test deterministic UTXO set hash results") assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "f9aa4fb5ffd10489b9a6994e70ccf1de8a8bfa2d5f201d9857332e9954b0855d") assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "d1725b2fe3ef43e55aa4907480aea98d406fc9e0bf8f60169e2305f1fbf5961b")
def test_getmnlistdiff_base(self, baseBlockHash, blockHash): hexstr = self.nodes[0].getblockheader(blockHash, False) header = from_hex(CBlockHeader(), hexstr) d = self.test_node.getmnlistdiff(int(baseBlockHash, 16), int(blockHash, 16)) assert_equal(d.baseBlockHash, int(baseBlockHash, 16)) assert_equal(d.blockHash, int(blockHash, 16)) # Check that the merkle proof is valid proof = CMerkleBlock() proof.header = header proof.txn = d.merkleProof proof = proof.serialize().hex() # merkle proof first hash should be coinbase assert_equal(self.nodes[0].verifytxoutproof(proof), [format(d.merkleProof.vHash[0], '064x')]) # Check if P2P messages match with RPCs d2 = self.nodes[0].protx_diff(baseBlockHash, blockHash) assert_equal(d2["baseBlockHash"], baseBlockHash) assert_equal(d2["blockHash"], blockHash) assert_equal(d2["cbTxMerkleTree"], d.merkleProof.serialize().hex()) assert_equal(set([int(e, 16) for e in d2["deletedMNs"]]), set(d.deletedMNs)) assert_equal(set([int(e["proRegTxHash"], 16) for e in d2["mnList"]]), set([e.proRegTxHash for e in d.mnList])) assert_equal(set([QuorumId(e["llmqType"], int(e["quorumHash"], 16)) for e in d2["deletedQuorums"]]), set(d.deletedQuorums)) assert_equal(set([QuorumId(e["llmqType"], int(e["quorumHash"], 16)) for e in d2["newQuorums"]]), set([QuorumId(e.llmqType, e.quorumHash) for e in d.newQuorums])) return d
def test_compactblock_construction(self, test_node, use_witness_address=True): version = test_node.cmpct_version node = self.nodes[0] # Generate a bunch of transactions. node.generate(COINBASE_MATURITY + 1) num_transactions = 25 address = node.getnewaddress() segwit_tx_generated = False for _ in range(num_transactions): txid = node.sendtoaddress(address, 0.1) hex_tx = node.gettransaction(txid)["hex"] tx = tx_from_hex(hex_tx) if not tx.wit.is_null(): segwit_tx_generated = True if use_witness_address: assert segwit_tx_generated # check that our test is not broken # Wait until we've seen the block announcement for the resulting tip tip = int(node.getbestblockhash(), 16) test_node.wait_for_block_announcement(tip) # Make sure we will receive a fast-announce compact block self.request_cb_announcements(test_node) # Now mine a block, and look at the resulting compact block. test_node.clear_block_announcement() block_hash = int(node.generate(1)[0], 16) # Store the raw block in our internal format. block = from_hex(CBlock(), node.getblock("%064x" % block_hash, False)) for tx in block.vtx: tx.calc_sha256() block.rehash() # Wait until the block was announced (via compact blocks) test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) # Now fetch and check the compact block header_and_shortids = None with p2p_lock: # Convert the on-the-wire representation to absolute indexes header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids) self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block) # Now fetch the compact block using a normal non-announce getdata test_node.clear_block_announcement() inv = CInv(MSG_CMPCT_BLOCK, block_hash) test_node.send_message(msg_getdata([inv])) test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) # Now fetch and check the compact block header_and_shortids = None with p2p_lock: # Convert the on-the-wire representation to absolute indexes header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids) self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
def test_getblocktxn_handler(self, test_node): version = test_node.cmpct_version node = self.nodes[0] # bitcoind will not send blocktxn responses for blocks whose height is # more than 10 blocks deep. MAX_GETBLOCKTXN_DEPTH = 10 chain_height = node.getblockcount() current_height = chain_height while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH): block_hash = node.getblockhash(current_height) block = from_hex(CBlock(), node.getblock(block_hash, False)) msg = msg_getblocktxn() msg.block_txn_request = BlockTransactionsRequest( int(block_hash, 16), []) num_to_request = random.randint(1, len(block.vtx)) msg.block_txn_request.from_absolute( sorted(random.sample(range(len(block.vtx)), num_to_request))) test_node.send_message(msg) test_node.wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) [tx.calc_sha256() for tx in block.vtx] with p2p_lock: assert_equal( test_node.last_message["blocktxn"].block_transactions. blockhash, int(block_hash, 16)) all_indices = msg.block_txn_request.to_absolute() for index in all_indices: tx = test_node.last_message[ "blocktxn"].block_transactions.transactions.pop(0) tx.calc_sha256() assert_equal(tx.sha256, block.vtx[index].sha256) if version == 1: # Witnesses should have been stripped assert tx.wit.is_null() else: # Check that the witness matches assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True)) test_node.last_message.pop("blocktxn", None) current_height -= 1 # Next request should send a full block response, as we're past the # allowed depth for a blocktxn response. block_hash = node.getblockhash(current_height) msg.block_txn_request = BlockTransactionsRequest( int(block_hash, 16), [0]) with p2p_lock: test_node.last_message.pop("block", None) test_node.last_message.pop("blocktxn", None) test_node.send_and_ping(msg) with p2p_lock: test_node.last_message["block"].block.calc_sha256() assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16)) assert "blocktxn" not in test_node.last_message
def mine_double_spend(self, node, txins, target_address, use_mnmerkleroot_from_tip=False): amount = Decimal(0) for txin in txins: txout = node.gettxout(txin['txid'], txin['vout'], False) amount += txout['value'] amount -= Decimal("0.001") # fee rawtx = node.createrawtransaction(txins, {target_address: amount}) rawtx = node.signrawtransactionwithwallet(rawtx)['hex'] tx = from_hex(CTransaction(), rawtx) self.mine_block(node, [tx], use_mnmerkleroot_from_tip=use_mnmerkleroot_from_tip)
def _test_getblockheader(self): self.log.info("Test getblockheader") node = self.nodes[0] assert_raises_rpc_error( -8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense") assert_raises_rpc_error( -8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844") assert_raises_rpc_error( -5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844") besthash = node.getbestblockhash() secondbesthash = node.getblockhash(HEIGHT - 1) header = node.getblockheader(blockhash=besthash) assert_equal(header['hash'], besthash) assert_equal(header['height'], HEIGHT) assert_equal(header['confirmations'], 1) assert_equal(header['previousblockhash'], secondbesthash) assert_is_hex_string(header['chainwork']) assert_equal(header['nTx'], 1) assert_is_hash_string(header['hash']) assert_is_hash_string(header['previousblockhash']) assert_is_hash_string(header['merkleroot']) assert_is_hash_string(header['bits'], length=None) assert isinstance(header['time'], int) assert_equal(header['mediantime'], TIME_RANGE_MTP) assert isinstance(header['nonce'], int) assert isinstance(header['version'], int) assert isinstance(int(header['versionHex'], 16), int) assert isinstance(header['difficulty'], Decimal) # Test with verbose=False, which should return the header as hex. header_hex = node.getblockheader(blockhash=besthash, verbose=False) assert_is_hex_string(header_hex) header = from_hex(CBlockHeader(), header_hex) header.calc_sha256() assert_equal(header.hash, besthash) assert 'previousblockhash' not in node.getblockheader( node.getblockhash(0)) assert 'nextblockhash' not in node.getblockheader( node.getbestblockhash())
def run_test(self): self.log.info("Check that nodes set minfilter to MAX_MONEY while still in IBD") for node in self.nodes: assert node.getblockchaininfo()['initialblockdownload'] self.wait_until(lambda: all(peer['minfeefilter'] == MAX_FEE_FILTER for peer in node.getpeerinfo())) self.log.info("Check that nodes don't send getdatas for transactions while still in IBD") peer_inver = self.nodes[0].add_p2p_connection(P2PDataStore()) txid = 0xdeadbeef peer_inver.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=txid)])) # The node should not send a getdata, but if it did, it would first delay 2 seconds self.nodes[0].setmocktime(int(time.time() + NONPREF_PEER_TX_DELAY)) peer_inver.sync_send_with_ping() with p2p_lock: assert txid not in peer_inver.getdata_requests self.nodes[0].disconnect_p2ps() self.log.info("Check that nodes don't process unsolicited transactions while still in IBD") # A transaction hex pulled from tx_valid.json. There are no valid transactions since no UTXOs # exist yet, but it should be a well-formed transaction. rawhex = "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff473" + \ "04402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e168" + \ "1a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696a" + \ "d990364e555c271ad504b88ac00000000" assert self.nodes[1].decoderawtransaction(rawhex) # returns a dict, should not throw tx = from_hex(CTransaction(), rawhex) peer_txer = self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(expected_msgs=["received: tx"], unexpected_msgs=["was not accepted"]): peer_txer.send_and_ping(msg_tx(tx)) self.nodes[0].disconnect_p2ps() # Come out of IBD by generating a block self.generate(self.nodes[0], 1) self.log.info("Check that nodes reset minfilter after coming out of IBD") for node in self.nodes: assert not node.getblockchaininfo()['initialblockdownload'] self.wait_until(lambda: all(peer['minfeefilter'] == NORMAL_FEE_FILTER for peer in node.getpeerinfo())) self.log.info("Check that nodes process the same transaction, even when unsolicited, when no longer in IBD") peer_txer = self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(expected_msgs=["was not accepted"]): peer_txer.send_and_ping(msg_tx(tx))
def run_test(self): self.log.info("Mining blocks...") self.generate(self.nodes[0], COINBASE_MATURITY + 1) # address address1 = self.nodes[0].getnewaddress() # pubkey address2 = self.nodes[0].getnewaddress() # privkey eckey = ECKey() eckey.generate() address3_privkey = bytes_to_wif(eckey.get_bytes()) address3 = key_to_p2wpkh(eckey.get_pubkey().get_bytes()) self.nodes[0].importprivkey(address3_privkey) # Check only one address address_info = self.nodes[0].getaddressinfo(address1) assert_equal(address_info['ismine'], True) self.sync_all() # Node 1 sync test assert_equal(self.nodes[1].getblockcount(), COINBASE_MATURITY + 1) # Address Test - before import address_info = self.nodes[1].getaddressinfo(address1) assert_equal(address_info['iswatchonly'], False) assert_equal(address_info['ismine'], False) address_info = self.nodes[1].getaddressinfo(address2) assert_equal(address_info['iswatchonly'], False) assert_equal(address_info['ismine'], False) address_info = self.nodes[1].getaddressinfo(address3) assert_equal(address_info['iswatchonly'], False) assert_equal(address_info['ismine'], False) # Send funds to self txnid1 = self.nodes[0].sendtoaddress(address1, 0.1) self.generate(self.nodes[0], 1) rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex'] proof1 = self.nodes[0].gettxoutproof([txnid1]) txnid2 = self.nodes[0].sendtoaddress(address2, 0.05) self.generate(self.nodes[0], 1) rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex'] proof2 = self.nodes[0].gettxoutproof([txnid2]) txnid3 = self.nodes[0].sendtoaddress(address3, 0.025) self.generate(self.nodes[0], 1) rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex'] proof3 = self.nodes[0].gettxoutproof([txnid3]) self.sync_all() # Import with no affiliated address assert_raises_rpc_error(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1) balance1 = self.nodes[1].getbalance() assert_equal(balance1, Decimal(0)) # Import with affiliated address with no rescan self.nodes[1].createwallet('wwatch', disable_private_keys=True) wwatch = self.nodes[1].get_wallet_rpc('wwatch') wwatch.importaddress(address=address2, rescan=False) wwatch.importprunedfunds(rawtransaction=rawtxn2, txoutproof=proof2) assert [tx for tx in wwatch.listtransactions(include_watchonly=True) if tx['txid'] == txnid2] # Import with private key with no rescan w1 = self.nodes[1].get_wallet_rpc(self.default_wallet_name) w1.importprivkey(privkey=address3_privkey, rescan=False) w1.importprunedfunds(rawtxn3, proof3) assert [tx for tx in w1.listtransactions() if tx['txid'] == txnid3] balance3 = w1.getbalance() assert_equal(balance3, Decimal('0.025')) # Addresses Test - after import address_info = w1.getaddressinfo(address1) assert_equal(address_info['iswatchonly'], False) assert_equal(address_info['ismine'], False) address_info = wwatch.getaddressinfo(address2) if self.options.descriptors: assert_equal(address_info['iswatchonly'], False) assert_equal(address_info['ismine'], True) else: assert_equal(address_info['iswatchonly'], True) assert_equal(address_info['ismine'], False) address_info = w1.getaddressinfo(address3) assert_equal(address_info['iswatchonly'], False) assert_equal(address_info['ismine'], True) # Remove transactions assert_raises_rpc_error(-8, "Transaction does not exist in wallet.", w1.removeprunedfunds, txnid1) assert not [tx for tx in w1.listtransactions(include_watchonly=True) if tx['txid'] == txnid1] wwatch.removeprunedfunds(txnid2) assert not [tx for tx in wwatch.listtransactions(include_watchonly=True) if tx['txid'] == txnid2] w1.removeprunedfunds(txnid3) assert not [tx for tx in w1.listtransactions(include_watchonly=True) if tx['txid'] == txnid3] # Check various RPC parameter validation errors assert_raises_rpc_error(-22, "TX decode failed", w1.importprunedfunds, b'invalid tx'.hex(), proof1) assert_raises_rpc_error(-5, "Transaction given doesn't exist in proof", w1.importprunedfunds, rawtxn2, proof1) mb = from_hex(CMerkleBlock(), proof1) mb.header.hashMerkleRoot = 0xdeadbeef # cause mismatch between merkle root and merkle block assert_raises_rpc_error(-5, "Something wrong with merkleblock", w1.importprunedfunds, rawtxn1, mb.serialize().hex()) mb = from_hex(CMerkleBlock(), proof1) mb.header.nTime += 1 # modify arbitrary block header field to change block hash assert_raises_rpc_error(-5, "Block not found in chain", w1.importprunedfunds, rawtxn1, mb.serialize().hex())
def run_test(self): self.log.info("Read headers data") self.headers_file_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), self.options.datafile) with open(self.headers_file_path, encoding='utf-8') as headers_data: h_lines = [l.strip() for l in headers_data.readlines()] # The headers data is taken from testnet3 for early blocks from genesis until the first checkpoint. There are # two headers with valid POW at height 1 and 2, forking off from genesis. They are indicated by the FORK_PREFIX. FORK_PREFIX = 'fork:' self.headers = [l for l in h_lines if not l.startswith(FORK_PREFIX)] self.headers_fork = [ l[len(FORK_PREFIX):] for l in h_lines if l.startswith(FORK_PREFIX) ] self.headers = [from_hex(CBlockHeader(), h) for h in self.headers] self.headers_fork = [ from_hex(CBlockHeader(), h) for h in self.headers_fork ] self.log.info( "Feed all non-fork headers, including and up to the first checkpoint" ) peer_checkpoint = self.nodes[0].add_outbound_p2p_connection( P2PInterface(), p2p_idx=0) peer_checkpoint.send_and_ping(msg_headers(self.headers)) assert { 'height': 546, 'hash': '000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70', 'branchlen': 546, 'status': 'headers-only', } in self.nodes[0].getchaintips() self.log.info("Feed all fork headers (fails due to checkpoint)") with self.nodes[0].assert_debug_log(['bad-fork-prior-to-checkpoint']): peer_checkpoint.send_message(msg_headers(self.headers_fork)) peer_checkpoint.wait_for_disconnect() self.log.info("Feed all fork headers (succeeds without checkpoint)") # On node 0 it succeeds because checkpoints are disabled self.restart_node(0, extra_args=['-nocheckpoints', "-minimumchainwork=0"]) peer_no_checkpoint = self.nodes[0].add_outbound_p2p_connection( P2PInterface(), p2p_idx=0) peer_no_checkpoint.send_and_ping(msg_headers(self.headers_fork)) assert { "height": 2, "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", "branchlen": 2, "status": "headers-only", } in self.nodes[0].getchaintips() # On node 1 it succeeds because no checkpoint has been reached yet by a chain tip peer_before_checkpoint = self.nodes[1].add_outbound_p2p_connection( P2PInterface(), p2p_idx=1) peer_before_checkpoint.send_and_ping(msg_headers(self.headers_fork)) assert { "height": 2, "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", "branchlen": 2, "status": "headers-only", } in self.nodes[1].getchaintips() self.log.info( "Feed checkpoint-violating block (succeeds up until the checkpoint mismatch, then fails)" ) block = CBlockHeader(self.headers_fork[-1]) headers_fork2 = [] for time_offset, nonce in ( (3, 0x023ec36d), (3, 0x9e4f929b), (0, 0x8bb04400), (3, 0x31bbae20), (0, 0xd53e5028), (2, 0x7841f4e3), (5, 0x7a8990a4), (2, 0x489e28a1), (1, 0x68bdb61a), (-1, 0xf6d2a9fb), (5, 0x487dcf25), (3, 0x546da3d4), (4, 0xc1f844d2), (3, 0x0c086f6f), (0, 0xc2321e55), (6, 0xde1aa13c), (0, 0x05227358), (4, 0x5e021e88), (1, 0xab2a18ae), (8, 0x80c58047), (5, 0xfaed66b9), (4, 0x85e64899), (6, 0x3a0de669), (1, 0x5c519d58), (4, 0x992f74d0), (4, 0xf9eb3bef), (4, 0x07673e35), (5, 0x21b99d08), (3, 0xef38d256), (2, 0xa4f1dc1b), (1, 0x2c8a4530), (0, 0x2b5ea5b4), (6, 0xf2284fc5), (0, 0x1dfbd513), (0, 0x0b17a886), (2, 0x0bc3f397), (0, 0x22cc4db0), (9, 0x297d6621), (1, 0xa6ae996b), (0, 0x48749a3f), (0, 0x989bf1a2), (6, 0xa052d387), (1, 0x9e2f6137), (3, 0x6a0be10c), (1, 0xef64e362), (4, 0xce516de6), (0, 0x2d077f41), (1, 0x6188fb5d), (3, 0xa72b0388), (2, 0xd1065e3b), (0, 0x73641cc7), (4, 0xa667e807), (3, 0x343f4941), (2, 0xe62c5e97), (2, 0x64ccbe3f), (2, 0x891494ce), (2, 0x1a1593ba), (1, 0x7fb3165c), (3, 0x9210c30b), (0, 0x221e0eb6), (2, 0x9e80023b), (5, 0xb8981525), (4, 0xa9eb35ed), (0, 0x0cfe8f68), (4, 0x31868c9d), (0, 0xbc0fa60e), (5, 0xcca64b21), (0, 0x28a1f860), (2, 0xbf629fb5), (2, 0x4e0673ab), (0, 0x8271fd15), (2, 0x1d1ba6fd), (1, 0xf8552431), (1, 0x4a5847a3), (2, 0x60e70a8b), (0, 0x28e05674), (1, 0x3a52baa0), (4, 0x93cc4193), (1, 0xb9e83452), (-1, 0x02578099), (6, 0xf1deecdb), (3, 0xbfc713f0), (1, 0xd42411c2), (3, 0x2ff09457), (4, 0xca26349a), (5, 0x11e45b8a), (2, 0x21861128), (0, 0xc2f0cf4d), (4, 0x8934b604), (0, 0xcc822981), (4, 0xef67ee2c), (2, 0x940a8496), (2, 0xd67ea903), (3, 0xd6975b4c), (1, 0x39d3775b), (3, 0x33e2a45a), (0, 0x43452dd5), (5, 0xf0221dda), (2, 0x24440716), (1, 0x9c160e08), (4, 0xd0e7252a), (1, 0x447411d2), (3, 0x958eaa10), (-3, 0xb9c956ec), (1, 0x5cd63c9c), (1, 0x4af69deb), (3, 0x90b93454), (2, 0x17959b09), (3, 0xb05154ec), (0, 0x058f9e11), (1, 0x227d9c1e), (4, 0xacb7701f), (4, 0x9542721f), (2, 0x1e05aa42), (1, 0x933d4365), (1, 0xb5c3a67e), (0, 0xac9cc6a6), (1, 0x4a76055a), (2, 0x7721afe9), (5, 0xe12b457e), (1, 0xaecdc119), (0, 0xe8e4ca43), (1, 0x6e42e836), (1, 0x1d4dec49), (1, 0xf8056d54), (1, 0x584bccb8), (1, 0x1932259b), (0, 0xdf53ee37), (0, 0x74e1f913), (1, 0xc7d3a7e2), (4, 0xef483c04), (0, 0x60ad07f0), (3, 0x89c790ea), (0, 0xb7cadd7e), (2, 0x38a82398), (1, 0xfb93ea07), (0, 0x200d8ecd), (0, 0xf1339a41), (3, 0x6af69ec7), (3, 0xaffa785f), (2, 0x67552c61), (3, 0xec447684), (0, 0xa28c3c1b), (0, 0x1a3218f3), (3, 0xc291da2c), (0, 0x497d588f), (3, 0x9fc4f865), (0, 0x68070cc7), (4, 0x9b7c0842), (3, 0x3ea910ac), (0, 0x5c793e79), (3, 0x839fca4c), (1, 0x16a801e7), (0, 0x26ad46a3), (2, 0x7709be6c), (2, 0xc57d1b58), (4, 0x9a4a49c1), (4, 0xd59ee673), (7, 0x8d1ded67), (1, 0x9ddc3594), (0, 0xf3af3d45), (3, 0xbbb210be), (0, 0xec262c80), (4, 0x6731951b), (0, 0xdc36282b), (2, 0xae470ed2), (1, 0x22c57186), (1, 0xde307b71), (4, 0x3d185e05), (-3, 0x58d53609), (1, 0xb25fc17d), (2, 0x6c490b64), (5, 0x03d05d9b), (2, 0x3e84e2ce), (0, 0x2c38303d), (1, 0x487c092c), (1, 0x23a3da6e), (3, 0x2854a040), (1, 0xa546be54), (1, 0x50bfd84d), (1, 0x6795f353), (0, 0x82e77285), (1, 0x24dd5aa3), (1, 0x0563f0ea), (2, 0xb2b9be8d), (1, 0x54e70019), (0, 0xb4a31d38), (0, 0xfd3c816d), (4, 0x84bfd3a7), (3, 0x47ecc30d), (2, 0x6e1caa0c), (1, 0x47097b3e), (0, 0x30316532), (0, 0xca42b48d), (6, 0xb5f05a80), (5, 0xcf1f9c0f), (1, 0xc7c9c0a0), (7, 0xdce826fa), (2, 0x92478133), (0, 0xdeff31ab), (2, 0xfeba362f), (2, 0x143b78db), (0, 0x48dfb442), (1, 0x7b660255), (0, 0x9b2d9613), (0, 0xc81a0b46), (5, 0xfa0257c2), (0, 0xcb799eac), (3, 0xe66885b5), (0, 0xb7523b87), (3, 0x80ec766e), (0, 0xd3117846), (4, 0x44d9d213), (3, 0xf3540f37), (0, 0x838a3b64), (4, 0xd221d138), (3, 0xa96e0947), (1, 0xd09222da), (1, 0x72071fec), (0, 0x5424ae38), (4, 0xbd5c3d49), (4, 0x2d1be9ef), (3, 0x31d8521d), (3, 0x5f0ac290), (0, 0x27710324), (3, 0xc1cc6b58), (0, 0xb1256275), (0, 0x5473ced1), (1, 0x35293898), (0, 0x062a003f), (3, 0xee177b2e), (4, 0xbbb9235a), (1, 0x183cebbe), (3, 0xced4e55b), (2, 0x8050c0fc), (7, 0xe46e0207), (2, 0xf23c4b96), (-2, 0x2d7ec1f1), (1, 0x90161c6d), (8, 0x62d4b92f), (1, 0x20086401), (2, 0x2ce864a0), (4, 0x317da57e), (2, 0x2cc9250b), (0, 0xf41ea979), (1, 0xa50ca905), (0, 0x4c0916bb), (6, 0x45becd84), (3, 0xdac6c807), (0, 0xc88954d5), (2, 0xf1ebf2b6), (2, 0xa1e8f013), (1, 0xb86af5b1), (1, 0xc864d9f1), (4, 0x5e91821b), (5, 0x9b3ae958), (0, 0x5c37debb), (4, 0xf85e2180), (1, 0x9de6eb5c), (1, 0x51ec9650), (0, 0xf3d31a0d), (0, 0x127a4cad), (2, 0x7698ee29), (1, 0x63297ce6), (1, 0xf9952a56), (0, 0xb2bcdb59), (2, 0xd904198f), (1, 0xe0ceed57), (2, 0xe883801f), (0, 0x9c48eff1), (2, 0x69bd1c00), (0, 0xefb5c46c), (1, 0x0ee6d904), (0, 0xa01e4f15), (0, 0xe50170fc), (3, 0x1a057766), (2, 0xffddd03e), (1, 0x9842404d), (0, 0xff3c892c), (3, 0x468f2c36), (2, 0xef3c2e4e), (0, 0x72c0ea16), (4, 0x815c722e), (1, 0xe77dee42), (0, 0xddd8b502), (5, 0xf4d60169), (0, 0x86b593af), (0, 0x08cca2a5), (4, 0x07652fb5), (2, 0x19ead298), (0, 0x94af6d52), (2, 0x67955b19), (0, 0xf579c469), (0, 0x4b010360), (0, 0x67bbba31), (5, 0x2e47930e), (1, 0xbc6872d8), (3, 0x645621b8), (1, 0xe2c5120b), (0, 0xf3c50807), (1, 0x6dcf4d07), (1, 0xaeb4237d), (1, 0x2a5f46a0), (2, 0x4e8d3883), (0, 0x48268869), (0, 0x3bd2401a), (6, 0x0bec238c), (0, 0x262c5697), (1, 0xbbf9572d), (2, 0x37df6e6f), (3, 0x2ce9e7f3), (2, 0x9c0741b1), (0, 0x8158c135), (2, 0x007c8856), (1, 0x6c59cc11), (1, 0x2d77e50c), (0, 0x43b85637), (1, 0x37440748), (4, 0x418b2692), (4, 0x3bc8200e), (3, 0x42e28d55), (1, 0xadd84676), (0, 0x2f58d608), (4, 0xa252bf4e), (5, 0x36365c0e), (3, 0x22736e12), (2, 0xac0e0e83), (1, 0x30316f60), (4, 0xedb2b98e), (1, 0x46cd60ed), (3, 0x8404d922), (2, 0x0e230e16), (1, 0xf2b50134), (-1, 0x8e256fff), (0, 0x80199c4d), (1, 0x56e07a97), (1, 0x2f9eed9a), (0, 0xfb8a7055), (3, 0xe3d02c6b), (3, 0xd9b43b13), (1, 0xe4faa52a), (2, 0x270801f7), (0, 0x5fa6a206), (4, 0xa151f071), (3, 0xd2848896), (0, 0x3d5f905f), (5, 0x499ae522), (1, 0xc61d9839), (5, 0xdd2f28b4), (0, 0x7dc21c39), (0, 0x57e1ab56), (0, 0x42027d5a), (6, 0x242a8813), (4, 0x69fdcc57), (3, 0xff7bd13a), (2, 0x9a3b2839), (5, 0x4af325ee), (2, 0x58dea930), (2, 0x202b57a4), (764, 0xa39c30f0), (3, 0x1ac08e2c), (7, 0xa9263507), (1, 0xb1c5602a), (0, 0xf9716695), (2, 0x8ce36f1c), (1, 0xddf12292), (4, 0xa22e830d), (1, 0xb84c2e51), (2, 0x3f6eb08c), (0, 0x185ae643), (0, 0x3b3ee340), (5, 0x2f0bce41), (5, 0x2c915d7c), (4, 0xe0169c60), (5, 0xc5b08211), (0, 0x3f123b19), (2, 0x443baa3f), (0, 0x86e5bd6b), (1, 0x728af7ae), (2, 0x34cd4af0), (1, 0x773b28fc), (4, 0xb42fcf79), (2, 0xcf4cddcd), (3, 0x472c939d), (1, 0xa2f66937), (3, 0x9202dd5a), (13, 0x87b4cbd0), (16, 0x8d74ed44), (1, 0xab0ec370), (0, 0x4345bc72), (3, 0x1663d4e8), (54, 0x53304a20), (14, 0xf3c7c0b5), (1, 0xa755c4d5), (0, 0xb4a4246d), (3, 0xb55800f7), (14, 0x80d85102), (0, 0x98d4e5ac), (1, 0x6f245269), (13, 0x038c57c4), (0, 0x86e5ac2e), (1, 0x6c1963c6), (0, 0x1adc14a1), (3, 0x8f37ac31), (18, 0x16fd4d32), (15, 0xee5bbf16), (13, 0xfba44c88), (13, 0x4f6b4e47), (14, 0xf9d7fe91), (1, 0xe5e66769), (1, 0x7ff9be17), (1, 0xd53b2c20), (3, 0xa48129e8), (1, 0xca7692d9), (1, 0x55067b69), (0, 0xbae33993), (0, 0x789a395c), (0, 0xb2617974), (1, 0xa49ae3ae), (0, 0x52c934ba), (4, 0x6ee4bde6), (0, 0x083b4807), (4, 0x382b6a26), (1, 0x17f2e8d3), (4, 0x70d17e03), (4, 0x48bb565b), (2, 0x437d655f), (2, 0xece43c5f), (0, 0xc06407f0), (4, 0xabc4d27a), (4, 0xf7162b9f), (5, 0x97dc4313), (4, 0x7c9578fa), (4, 0xd38229e0), (4, 0xc61a6e08), (0, 0xc821347c), (5, 0xbb37d0ab), (4, 0x3e93a911), (5, 0x3c03d85e), (4, 0xb289102e), (5, 0x5e42768e), (4, 0x4c574f91), (0, 0xc3531db9), (5, 0x8ebbfe1b), (2, 0x62de7520), (4, 0x11def7c6), (0, 0xd12a5839), (4, 0xd60eb230), (0, 0xfb6d0844), (2, 0x701a5c56), (1, 0x48998570), (4, 0xcc786b3e), (1, 0x8973807a), (4, 0x77151b83), (3, 0xb9b223a4), (4, 0x7d213a8e), (0, 0xe627ba6e), (1, 0x2de15b60), (0, 0x382c67c4), (6, 0x43701b8e), (8, 0x5f41b027), (1, 0x09c5d515), (1, 0x7fdaaf68), (4, 0x8bf79290), (3, 0x1a7c0271), (0, 0x3562b3a1), (4, 0x079aa703), (1, 0x8fb1aace), (4, 0xb02b8935), (4, 0x939d1697), (0, 0x7b2d7a80), (4, 0x351c3288), (5, 0x5f3dd388), (1, 0xe865101a), (0, 0x57871387), (0, 0xd4fd6955), (4, 0x86fe1cbb), (0, 0x21296c24), (4, 0x68f6d66d), (3, 0x9ac3b10b), (8, 0x659ebf23), (0, 0x8e483006), (5, 0x2821774f), (4, 0x3b005030), (1, 0x6bb6f09a), (3, 0xb918ea6c), (5, 0x259aca8a), (1, 0x4bdaa577), (3, 0x585e295b), (2, 0xd7c04cca), (6, 0x00a0f04d), (3, 0x0cb7eda9), (5, 0xb1d83641), (4, 0xd1105e7d), (2, 0xe8ad8382), (3, 0x92df8405), (4, 0xffb344bf), (0, 0x94471661), (-3, 0x0b9714a4), (6, 0x87e08f18), (6, 0xae594216), (5, 0x51acdc5e), (4, 0x83664747), (0, 0x7b10c195), (2, 0x1ef4426a), (5, 0x1dbf29d0), (2, 0xe9b85e89), (3, 0x18611e1a), (0, 0xa10966dd), (0, 0xe54fad12), (5, 0x03e6220d), (3, 0x64fa4ada), (4, 0x8facb4b4), (2, 0xfc0dae5b), (4, 0x61a98300), (0, 0xd919ee25), (3, 0x47d8f268), (1, 0xd3d5250f), (1, 0xa1b7d150), (1, 0x39584b6a), (1, 0xb730f059), (0, 0x421a930a), (0, 0xf4520724), (2, 0xf51ac97e), (1, 0x3a2e424f), (5, 0x4488e824), (5, 0x51f37f50), (0, 0x2060682b), (4, 0x668bcc70), (0, 0x87bfad0d), (3, 0x87a5e2be), (3, 0xdb87b268), (0, 0xbdc1bd9f), (0, 0x9e97bae4), (0, 0x5f8854cc), (1, 0x6a54a576), (0, 0x6abb7c6e), (4, 0x3529e627), (0, 0x2b17bf18), (6, 0xe718bb6f), (0, 0x2f8ca470), (5, 0xabf106a3), (4, 0x6f80543f), (0, 0x7459d412), ): block.hashPrevBlock = block.sha256 block.nTime += time_offset block.nNonce = nonce block.rehash() headers_fork2.append(CBlockHeader(block)) with self.nodes[1].assert_debug_log(['checkpoint-mismatch']): peer_before_checkpoint.send_message(msg_headers(headers_fork2)) peer_before_checkpoint.wait_for_disconnect() assert { "height": 545, "hash": "000000008ce04625549eb92726e39fe6de52cd44df861bbd477f9ada8bc30efc", "branchlen": 545, "status": "headers-only", } in self.nodes[1].getchaintips()
def build_block_on_tip(self): blockhash = self.generate(self.nodes[2], 1)[0] block_hex = self.nodes[2].getblock(blockhash=blockhash, verbosity=0) block = from_hex(CBlock(), block_hex) block.rehash() return block
def mine_block(self, node, vtx=None, mn_payee=None, mn_amount=None, use_mnmerkleroot_from_tip=False, expected_error=None): if vtx is None: vtx = [] bt = node.getblocktemplate({'rules': ['segwit']}) height = bt['height'] tip_hash = bt['previousblockhash'] tip_block = node.getblock(tip_hash, 2)["tx"][0] coinbasevalue = 50 * COIN halvings = int(height / 150) # regtest coinbasevalue >>= halvings miner_script = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['scriptPubKey'] if mn_payee is None: if isinstance(bt['masternode'], list): mn_payee = bt['masternode'][0]['script'] else: mn_payee = bt['masternode']['script'] # we can't take the masternode payee amount from the template here as we might have additional fees in vtx new_fees = 0 for tx in vtx: in_value = 0 out_value = 0 for txin in tx.vin: txout = node.gettxout("%064x" % txin.prevout.hash, txin.prevout.n, False) in_value += int(txout['value'] * COIN) for txout in tx.vout: out_value += txout.nValue new_fees += in_value - out_value if mn_amount is None: mn_amount = get_masternode_payment(height, coinbasevalue, bt['masternode_collateral_height']) + new_fees/2 miner_amount = int(coinbasevalue*0.25) miner_amount += new_fees/2 coinbase = CTransaction() coinbase.vout.append(CTxOut(int(miner_amount), bytes.fromhex(miner_script))) coinbase.vout.append(CTxOut(int(mn_amount), bytes.fromhex(mn_payee))) coinbase.vin = create_coinbase(height).vin # Recreate mn root as using one in BT would result in invalid merkle roots for masternode lists coinbase.nVersion = bt['version_coinbase'] if len(bt['default_witness_commitment_extra']) != 0: if use_mnmerkleroot_from_tip: cbtx = from_hex(CCbTx(version=2), bt['default_witness_commitment_extra']) if 'cbTx' in tip_block: cbtx.merkleRootMNList = int(tip_block['cbTx']['merkleRootMNList'], 16) else: cbtx.merkleRootMNList = 0 coinbase.extraData = cbtx.serialize() else: coinbase.extraData = bytes.fromhex(bt['default_witness_commitment_extra']) coinbase.calc_sha256(with_witness=True) block = create_block(int(tip_hash, 16), coinbase) block.nVersion = 4 block.vtx += vtx block.hashMerkleRoot = block.calc_merkle_root() add_witness_commitment(block) block.solve() result = node.submitblock(block.serialize().hex()) if expected_error is not None and result != expected_error: raise AssertionError('mining the block should have failed with error %s, but submitblock returned %s' % (expected_error, result)) elif expected_error is None and result is not None: raise AssertionError('submitblock returned %s' % (result))
def run_test(self): miniwallet = MiniWallet(self.nodes[0]) # Add enough mature utxos to the wallet, so that all txs spend confirmed coins self.generate(miniwallet, 5) self.generate(self.nodes[0], COINBASE_MATURITY) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) txid1 = miniwallet.send_self_transfer(from_node=self.nodes[0])['txid'] txid2 = miniwallet.send_self_transfer(from_node=self.nodes[0])['txid'] # This will raise an exception because the transaction is not yet in a block assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].gettxoutproof, [txid1]) self.generate(self.nodes[0], 1) blockhash = self.nodes[0].getblockhash(chain_height + 1) txlist = [] blocktxn = self.nodes[0].getblock(blockhash, True)["tx"] txlist.append(blocktxn[1]) txlist.append(blocktxn[2]) assert_equal( self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid1 ])), [txid1]) assert_equal( self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof( [txid1, txid2])), txlist) assert_equal( self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof( [txid1, txid2], blockhash)), txlist) txin_spent = miniwallet.get_utxo() # Get the change from txid2 tx3 = miniwallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=txin_spent) txid3 = tx3['txid'] self.generate(self.nodes[0], 1) self.sync_all() txid_spent = txin_spent["txid"] txid_unspent = txid1 # Input was change from txid2, so txid1 should be unspent # Invalid txids assert_raises_rpc_error( -8, "txid must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[0].gettxoutproof, ["00000000000000000000000000000000"], blockhash) assert_raises_rpc_error( -8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].gettxoutproof, [ "ZZZ0000000000000000000000000000000000000000000000000000000000000" ], blockhash) # Invalid blockhashes assert_raises_rpc_error( -8, "blockhash must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[0].gettxoutproof, [txid_spent], "00000000000000000000000000000000") assert_raises_rpc_error( -8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].gettxoutproof, [txid_spent], "ZZZ0000000000000000000000000000000000000000000000000000000000000") # We can't find the block from a fully-spent tx assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[0].gettxoutproof, [txid_spent]) # We can get the proof if we specify the block assert_equal( self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof( [txid_spent], blockhash)), [txid_spent]) # We can't get the proof if we specify a non-existent block assert_raises_rpc_error( -5, "Block not found", self.nodes[0].gettxoutproof, [txid_spent], "0000000000000000000000000000000000000000000000000000000000000000") # We can get the proof if the transaction is unspent assert_equal( self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof( [txid_unspent])), [txid_unspent]) # We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter. assert_equal( sorted(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof( [txid1, txid2]))), sorted(txlist)) assert_equal( sorted(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof( [txid2, txid1]))), sorted(txlist)) # We can always get a proof if we have a -txindex assert_equal( self.nodes[0].verifytxoutproof(self.nodes[1].gettxoutproof( [txid_spent])), [txid_spent]) # We can't get a proof if we specify transactions from different blocks assert_raises_rpc_error( -5, "Not all transactions found in specified or retrieved block", self.nodes[0].gettxoutproof, [txid1, txid3]) # Test empty list assert_raises_rpc_error(-8, "Parameter 'txids' cannot be empty", self.nodes[0].gettxoutproof, []) # Test duplicate txid assert_raises_rpc_error(-8, 'Invalid parameter, duplicated txid', self.nodes[0].gettxoutproof, [txid1, txid1]) # Now we'll try tweaking a proof. proof = self.nodes[1].gettxoutproof([txid1, txid2]) assert txid1 in self.nodes[0].verifytxoutproof(proof) assert txid2 in self.nodes[1].verifytxoutproof(proof) tweaked_proof = from_hex(CMerkleBlock(), proof) # Make sure that our serialization/deserialization is working assert txid1 in self.nodes[0].verifytxoutproof( tweaked_proof.serialize().hex()) # Check to see if we can go up the merkle tree and pass this off as a # single-transaction block tweaked_proof.txn.nTransactions = 1 tweaked_proof.txn.vHash = [tweaked_proof.header.hashMerkleRoot] tweaked_proof.txn.vBits = [True] + [False] * 7 for n in self.nodes: assert not n.verifytxoutproof(tweaked_proof.serialize().hex())
def test_getblocktxn_handler(self, test_node): node = self.nodes[0] # bitcoind will not send blocktxn responses for blocks whose height is # more than 10 blocks deep. MAX_GETBLOCKTXN_DEPTH = 10 chain_height = node.getblockcount() current_height = chain_height while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH): block_hash = node.getblockhash(current_height) block = from_hex(CBlock(), node.getblock(block_hash, False)) msg = msg_getblocktxn() msg.block_txn_request = BlockTransactionsRequest( int(block_hash, 16), []) num_to_request = random.randint(1, len(block.vtx)) msg.block_txn_request.from_absolute( sorted(random.sample(range(len(block.vtx)), num_to_request))) test_node.send_message(msg) test_node.wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) [tx.calc_sha256() for tx in block.vtx] with p2p_lock: assert_equal( test_node.last_message["blocktxn"].block_transactions. blockhash, int(block_hash, 16)) all_indices = msg.block_txn_request.to_absolute() for index in all_indices: tx = test_node.last_message[ "blocktxn"].block_transactions.transactions.pop(0) tx.calc_sha256() assert_equal(tx.sha256, block.vtx[index].sha256) # Check that the witness matches assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True)) test_node.last_message.pop("blocktxn", None) current_height -= 1 # Next request should send a full block response, as we're past the # allowed depth for a blocktxn response. block_hash = node.getblockhash(current_height) msg.block_txn_request = BlockTransactionsRequest( int(block_hash, 16), [0]) with p2p_lock: test_node.last_message.pop("block", None) test_node.last_message.pop("blocktxn", None) test_node.send_and_ping(msg) with p2p_lock: test_node.last_message["block"].block.calc_sha256() assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16)) assert "blocktxn" not in test_node.last_message # Request with out-of-bounds tx index results in disconnect bad_peer = self.nodes[0].add_p2p_connection(TestP2PConn()) block_hash = node.getblockhash(chain_height) block = from_hex(CBlock(), node.getblock(block_hash, False)) msg.block_txn_request = BlockTransactionsRequest( int(block_hash, 16), [len(block.vtx)]) with node.assert_debug_log( ['getblocktxn with out-of-bounds tx indices']): bad_peer.send_message(msg) bad_peer.wait_for_disconnect()