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 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'], 2) nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 2) nodes[0].generate(1) assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) auxblock = nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) target = auxpow.reverseHex(auxblock['_target']) solved = auxpow.computeAuxpow(auxblock['hash'], target, True) res = nodes[0].getauxblock(auxblock['hash'], solved) assert res assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 0) try: nodes[0].getauxblock() raise AssertionError('Keypool should be exhausted by getauxblock') except JSONRPCException as e: assert (e.error['code'] == -12)
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(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'], 2) nodes[0].getauxblock() assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 2) nodes[0].generate(1) assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 1) auxblock = nodes[0].getauxblock() assert_equal (nodes[0].getwalletinfo()['keypoolsize'], 1) target = auxpow.reverseHex(auxblock['_target']) solved = auxpow.computeAuxpow(auxblock['hash'], target, True) res = nodes[0].getauxblock(auxblock['hash'], solved) assert res assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 0) try: nodes[0].getauxblock() raise AssertionError('Keypool should be exhausted by getauxblock') except JSONRPCException as e: assert(e.error['code']==-12)
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(2) nodes[0].walletlock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 2) nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 2) nodes[0].generate(1) assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) auxblock = nodes[0].getauxblock() assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 1) target = auxpow.reverseHex(auxblock['_target']) solved = auxpow.computeAuxpow(auxblock['hash'], target, True) res = nodes[0].getauxblock(auxblock['hash'], solved) assert res assert_equal(nodes[0].getwalletinfo()['keypoolsize'], 0) assert_raises_jsonrpc(-12, 'Keypool ran out', nodes[0].getauxblock)
def mineAuxpowBlockWithMethods (create, submit): """ Mine an auxpow block, using the given methods for creation and submission. """ auxblock = create () target = auxpow.reverseHex (auxblock['_target']) apow = computeAuxpow (auxblock['hash'], target, True) res = submit (auxblock['hash'], apow) assert res return auxblock['hash']
def mineWorkBlockWithMethods (rpc, create, submit): """ Mine a stand-alone block, using the given methods for creation and submission. """ work = create () target = auxpow.reverseHex (work['target']) solved = solveData (work['data'], target, True) res = submit (work['hash'], solved) assert res return work['hash']
def mineAuxpowBlockWithMethods(create, submit): """ Mine an auxpow block, using the given methods for creation and submission. """ auxblock = create() target = auxpow.reverseHex(auxblock['_target']) apow = computeAuxpow(auxblock['hash'], target, True) res = submit(auxblock['hash'], apow) assert res return auxblock['hash']
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 run_test(self): # Check for difficulty reports in various RPC calls. Where the "current" # state is involved, we get two (for each algo). Where a particular block # is involved, we just get that block's difficulty (whatever the algo). dual = [] dual.append(self.nodes[0].getblockchaininfo()) dual.append(self.nodes[0].getmininginfo()) for data in dual: assert 'difficulty_sha256d' in data assert 'difficulty_scrypt' in data assert 'difficulty' not in data bestHash = self.nodes[0].getbestblockhash() data = self.nodes[0].getblock(bestHash) assert 'difficulty' in data assert 'difficulty_sha256d' not in data assert 'difficulty_scrypt' not in data # Check getdifficulty RPC call. diffSHA = self.nodes[0].getdifficulty(0) assert_equal(diffSHA, dual[0]['difficulty_sha256d']) diffScrypt = self.nodes[0].getdifficulty(1) assert_equal(diffScrypt, dual[0]['difficulty_scrypt']) assert_raises_jsonrpc(-1, None, self.nodes[0].getdifficulty) # Generate a few blocks with SHA256D. Ensure that they are, indeed, # with the correct algo. arr1 = self.nodes[0].generate(5) arr2 = self.nodes[0].generate(5, 0) for blk in arr1 + arr2: data = self.nodes[0].getblock(blk) assert_equal(data['algo'], 0) # Generate a few blocks with scrypt. Ensure the algo parameter. # Furthermore, at least one of them "should" have an obviously high # hash value. It may, of course, happen that this is not the case, # but the probability for that is negligible (about 2^(-20)). arr = self.nodes[0].generate(20, 1) foundHigh = False for blk in arr: data = self.nodes[0].getblock(blk) assert_equal(data['algo'], 1) if blk[0] in '89abcdef': foundHigh = True assert foundHigh # Verify check for algo parameter. for p in [-1, 2]: assert_raises_jsonrpc(-8, 'invalid algo', self.nodes[0].generate, 1, p) # Briefly test generatetoaddress as well. for algo in [0, 1]: addr = self.nodes[0].getnewaddress() blkhash = self.nodes[0].generatetoaddress(1, addr, algo) assert_equal(1, len(blkhash)) data = self.nodes[0].getblock(blkhash[0]) assert_equal(algo, data['algo']) coinbaseTx = data['tx'][0] utxo = self.nodes[0].gettxout(coinbaseTx, 0) assert_equal([addr], utxo['scriptPubKey']['addresses']) # Check updates of the returned block (or not) with aux mining. # Note that this behaviour needs not necessarily be exactly as tested, # but the test ensures that no change is introduced accidentally. coinbaseAddr = self.nodes[0].getnewaddress() auxblock1 = self.nodes[0].createauxblock(coinbaseAddr) auxblock2 = self.nodes[0].createauxblock(coinbaseAddr, 0) assert_equal(auxblock1['hash'], auxblock2['hash']) auxblock2 = self.nodes[0].createauxblock(coinbaseAddr, 1) auxblock3 = self.nodes[0].createauxblock(coinbaseAddr, 1) assert_equal(auxblock2['hash'], auxblock3['hash']) assert auxblock2['hash'] != auxblock1['hash'] auxblock3 = self.nodes[0].createauxblock(coinbaseAddr) assert auxblock1['hash'] != auxblock3['hash'] # Use createauxblock with explicit algo to mine a SHA256D block. # Assert that this works (the block is saved) even if we request # another scrypt block before. auxblock = self.nodes[0].createauxblock(coinbaseAddr) assert_equal(auxblock['chainid'], 6) assert_equal(auxblock['algo'], 0) dummy = self.nodes[0].createauxblock(coinbaseAddr, 1) assert_equal(dummy['chainid'], 2) assert_equal(dummy['algo'], 1) # Solve the auxpow requested before. curcnt = self.nodes[0].getblockcount() target = auxpow.reverseHex(auxblock['_target']) apow = auxpow.computeAuxpow(auxblock['hash'], target, True) res = self.nodes[0].submitauxblock(auxblock['hash'], apow) assert res # Check submitted data. assert_equal(self.nodes[0].getblockcount(), curcnt + 1) data = self.nodes[0].getblock(auxblock['hash']) assert_equal(data['algo'], 0) # Mine an scrypt auxpow. Since there is no built-in Python # function to scrypt, we do it differently: Simply try submitting # until the block is accepted. Since we need on average 2 trials, # this is no big hit. trials = 0 curcnt = self.nodes[0].getblockcount() ok = False while not ok: if trials > 100: raise AssertionError("failed to merge-mine scrypt auxpow") trials += 1 # Force an update of the block so we get a new trial. self.nodes[0].createauxblock(coinbaseAddr, 0) auxblock = self.nodes[0].createauxblock(coinbaseAddr, 1) target = auxpow.reverseHex(auxblock['_target']) apow = auxpow.computeAuxpow(auxblock['hash'], target, False) ok = self.nodes[0].submitauxblock(auxblock['hash'], apow) print("Found scrypt block after %d trials." % trials) # Check submitted auxblock. assert_equal(self.nodes[0].getblockcount(), curcnt + 1) data = self.nodes[0].getblock(auxblock['hash']) assert_equal(data['algo'], 1)
def run_test(self): BitcoinTestFramework.run_test(self) # Generate a block so that we are not "downloading blocks". self.nodes[0].generate(1) # Compare basic data of getauxblock to getblocktemplate. auxblock = self.nodes[0].getauxblock() blocktemplate = self.nodes[0].getblocktemplate() assert_equal(auxblock['coinbasevalue'], blocktemplate['coinbasevalue']) assert_equal(auxblock['bits'], blocktemplate['bits']) assert_equal(auxblock['height'], blocktemplate['height']) assert_equal(auxblock['previousblockhash'], blocktemplate['previousblockhash']) # Compare target and take byte order into account. target = auxblock['_target'] reversedTarget = auxpow.reverseHex(target) assert_equal(reversedTarget, blocktemplate['target']) # Verify data that can be found in another way. 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 = self.nodes[0].getauxblock() 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 = self.nodes[0].getauxblock() assert auxblock['hash'] != auxblock2['hash'] try: self.nodes[0].getauxblock(auxblock['hash'], "x") raise AssertionError("invalid block hash accepted") except JSONRPCException as exc: assert_equal(exc.error['code'], -8) # Invalid format for auxpow. try: self.nodes[0].getauxblock(auxblock2['hash'], "x") raise AssertionError("malformed auxpow accepted") except JSONRPCException as exc: assert_equal(exc.error['code'], -1) # 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 = self.nodes[0].getauxblock() blocktemplate = self.nodes[0].getblocktemplate() target = blocktemplate['target'] # Compute invalid auxpow. apow = auxpow.computeAuxpow(auxblock['hash'], target, False) res = self.nodes[0].getauxblock(auxblock['hash'], apow) assert not res # Compute and submit valid auxpow. apow = auxpow.computeAuxpow(auxblock['hash'], target, True) res = self.nodes[0].getauxblock(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['parentblock'], apow[-160:]) # Check that previous blocks don't have 'auxpow' in their getblock JSON. oldHash = self.nodes[1].getblockhash(100) data = self.nodes[1].getblock(oldHash) assert 'auxpow' not 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 t['amount'] >= Decimal("25") 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. 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 run_test (self): BitcoinTestFramework.run_test (self) # Generate a block so that we are not "downloading blocks". self.nodes[0].generate (1) # We used to compare to getblocktemplate, but this call is gone # now completely for merge-mining. # Verify data that can be found in another way. auxblock = self.nodes[0].getauxblock () 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 = self.nodes[0].getauxblock () 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 = self.nodes[0].getauxblock () assert auxblock['hash'] != auxblock2['hash'] try: self.nodes[0].getauxblock (auxblock['hash'], "x") raise AssertionError ("invalid block hash accepted") except JSONRPCException as exc: assert_equal (exc.error['code'], -8) # Invalid format for auxpow. try: self.nodes[0].getauxblock (auxblock2['hash'], "x") raise AssertionError ("malformed auxpow accepted") except JSONRPCException as exc: assert_equal (exc.error['code'], -1) # 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 = self.nodes[0].getauxblock () target = auxpow.reverseHex (auxblock['_target']) # Compute invalid auxpow. apow = auxpow.computeAuxpow (auxblock['hash'], target, False) res = self.nodes[0].getauxblock (auxblock['hash'], apow) assert not res # Compute and submit valid auxpow. apow = auxpow.computeAuxpow (auxblock['hash'], target, True) res = self.nodes[0].getauxblock (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 t['amount'] >= Decimal ("25") 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. 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]) # Ensure that the payout address is changed from one block to the next. addr1 = self.getCoinbaseAddr (auxblock['hash']) newHash = auxpow.mineAuxpowBlock (self.nodes[0]) self.sync_all () addr2 = self.getCoinbaseAddr (newHash) assert addr1 != addr2 valid = self.nodes[0].validateaddress (addr1) assert valid['ismine'] valid = self.nodes[0].validateaddress (addr2) assert valid['ismine']
def test_common(self, create, submit): """ Common test code that is shared between the tests for getwork and the creatework / submitwork method pair. """ # Verify data that can be found in another way. work = create() assert_equal(work['algo'], 'neoscrypt') assert_equal(work['height'], self.nodes[0].getblockcount() + 1) assert_equal(work['previousblockhash'], self.nodes[0].getblockhash(work['height'] - 1)) # Invalid format for data. assert_raises_rpc_error(-8, None, submit, "", "x") assert_raises_rpc_error(-8, None, submit, "", "00") # Compute invalid work. target = reverseHex(work['target']) solved = solveData(work['data'], target, False) res = submit(work['hash'], solved) assert not res # Compute and submit valid work. solved = solveData(work['data'], target, True) res = submit(work['hash'], solved) assert res # Make sure that the block is indeed accepted. height = self.nodes[0].getblockcount() assert_equal(height, work['height']) # Call getblock and verify the powdata field. data = self.nodes[0].getblock(work['hash']) assert 'powdata' in data data = data['powdata'] assert_equal(data['algo'], 'neoscrypt') assert_equal(data['mergemined'], False) assert_equal(data['bits'], '207fffff') assert 'difficulty' in data fakeHeader = codecs.decode(solved, 'hex_codec') fakeHeader = getworkByteswap(fakeHeader) fakeHeader = codecs.encode(fakeHeader, 'hex_codec') fakeHeader = codecs.decode(fakeHeader, 'ascii') assert_equal(data['fakeheader'], fakeHeader) # Also previous blocks should have 'powdata', since all blocks (also # those generated by "generate") are mined with it. oldHash = self.nodes[0].getblockhash(100) data = self.nodes[0].getblock(oldHash) assert 'powdata' 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 t['generated'] assert_greater_than_or_equal(t['amount'], Decimal("1")) assert_equal(t['confirmations'], 1) # Mine a block using the hash-less form of submit. work = create() target = reverseHex(work['target']) solved = solveData(work['data'], target, True) res = submit(solved) assert res assert_equal(self.nodes[0].getbestblockhash(), work['hash'])
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 run_test(self): # Generate a block so that we are not "downloading blocks". self.nodes[0].generate(1) # specify coinbase output coinbaseAddress = self.nodes[0].getnewaddress() # # check params # # missing address assert_raises_jsonrpc(-1, None, self.nodes[0].createauxblock) # invalid address assert_raises_jsonrpc(-8, "Invalid coinbase payout address", self.nodes[0].createauxblock, "this_a_invalid_address") # Verify data that can be found in another way. auxblock = self.nodes[0].createauxblock(coinbaseAddress) 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 = self.nodes[0].createauxblock(coinbaseAddress) 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 = self.nodes[0].createauxblock(coinbaseAddress) assert auxblock['hash'] != auxblock2['hash'] # Invalid format for auxpow. assert_raises_jsonrpc(-8, 'block hash unknown', self.nodes[0].submitauxblock, auxblock['hash'], "x") assert_raises_jsonrpc(-1, None, self.nodes[0].submitauxblock, 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 = self.nodes[0].createauxblock(coinbaseAddress) target = auxpow.reverseHex(auxblock['_target']) # Compute invalid auxpow. apow = auxpow.computeAuxpow(auxblock['hash'], target, False) res = self.nodes[0].submitauxblock(auxblock['hash'], apow) assert not res # Compute and submit valid auxpow. apow = auxpow.computeAuxpow(auxblock['hash'], target, True) res = self.nodes[0].submitauxblock(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 t['amount'] >= Decimal("25") 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. 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]) # Ensure that the payout address is the one which we specify addr1 = auxpow.getCoinbaseAddr(self.nodes[1], auxblock['hash']) assert addr1 == coinbaseAddress newHash = auxpow.mineAuxpowBlock2(self.nodes[0], coinbaseAddress) self.sync_all() addr2 = auxpow.getCoinbaseAddr(self.nodes[1], newHash) assert addr2 == coinbaseAddress
def run_test (self): BitcoinTestFramework.run_test (self) # Generate a block so that we are not "downloading blocks". self.nodes[0].generate (1) # Compare basic data of getauxblock to getblocktemplate. auxblock = self.nodes[0].getauxblock () blocktemplate = self.nodes[0].getblocktemplate () assert_equal (auxblock['coinbasevalue'], blocktemplate['coinbasevalue']) assert_equal (auxblock['bits'], blocktemplate['bits']) assert_equal (auxblock['height'], blocktemplate['height']) assert_equal (auxblock['previousblockhash'], blocktemplate['previousblockhash']) # Compare target and take byte order into account. target = auxblock['_target'] reversedTarget = auxpow.reverseHex (target) assert_equal (reversedTarget, blocktemplate['target']) # Verify data that can be found in another way. 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 = self.nodes[0].getauxblock () 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 = self.nodes[0].getauxblock () assert auxblock['hash'] != auxblock2['hash'] try: self.nodes[0].getauxblock (auxblock['hash'], "x") raise AssertionError ("invalid block hash accepted") except JSONRPCException as exc: assert_equal (exc.error['code'], -8) # Invalid format for auxpow. try: self.nodes[0].getauxblock (auxblock2['hash'], "x") raise AssertionError ("malformed auxpow accepted") except JSONRPCException as exc: assert_equal (exc.error['code'], -1) # 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 = self.nodes[0].getauxblock () blocktemplate = self.nodes[0].getblocktemplate () target = blocktemplate['target'] # Compute invalid auxpow. apow = auxpow.computeAuxpow (auxblock['hash'], target, False) res = self.nodes[0].getauxblock (auxblock['hash'], apow) assert not res # Compute and submit valid auxpow. apow = auxpow.computeAuxpow (auxblock['hash'], target, True) res = self.nodes[0].getauxblock (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['parentblock'], apow[-160:]) # Check that previous blocks don't have 'auxpow' in their getblock JSON. oldHash = self.nodes[1].getblockhash (100) data = self.nodes[1].getblock (oldHash) assert 'auxpow' not 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 t['amount'] >= Decimal ("25") 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. 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]) # Ensure that the payout address is changed from one block to the next. addr1 = self.getCoinbaseAddr (auxblock['hash']) newHash = auxpow.mineAuxpowBlock (self.nodes[0]) self.sync_all () addr2 = self.getCoinbaseAddr (newHash) assert addr1 != addr2 valid = self.nodes[0].validateaddress (addr1) assert valid['ismine'] valid = self.nodes[0].validateaddress (addr2) assert valid['ismine']
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 run_test (self): BitcoinTestFramework.run_test (self) # Check for difficulty reports in various RPC calls. Where the "current" # state is involved, we get two (for each algo). Where a particular block # is involved, we just get that block's difficulty (whatever the algo). dual = [] dual.append (self.nodes[0].getinfo ()) dual.append (self.nodes[0].getblockchaininfo ()) dual.append (self.nodes[0].getmininginfo ()) for data in dual: assert 'difficulty_sha256d' in data assert 'difficulty_scrypt' in data assert 'difficulty' not in data bestHash = self.nodes[0].getbestblockhash () data = self.nodes[0].getblock (bestHash) assert 'difficulty' in data assert 'difficulty_sha256d' not in data assert 'difficulty_scrypt' not in data # Check getdifficulty RPC call. diffSHA = self.nodes[0].getdifficulty (0) assert_equal (diffSHA, dual[0]['difficulty_sha256d']) diffScrypt = self.nodes[0].getdifficulty (1) assert_equal (diffScrypt, dual[0]['difficulty_scrypt']) try: self.nodes[0].getdifficulty () raise AssertionError ("getdifficulty without arg accepted") except JSONRPCException as exc: assert_equal (exc.error['code'], -1) # Generate a few blocks with SHA256D. Ensure that they are, indeed, # with the correct algo. arr1 = self.nodes[0].generate (5) arr2 = self.nodes[0].generate (5, 0) for blk in arr1 + arr2: data = self.nodes[0].getblock (blk) assert_equal (data['algo'], 0) # Generate a few blocks with scrypt. Ensure the algo parameter. # Furthermore, at least one of them "should" have an obviously high # hash value. It may, of course, happen that this is not the case, # but the probability for that is negligible (about 2^(-20)). arr = self.nodes[0].generate (20, 1) foundHigh = False for blk in arr: data = self.nodes[0].getblock (blk) assert_equal (data['algo'], 1) if blk[0] in '89abcdef': foundHigh = True assert foundHigh # Verify check for algo parameter. for p in [-1, 2]: try: self.nodes[0].generate (1, p) raise AssertionError ("invalid algo parameter accepted") except JSONRPCException as exc: assert_equal (exc.error['code'], -8) # Briefly test generatetoaddress as well. for algo in [0, 1]: addr = self.nodes[0].getnewaddress () blkhash = self.nodes[0].generatetoaddress (1, addr, algo) assert_equal (1, len (blkhash)) data = self.nodes[0].getblock(blkhash[0]) assert_equal (algo, data['algo']) coinbaseTx = data['tx'][0] utxo = self.nodes[0].gettxout (coinbaseTx, 0) assert_equal ([addr], utxo['scriptPubKey']['addresses']) # Check updates of the returned block (or not) with getauxblock. # Note that this behaviour needs not necessarily be exactly as tested, # but the test ensures that no change is introduced accidentally. auxblock1 = self.nodes[0].getauxblock () auxblock2 = self.nodes[0].getauxblock (0) assert_equal (auxblock1['hash'], auxblock2['hash']) auxblock2 = self.nodes[0].getauxblock (1) auxblock3 = self.nodes[0].getauxblock (1) assert_equal (auxblock2['hash'], auxblock3['hash']) assert auxblock2['hash'] != auxblock1['hash'] auxblock3 = self.nodes[0].getauxblock () assert auxblock1['hash'] != auxblock3['hash'] # Use getauxblock with explicit algo to mine a SHA256D block. # Assert that this works (the block is saved) even if we request # another scrypt block before. auxblock = self.nodes[0].getauxblock () assert_equal (auxblock['chainid'], 6) assert_equal (auxblock['algo'], 0) dummy = self.nodes[0].getauxblock (1) assert_equal (dummy['chainid'], 2) assert_equal (dummy['algo'], 1) # Solve the auxpow requested before. curcnt = self.nodes[0].getblockcount () target = auxpow.reverseHex (auxblock['_target']) apow = auxpow.computeAuxpow (auxblock['hash'], target, True) res = self.nodes[0].getauxblock (auxblock['hash'], apow) assert res # Check submitted data. assert_equal (self.nodes[0].getblockcount (), curcnt + 1) data = self.nodes[0].getblock (auxblock['hash']) assert_equal (data['algo'], 0) # Mine an scrypt auxpow. Since there is no built-in Python # function to scrypt, we do it differently: Simply try submitting # until the block is accepted. Since we need on average 2 trials, # this is no big hit. trials = 0 curcnt = self.nodes[0].getblockcount () ok = False while not ok: if trials > 100: raise AssertionError ("failed to merge-mine scrypt auxpow") trials += 1 # Force an update of the block so we get a new trial. self.nodes[0].getauxblock (0) auxblock = self.nodes[0].getauxblock (1) target = auxpow.reverseHex (auxblock['_target']) apow = auxpow.computeAuxpow (auxblock['hash'], target, False) ok = self.nodes[0].getauxblock (auxblock['hash'], apow) print "Found scrypt block after %d trials." % trials # Check submitted auxblock. assert_equal (self.nodes[0].getblockcount (), curcnt + 1) data = self.nodes[0].getblock (auxblock['hash']) assert_equal (data['algo'], 1)