def test_auxpow(nodes): """ Test behaviour of getauxpow. Calling getauxpow should reserve a key from the pool, but it should be released again if the created block is not actually used. On the other hand, if the auxpow is submitted and turned into a block, the keypool should be drained. """ nodes[0].walletpassphrase('test', 12000) nodes[0].keypoolrefill(1) nodes[0].walletlock() assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 1) nodes[0].getauxblock() assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 1) nodes[0].generate(1) assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 1) auxblock = nodes[0].getauxblock() assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 1) target = reverseHex(auxblock['_target']) solved = computeAuxpow(auxblock['hash'], target, True) res = nodes[0].getauxblock(auxblock['hash'], solved) assert res assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 0) assert_raises_rpc_error(-12, 'Keypool ran out', nodes[0].getauxblock)
def test_auxpow(self, nodes): """ Test behaviour of getauxpow. Calling getauxpow should reserve a key from the pool, but it should be released again if the created block is not actually used. On the other hand, if the auxpow is submitted and turned into a block, the keypool should be drained. """ extraKeys = 0 if self.options.descriptors: extraKeys = 12 nodes[0].walletpassphrase('test', 12000) nodes[0].keypoolrefill(1) nodes[0].walletlock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1 + extraKeys) nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], extraKeys) nodes[0].generate(1) assert_equal(nodes[0].getwalletinfo()['keypoolsize'], extraKeys) auxblock = nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], extraKeys) target = reverseHex(auxblock['_target']) solved = computeAuxpow(auxblock['hash'], target, True) res = nodes[0].getauxblock(auxblock['hash'], solved) assert res assert_equal(nodes[0].getwalletinfo()['keypoolsize'], extraKeys) assert_raises_rpc_error(-12, 'Keypool ran out', nodes[0].getauxblock)
def addAuxpow(self, block, blkHash, ok): """ Fills in the auxpow for the given block message. It is either chosen to be valid (ok = True) or invalid (ok = False). """ target = b"%064x" % uint256_from_compact(block.nBits) auxpowHex = computeAuxpow(blkHash, target, ok) block.auxpow = CAuxPow() block.auxpow.deserialize(BytesIO(hex_str_to_bytes(auxpowHex))) return block
def addAuxpow (self, block, blkHash, ok): """ Fills in the auxpow for the given block message. It is either chosen to be valid (ok = True) or invalid (ok = False). """ target = b"%064x" % uint256_from_compact (block.nBits) auxpowHex = computeAuxpow (blkHash, target, ok) block.auxpow = CAuxPow () block.auxpow.deserialize (BytesIO (hex_str_to_bytes (auxpowHex))) return block
def addAuxpow(self, block, blkHash, ok): """ Fills in the auxpow for the given block message. It is either chosen to be valid (ok = True) or invalid (ok = False). """ tmpl = self.nodes[0].getauxblock() target = reverseHex(tmpl["_target"]) auxpowHex = computeAuxpow(blkHash, target, ok) block.auxpow = CAuxPow() block.auxpow.deserialize(BytesIO(hex_str_to_bytes(auxpowHex))) return block
def createBlock(self): """ Creates and mines a new block with auxpow. """ bestHash = self.nodes[0].getbestblockhash() bestBlock = self.nodes[0].getblock(bestHash) tip = int(bestHash, 16) height = bestBlock["height"] + 1 time = bestBlock["time"] + 1 block = create_block(tip, create_coinbase(height), time) newHash = "%064x" % block.sha256 target = b"%064x" % uint256_from_compact(block.powData.nBits) auxpowHex = computeAuxpow(newHash, target, True) block.powData.set_merge_mined() block.powData.auxpow.deserialize(BytesIO(hex_str_to_bytes(auxpowHex))) return block, newHash
def createBlock (self): """ Creates and mines a new block with auxpow. """ bestHash = self.nodes[0].getbestblockhash () bestBlock = self.nodes[0].getblock (bestHash) tip = int (bestHash, 16) height = bestBlock["height"] + 1 time = bestBlock["time"] + 1 block = create_block (tip, create_coinbase (height), time) block.mark_auxpow () block.rehash () newHash = "%064x" % block.sha256 target = b"%064x" % uint256_from_compact (block.nBits) auxpowHex = computeAuxpow (newHash, target, True) block.auxpow = CAuxPow () block.auxpow.deserialize (BytesIO (hex_str_to_bytes (auxpowHex))) return block, newHash
def test_common(self, create, submit): """ Common test code that is shared between the tests for getauxblock and the createauxblock / submitauxblock method pair. """ # Verify data that can be found in another way. auxblock = create() assert_equal(auxblock['chainid'], 1) assert_equal(auxblock['height'], self.nodes[0].getblockcount() + 1) assert_equal(auxblock['previousblockhash'], self.nodes[0].getblockhash(auxblock['height'] - 1)) # Calling again should give the same block. auxblock2 = create() assert_equal(auxblock2, auxblock) # If we receive a new block, the old hash will be replaced. self.sync_all() self.nodes[1].generate(1) self.sync_all() auxblock2 = create() assert auxblock['hash'] != auxblock2['hash'] assert_raises_rpc_error(-8, 'block hash unknown', submit, auxblock['hash'], "x") # Invalid format for auxpow. assert_raises_rpc_error(-1, None, submit, auxblock2['hash'], "x") # Invalidate the block again, send a transaction and query for the # auxblock to solve that contains the transaction. self.nodes[0].generate(1) addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 1) self.sync_all() assert_equal(self.nodes[1].getrawmempool(), [txid]) auxblock = create() target = reverseHex(auxblock['_target']) # Cross-check target value with GBT to make explicitly sure that it is # correct (not just implicitly by successfully mining blocks for it # later on). gbt = self.nodes[0].getblocktemplate({"rules": ["segwit"]}) assert_equal(target, gbt['target'].encode("ascii")) # Compute invalid auxpow. apow = computeAuxpow(auxblock['hash'], target, False) res = submit(auxblock['hash'], apow) assert not res # Compute and submit valid auxpow. apow = computeAuxpow(auxblock['hash'], target, True) res = submit(auxblock['hash'], apow) assert res # Make sure that the block is indeed accepted. self.sync_all() assert_equal(self.nodes[1].getrawmempool(), []) height = self.nodes[1].getblockcount() assert_equal(height, auxblock['height']) assert_equal(self.nodes[1].getblockhash(height), auxblock['hash']) # Call getblock and verify the auxpow field. data = self.nodes[1].getblock(auxblock['hash']) assert 'auxpow' in data auxJson = data['auxpow'] assert_equal(auxJson['index'], 0) assert_equal(auxJson['chainindex'], 0) assert_equal(auxJson['merklebranch'], []) assert_equal(auxJson['chainmerklebranch'], []) assert_equal(auxJson['parentblock'], apow[-160:]) # Also previous blocks should have 'auxpow', since all blocks (also # those generated by "generate") are merge-mined. oldHash = self.nodes[1].getblockhash(100) data = self.nodes[1].getblock(oldHash) assert 'auxpow' in data # Check that it paid correctly to the first node. t = self.nodes[0].listtransactions("*", 1) assert_equal(len(t), 1) t = t[0] assert_equal(t['category'], "immature") assert_equal(t['blockhash'], auxblock['hash']) assert t['generated'] assert_greater_than_or_equal(t['amount'], Decimal("1")) assert_equal(t['confirmations'], 1) # Verify the coinbase script. Ensure that it includes the block height # to make the coinbase tx unique. The expected block height is around # 200, so that the serialisation of the CScriptNum ends in an extra 00. # The vector has length 2, which makes up for 02XX00 as the serialised # height. Check this. (With segwit, the height is different, so we skip # this for simplicity.) if not self.options.segwit: blk = self.nodes[1].getblock(auxblock['hash']) tx = self.nodes[1].getrawtransaction(blk['tx'][0], 1) coinbase = tx['vin'][0]['coinbase'] assert_equal("02%02x00" % auxblock['height'], coinbase[0:6])
def test_auxpow(nodes): """ Test behaviour of getauxpow. Calling getauxpow should reserve a key from the pool, but it should be released again if the created block is not actually used. On the other hand, if the auxpow is submitted and turned into a block, the keypool should be drained. """ nodes[0].walletpassphrase('test', 12000) nodes[0].keypoolrefill(1) nodes[0].walletlock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) nodes[0].generate(1) assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) auxblock = nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) target = reverseHex(auxblock['_target']) solved = computeAuxpow(auxblock['hash'], target, True) res = nodes[0].getauxblock(auxblock['hash'], solved) assert res assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 0) assert_raises_rpc_error(-12, 'Keypool ran out', nodes[0].getauxblock) # drain the internal keys nodes[0].getrawchangeaddress() nodes[0].getrawchangeaddress() nodes[0].getrawchangeaddress() nodes[0].getrawchangeaddress() nodes[0].getrawchangeaddress() nodes[0].getrawchangeaddress() addr = set() # the next one should fail assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getrawchangeaddress) # drain the external keys addr.add(nodes[0].getnewaddress()) addr.add(nodes[0].getnewaddress()) addr.add(nodes[0].getnewaddress()) addr.add(nodes[0].getnewaddress()) addr.add(nodes[0].getnewaddress()) addr.add(nodes[0].getnewaddress()) assert len(addr) == 6 # the next one should fail assert_raises_rpc_error( -12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) # refill keypool with three new addresses nodes[0].walletpassphrase('test', 1) nodes[0].keypoolrefill(3) # test walletpassphrase timeout time.sleep(1.1) assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0) # drain the keypool for _ in range(3): nodes[0].getnewaddress() assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getnewaddress) nodes[0].walletpassphrase('test', 100) nodes[0].keypoolrefill(100) wi = nodes[0].getwalletinfo() assert_equal(wi['keypoolsize_hd_internal'], 100) assert_equal(wi['keypoolsize'], 100)
def test_common (self, create, submit): """ Common test code that is shared between the tests for getauxblock and the createauxblock / submitauxblock method pair. """ # Verify data that can be found in another way. auxblock = create () assert_equal (auxblock['chainid'], 1) assert_equal (auxblock['height'], self.nodes[0].getblockcount () + 1) assert_equal (auxblock['previousblockhash'], self.nodes[0].getblockhash (auxblock['height'] - 1)) # Calling again should give the same block. auxblock2 = create () assert_equal (auxblock2, auxblock) # If we receive a new block, the old hash will be replaced. self.sync_all () self.nodes[1].generate (1) self.sync_all () auxblock2 = create () assert auxblock['hash'] != auxblock2['hash'] assert_raises_rpc_error (-8, 'block hash unknown', submit, auxblock['hash'], "x") # Invalid format for auxpow. assert_raises_rpc_error (-1, None, submit, auxblock2['hash'], "x") # Invalidate the block again, send a transaction and query for the # auxblock to solve that contains the transaction. self.nodes[0].generate (1) addr = self.nodes[1].getnewaddress () txid = self.nodes[0].sendtoaddress (addr, 1) self.sync_all () assert_equal (self.nodes[1].getrawmempool (), [txid]) auxblock = create () target = reverseHex (auxblock['_target']) # Cross-check target value with GBT to make explicitly sure that it is # correct (not just implicitly by successfully mining blocks for it # later on). gbt = self.nodes[0].getblocktemplate ({"rules": ["segwit"]}) assert_equal (target, gbt['target'].encode ("ascii")) # Compute invalid auxpow. apow = computeAuxpow (auxblock['hash'], target, False) res = submit (auxblock['hash'], apow) assert not res # Compute and submit valid auxpow. apow = computeAuxpow (auxblock['hash'], target, True) res = submit (auxblock['hash'], apow) assert res # Make sure that the block is indeed accepted. self.sync_all () assert_equal (self.nodes[1].getrawmempool (), []) height = self.nodes[1].getblockcount () assert_equal (height, auxblock['height']) assert_equal (self.nodes[1].getblockhash (height), auxblock['hash']) # Call getblock and verify the auxpow field. data = self.nodes[1].getblock (auxblock['hash']) assert 'auxpow' in data auxJson = data['auxpow'] assert_equal (auxJson['chainindex'], 0) assert_equal (auxJson['merklebranch'], []) assert_equal (auxJson['chainmerklebranch'], []) assert_equal (auxJson['parentblock'], apow[-160:]) # Also previous blocks should have 'auxpow', since all blocks (also # those generated by "generate") are merge-mined. oldHash = self.nodes[1].getblockhash (100) data = self.nodes[1].getblock (oldHash) assert 'auxpow' in data # Check that it paid correctly to the first node. t = self.nodes[0].listtransactions ("*", 1) assert_equal (len (t), 1) t = t[0] assert_equal (t['category'], "immature") assert_equal (t['blockhash'], auxblock['hash']) assert t['generated'] assert_greater_than_or_equal (t['amount'], Decimal ("1")) assert_equal (t['confirmations'], 1) # Verify the coinbase script. Ensure that it includes the block height # to make the coinbase tx unique. The expected block height is around # 200, so that the serialisation of the CScriptNum ends in an extra 00. # The vector has length 2, which makes up for 02XX00 as the serialised # height. Check this. (With segwit, the height is different, so we skip # this for simplicity.) if not self.options.segwit: blk = self.nodes[1].getblock (auxblock['hash']) tx = self.nodes[1].getrawtransaction (blk['tx'][0], True, blk['hash']) coinbase = tx['vin'][0]['coinbase'] assert_equal ("02%02x00" % auxblock['height'], coinbase[0 : 6])
def test_common(self, create, submit): # Verify data that can be found in another way. auxblock = create() assert_equal(auxblock['chainid'], 0x2137) assert_equal(auxblock['height'], self.nodes[0].getblockcount() + 1) assert_equal(auxblock['previousblockhash'], self.nodes[0].getblockhash(auxblock['height'] - 1)) # Calling again should give the same block. auxblock2 = create() assert_equal(auxblock2, auxblock) # If we receive a new block, the old hash will be replaced. self.sync_all() self.nodes[1].generate(1) self.sync_all() auxblock2 = create() assert auxblock['hash'] != auxblock2['hash'] assert_raises_rpc_error(-8, 'block hash unknown', submit, auxblock['hash'], "x") # Invalid format for auxpow. assert_raises_rpc_error(-1, None, submit, auxblock2['hash'], "x") # Invalidate the block again, send a transaction and query for the # auxblock to solve that contains the transaction. self.nodes[0].generate(1) addr = "THG2uNG2VASsFWK4DmpZZpkwKtC5Qjkyoo" txid = self.nodes[0].sendtoaddress(addr, 1) self.sync_all() assert_equal(self.nodes[1].getrawmempool(), [txid]) auxblock = create() target = b"%064x" % uint256_from_compact(int(auxblock['bits'], 16)) # Compute invalid auxpow apow = computeAuxpow(auxblock['hash'], target, False) res = submit(auxblock['hash'], apow) assert not res # Compute valid auxpow apow = computeAuxpow(auxblock['hash'], target, True) res = submit(auxblock['hash'], apow) assert res # Make sure that the block is indeed accepted. self.sync_all() assert_equal(self.nodes[1].getrawmempool(), []) height = self.nodes[1].getblockcount() assert_equal(height, auxblock['height']) assert_equal(self.nodes[1].getblockhash(height), auxblock['hash']) # Call getblock and verify the auxpow field. data = self.nodes[1].getblock(auxblock['hash']) print(data) assert 'auxheader' in data auxJson = data['auxheader'] assert_equal(auxJson['chainindex'], 0) assert_equal(auxJson['merklebranch'], []) assert_equal(auxJson['chainmerklebranch'], []) assert_equal(auxJson['parentblock'], apow[-160:]) # Also previous blocks should have 'auxpow', since all blocks (also # those generated by "generate") are merge-mined. oldHash = self.nodes[1].getblockhash(100) data = self.nodes[1].getblock(oldHash) assert 'auxheader' in data # Check that it paid correctly to the first node. t = self.nodes[0].listtransactions("*", 1) assert_equal(len(t), 1) t = t[0] assert_equal(t['category'], "immature") assert_equal(t['blockhash'], auxblock['hash']) assert t['generated'] assert_greater_than_or_equal(t['amount'], Decimal("1")) assert_equal(t['confirmations'], 1) # Verify the coinbase script. Ensure that it includes the block height # to make the coinbase tx unique. The expected block height is around # 200, so that the serialisation of the CScriptNum ends in an extra 00. # The vector has length 2, which makes up for 02XX00 as the serialised # height. Check this. (With segwit, the height is different, so we skip # this for simplicity.) if not self.options.segwit: blk = self.nodes[1].getblock(auxblock['hash']) tx = self.nodes[1].getrawtransaction(blk['tx'][0], True, blk['hash']) coinbase = tx['vin'][0]['coinbase'] assert_equal("02%02x00" % auxblock['height'], coinbase[0:6])