def run_test(self): url = urllib.parse.urlparse(self.nodes[0].url) self.log.info("Mining blocks...") self.nodes[0].generate(1) self.sync_all() self.nodes[2].generate(100) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() self.nodes[2].generate(1) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) #balance now should be 0.1 on node 1 # load the latest 0.1 tx over the REST API json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + txid + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0][ 'txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] ####################################### # GETUTXOS: query an unspent outpoint # ####################################### json_request = '/checkmempool/' + txid + '-' + str(n) json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is one utxo assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['utxos'][0]['value'], 0.1) ################################################# # GETUTXOS: now query an already spent outpoint # ################################################# json_request = '/checkmempool/' + vintx + '-0' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is no utox in the response because this oupoint has been spent assert_equal(len(json_obj['utxos']), 0) #check bitmap assert_equal(json_obj['bitmap'], "0") ################################################## # GETUTXOS: now check both with the same request # ################################################## json_request = '/checkmempool/' + txid + '-' + str( n) + '/' + vintx + '-0' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['bitmap'], "10") #test binary response bb_hash = self.nodes[0].getbestblockhash() binaryRequest = b'\x01\x02' binaryRequest += hex_str_to_bytes(txid) binaryRequest += pack("i", n) binaryRequest += hex_str_to_bytes(vintx) binaryRequest += pack("i", 0) bin_response = http_post_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'bin', binaryRequest) output = BytesIO() output.write(bin_response) output.seek(0) chainHeight = unpack("i", output.read(4))[0] hashFromBinResponse = hex(deser_uint256(output))[2:].zfill(64) assert_equal( bb_hash, hashFromBinResponse ) #check if getutxo's chaintip during calculation was fine assert_equal(chainHeight, 102) #chain height must be 102 ############################ # GETUTXOS: mempool checks # ############################ # do a tx and don't sync txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + txid + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0][ 'txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] json_request = '/' + txid + '-' + str(n) json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) assert_equal( len(json_obj['utxos']), 0 ) #there should be an outpoint because it has just added to the mempool json_request = '/checkmempool/' + txid + '-' + str(n) json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) assert_equal( len(json_obj['utxos']), 1 ) #there should be an outpoint because it has just added to the mempool #do some invalid requests json_request = '{"checkmempool' response = http_post_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request, True) assert_equal( response.status, 400) #must be a 400 because we send an invalid json request json_request = '{"checkmempool' response = http_post_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'bin', json_request, True) assert_equal( response.status, 400) #must be a 400 because we send an invalid bin request response = http_post_call( url.hostname, url.port, '/rest/getutxos/checkmempool' + self.FORMAT_SEPARATOR + 'bin', '', True) assert_equal( response.status, 400) #must be a 400 because we send an invalid bin request #test limits json_request = '/checkmempool/' for x in range(0, 20): json_request += txid + '-' + str(n) + '/' json_request = json_request.rstrip("/") response = http_post_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json', '', True) assert_equal(response.status, 400) #must be a 400 because we exceeding the limits json_request = '/checkmempool/' for x in range(0, 15): json_request += txid + '-' + str(n) + '/' json_request = json_request.rstrip("/") response = http_post_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json', '', True) assert_equal(response.status, 200) #must be a 200 because we are within the limits # Generate a block to not affect upcoming tests. auxpow.mineAuxpowBlock(self.nodes[0]) #generate self.sync_all() bb_hash = self.nodes[0].getbestblockhash() ################ # /rest/block/ # ################ # check binary format response = http_get_call( url.hostname, url.port, '/rest/block/' + bb_hash + self.FORMAT_SEPARATOR + "bin", True) assert_equal(response.status, 200) assert_greater_than(int(response.getheader('content-length')), 80) response_str = response.read() # compare with block header response_header = http_get_call( url.hostname, url.port, '/rest/headers/1/' + bb_hash + self.FORMAT_SEPARATOR + "bin", True) assert_equal(response_header.status, 200) headerLen = int(response_header.getheader('content-length')) assert_greater_than(headerLen, 80) response_header_str = response_header.read() assert_equal(response_str[0:headerLen], response_header_str) # check block hex format response_hex = http_get_call( url.hostname, url.port, '/rest/block/' + bb_hash + self.FORMAT_SEPARATOR + "hex", True) assert_equal(response_hex.status, 200) assert_greater_than(int(response_hex.getheader('content-length')), 160) response_hex_str = response_hex.read().strip() assert_equal(encode(response_str, "hex_codec"), response_hex_str) # compare with hex block header response_header_hex = http_get_call( url.hostname, url.port, '/rest/headers/1/' + bb_hash + self.FORMAT_SEPARATOR + "hex", True) assert_equal(response_header_hex.status, 200) assert_greater_than( int(response_header_hex.getheader('content-length')), 160) response_header_hex_str = response_header_hex.read().strip() headerLen = len(response_header_hex_str) assert_equal(response_hex_str[0:headerLen], response_header_hex_str) assert_equal(encode(response_header_str, "hex_codec"), response_header_hex_str) # check json format block_json_string = http_get_call( url.hostname, url.port, '/rest/block/' + bb_hash + self.FORMAT_SEPARATOR + 'json') block_json_obj = json.loads(block_json_string) assert_equal(block_json_obj['hash'], bb_hash) # compare with json block header response_header_json = http_get_call( url.hostname, url.port, '/rest/headers/1/' + bb_hash + self.FORMAT_SEPARATOR + "json", True) assert_equal(response_header_json.status, 200) response_header_json_str = response_header_json.read().decode('utf-8') json_obj = json.loads(response_header_json_str, parse_float=Decimal) assert_equal(len(json_obj), 1) #ensure that there is one header in the json response assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same #compare with normal RPC block response rpc_block_json = self.nodes[0].getblock(bb_hash) assert_equal(json_obj[0]['hash'], rpc_block_json['hash']) assert_equal(json_obj[0]['confirmations'], rpc_block_json['confirmations']) assert_equal(json_obj[0]['height'], rpc_block_json['height']) assert_equal(json_obj[0]['version'], rpc_block_json['version']) assert_equal(json_obj[0]['merkleroot'], rpc_block_json['merkleroot']) assert_equal(json_obj[0]['time'], rpc_block_json['time']) assert_equal(json_obj[0]['nonce'], rpc_block_json['nonce']) assert_equal(json_obj[0]['bits'], rpc_block_json['bits']) assert_equal(json_obj[0]['difficulty'], rpc_block_json['difficulty']) assert_equal(json_obj[0]['chainwork'], rpc_block_json['chainwork']) assert_equal(json_obj[0]['previousblockhash'], rpc_block_json['previousblockhash']) #see if we can get 5 headers in one response self.nodes[1].generate(5) self.sync_all() response_header_json = http_get_call( url.hostname, url.port, '/rest/headers/5/' + bb_hash + self.FORMAT_SEPARATOR + "json", True) assert_equal(response_header_json.status, 200) response_header_json_str = response_header_json.read().decode('utf-8') json_obj = json.loads(response_header_json_str) assert_equal(len(json_obj), 5) #now we should have 5 header objects # do tx test tx_hash = block_json_obj['tx'][0]['txid'] json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + tx_hash + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) assert_equal(json_obj['txid'], tx_hash) # check hex format response hex_string = http_get_call( url.hostname, url.port, '/rest/tx/' + tx_hash + self.FORMAT_SEPARATOR + "hex", True) assert_equal(hex_string.status, 200) assert_greater_than(int(response.getheader('content-length')), 10) # check block tx details # let's make 3 tx and mine them on node 1 txs = [] txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) self.sync_all() # check that there are exactly 3 transactions in the TX memory pool before generating the block json_string = http_get_call( url.hostname, url.port, '/rest/mempool/info' + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) assert_equal(json_obj['size'], 3) # the size of the memory pool should be greater than 3x ~100 bytes assert_greater_than(json_obj['bytes'], 300) # check that there are our submitted transactions in the TX memory pool json_string = http_get_call( url.hostname, url.port, '/rest/mempool/contents' + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) for tx in txs: assert_equal(tx in json_obj, True) # now mine the transactions newblockhash = self.nodes[1].generate(1) self.sync_all() #check if the 3 tx show up in the new block json_string = http_get_call( url.hostname, url.port, '/rest/block/' + newblockhash[0] + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) for tx in json_obj['tx']: if not 'coinbase' in tx['vin'][0]: #exclude coinbase assert_equal(tx['txid'] in txs, True) #check the same but without tx details json_string = http_get_call( url.hostname, url.port, '/rest/block/notxdetails/' + newblockhash[0] + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) for tx in txs: assert_equal(tx in json_obj['tx'], True) #test rest bestblock bb_hash = self.nodes[0].getbestblockhash() json_string = http_get_call(url.hostname, url.port, '/rest/chaininfo.json') json_obj = json.loads(json_string) assert_equal(json_obj['bestblockhash'], bb_hash) # Test name handling. self.name_tests(url)
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 run_test(self): url = urllib.parse.urlparse(self.nodes[0].url) self.log.info("Mining blocks...") self.nodes[0].generate(1) self.sync_all() self.nodes[2].generate(100) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() self.nodes[2].generate(1) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) #balance now should be 0.1 on node 1 # load the latest 0.1 tx over the REST API json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] ####################################### # GETUTXOS: query an unspent outpoint # ####################################### json_request = '/checkmempool/'+txid+'-'+str(n) json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is one utxo assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['utxos'][0]['value'], 0.1) ################################################# # GETUTXOS: now query an already spent outpoint # ################################################# json_request = '/checkmempool/'+vintx+'-0' json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is no utox in the response because this oupoint has been spent assert_equal(len(json_obj['utxos']), 0) #check bitmap assert_equal(json_obj['bitmap'], "0") ################################################## # GETUTXOS: now check both with the same request # ################################################## json_request = '/checkmempool/'+txid+'-'+str(n)+'/'+vintx+'-0' json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['bitmap'], "10") #test binary response bb_hash = self.nodes[0].getbestblockhash() binaryRequest = b'\x01\x02' binaryRequest += hex_str_to_bytes(txid) binaryRequest += pack("i", n) binaryRequest += hex_str_to_bytes(vintx) binaryRequest += pack("i", 0) bin_response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', binaryRequest) output = BytesIO() output.write(bin_response) output.seek(0) chainHeight = unpack("i", output.read(4))[0] hashFromBinResponse = hex(deser_uint256(output))[2:].zfill(64) assert_equal(bb_hash, hashFromBinResponse) #check if getutxo's chaintip during calculation was fine assert_equal(chainHeight, 102) #chain height must be 102 ############################ # GETUTXOS: mempool checks # ############################ # do a tx and don't sync txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] json_request = '/'+txid+'-'+str(n) json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 0) #there should be an outpoint because it has just added to the mempool json_request = '/checkmempool/'+txid+'-'+str(n) json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it has just added to the mempool #do some invalid requests json_request = '{"checkmempool' response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True) assert_equal(response.status, 400) #must be a 400 because we send an invalid json request json_request = '{"checkmempool' response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True) assert_equal(response.status, 400) #must be a 400 because we send an invalid bin request response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True) assert_equal(response.status, 400) #must be a 400 because we send an invalid bin request #test limits json_request = '/checkmempool/' for x in range(0, 20): json_request += txid+'-'+str(n)+'/' json_request = json_request.rstrip("/") response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) assert_equal(response.status, 400) #must be a 400 because we exceeding the limits json_request = '/checkmempool/' for x in range(0, 15): json_request += txid+'-'+str(n)+'/' json_request = json_request.rstrip("/") response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) assert_equal(response.status, 200) #must be a 200 because we are within the limits # Generate a block to not affect upcoming tests. auxpow.mineAuxpowBlock(self.nodes[0]) #generate self.sync_all() bb_hash = self.nodes[0].getbestblockhash() ################ # /rest/block/ # ################ # check binary format response = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True) assert_equal(response.status, 200) assert_greater_than(int(response.getheader('content-length')), 80) response_str = response.read() # compare with block header response_header = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True) assert_equal(response_header.status, 200) headerLen = int(response_header.getheader('content-length')) assert_greater_than(headerLen, 80) response_header_str = response_header.read() assert_equal(response_str[0:headerLen], response_header_str) # check block hex format response_hex = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True) assert_equal(response_hex.status, 200) assert_greater_than(int(response_hex.getheader('content-length')), 160) response_hex_str = response_hex.read().strip() assert_equal(encode(response_str, "hex_codec"), response_hex_str) # compare with hex block header response_header_hex = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True) assert_equal(response_header_hex.status, 200) assert_greater_than(int(response_header_hex.getheader('content-length')), 160) response_header_hex_str = response_header_hex.read().strip() headerLen = len (response_header_hex_str) assert_equal(response_hex_str[0:headerLen], response_header_hex_str) assert_equal(encode(response_header_str, "hex_codec"), response_header_hex_str) # check json format block_json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json') block_json_obj = json.loads(block_json_string) assert_equal(block_json_obj['hash'], bb_hash) # compare with json block header response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"json", True) assert_equal(response_header_json.status, 200) response_header_json_str = response_header_json.read().decode('utf-8') json_obj = json.loads(response_header_json_str, parse_float=Decimal) assert_equal(len(json_obj), 1) #ensure that there is one header in the json response assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same #compare with normal RPC block response rpc_block_json = self.nodes[0].getblock(bb_hash) assert_equal(json_obj[0]['hash'], rpc_block_json['hash']) assert_equal(json_obj[0]['confirmations'], rpc_block_json['confirmations']) assert_equal(json_obj[0]['height'], rpc_block_json['height']) assert_equal(json_obj[0]['version'], rpc_block_json['version']) assert_equal(json_obj[0]['merkleroot'], rpc_block_json['merkleroot']) assert_equal(json_obj[0]['time'], rpc_block_json['time']) assert_equal(json_obj[0]['nonce'], rpc_block_json['nonce']) assert_equal(json_obj[0]['bits'], rpc_block_json['bits']) assert_equal(json_obj[0]['difficulty'], rpc_block_json['difficulty']) assert_equal(json_obj[0]['chainwork'], rpc_block_json['chainwork']) assert_equal(json_obj[0]['previousblockhash'], rpc_block_json['previousblockhash']) #see if we can get 5 headers in one response self.nodes[1].generate(5) self.sync_all() response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/5/'+bb_hash+self.FORMAT_SEPARATOR+"json", True) assert_equal(response_header_json.status, 200) response_header_json_str = response_header_json.read().decode('utf-8') json_obj = json.loads(response_header_json_str) assert_equal(len(json_obj), 5) #now we should have 5 header objects # do tx test tx_hash = block_json_obj['tx'][0]['txid'] json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) assert_equal(json_obj['txid'], tx_hash) # check hex format response hex_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"hex", True) assert_equal(hex_string.status, 200) assert_greater_than(int(response.getheader('content-length')), 10) # check block tx details # let's make 3 tx and mine them on node 1 txs = [] txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) self.sync_all() # check that there are exactly 3 transactions in the TX memory pool before generating the block json_string = http_get_call(url.hostname, url.port, '/rest/mempool/info'+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(json_obj['size'], 3) # the size of the memory pool should be greater than 3x ~100 bytes assert_greater_than(json_obj['bytes'], 300) # check that there are our submitted transactions in the TX memory pool json_string = http_get_call(url.hostname, url.port, '/rest/mempool/contents'+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) for tx in txs: assert_equal(tx in json_obj, True) # now mine the transactions newblockhash = self.nodes[1].generate(1) self.sync_all() #check if the 3 tx show up in the new block json_string = http_get_call(url.hostname, url.port, '/rest/block/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) for tx in json_obj['tx']: if not 'coinbase' in tx['vin'][0]: #exclude coinbase assert_equal(tx['txid'] in txs, True) #check the same but without tx details json_string = http_get_call(url.hostname, url.port, '/rest/block/notxdetails/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) for tx in txs: assert_equal(tx in json_obj['tx'], True) #test rest bestblock bb_hash = self.nodes[0].getbestblockhash() json_string = http_get_call(url.hostname, url.port, '/rest/chaininfo.json') json_obj = json.loads(json_string) assert_equal(json_obj['bestblockhash'], bb_hash) # Test name handling. self.name_tests(url)
def 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'] assert_raises_jsonrpc(-8, 'block hash unknown', self.nodes[0].getauxblock, auxblock['hash'], "x") # Invalid format for auxpow. assert_raises_jsonrpc(-1, None, self.nodes[0].getauxblock, 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].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 run_test(self): url = urlparse.urlparse(self.nodes[0].url) print "Mining blocks..." self.nodes[0].generate(1) self.sync_all() self.nodes[2].generate(100) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() self.nodes[2].generate(1) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) #balance now should be 0.1 on node 1 # load the latest 0.1 tx over the REST API json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + txid + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0][ 'txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] ###################################### # GETUTXOS: query a unspent outpoint # ###################################### json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + txid + '","n":' + str( n) + '}]}' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request) json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is one utxo assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['utxos'][0]['value'], 0.1) ################################################ # GETUTXOS: now query a already spent outpoint # ################################################ json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + vintx + '","n":0}]}' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request) json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is no utox in the response because this oupoint has been spent assert_equal(len(json_obj['utxos']), 0) #check bitmap assert_equal(json_obj['bitmap'], "0") ################################################## # GETUTXOS: now check both with the same request # ################################################## json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + txid + '","n":' + str( n) + '},{"txid":"' + vintx + '","n":0}]}' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request) json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['bitmap'], "10") #test binary response bb_hash = self.nodes[0].getbestblockhash() binaryRequest = b'\x01\x02' binaryRequest += binascii.unhexlify(txid) binaryRequest += pack("i", n) binaryRequest += binascii.unhexlify(vintx) binaryRequest += pack("i", 0) bin_response = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'bin', binaryRequest) output = StringIO.StringIO() output.write(bin_response) output.seek(0) chainHeight = unpack("i", output.read(4))[0] hashFromBinResponse = hex( deser_uint256(output))[2:].zfill(65).rstrip("L") assert_equal( bb_hash, hashFromBinResponse ) #check if getutxo's chaintip during calculation was fine assert_equal(chainHeight, 102) #chain height must be 102 ############################ # GETUTXOS: mempool checks # ############################ # do a tx and don't sync txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + txid + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0][ 'txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] json_request = '{"checkmempool":false,"outpoints":[{"txid":"' + txid + '","n":' + str( n) + '}]}' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request) json_obj = json.loads(json_string) assert_equal( len(json_obj['utxos']), 0 ) #there should be a outpoint because it has just added to the mempool json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + txid + '","n":' + str( n) + '}]}' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request) json_obj = json.loads(json_string) assert_equal( len(json_obj['utxos']), 1 ) #there should be a outpoint because it has just added to the mempool #do some invalid requests json_request = '{"checkmempool' response = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request, True) assert_equal( response.status, 500) #must be a 500 because we send a invalid json request json_request = '{"checkmempool' response = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'bin', json_request, True) assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request #test limits json_request = '{"checkmempool":true,"outpoints":[' for x in range(0, 200): json_request += '{"txid":"' + txid + '","n":' + str(n) + '},' json_request = json_request.rstrip(",") json_request += "]}" response = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request, True) assert_equal(response.status, 500) #must be a 500 because we exceeding the limits json_request = '{"checkmempool":true,"outpoints":[' for x in range(0, 90): json_request += '{"txid":"' + txid + '","n":' + str(n) + '},' json_request = json_request.rstrip(",") json_request += "]}" response = http_get_call( url.hostname, url.port, '/rest/getutxos' + self.FORMAT_SEPARATOR + 'json', json_request, True) assert_equal(response.status, 200) #must be a 500 because we exceeding the limits auxpow.mineAuxpowBlock(self.nodes[0]) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() ################ # /rest/block/ # ################ # check binary format response = http_get_call( url.hostname, url.port, '/rest/block/' + bb_hash + self.FORMAT_SEPARATOR + "bin", "", True) assert_equal(response.status, 200) assert_greater_than(int(response.getheader('content-length')), 80) response_str = response.read() # compare with block header response_header = http_get_call( url.hostname, url.port, '/rest/headers/1/' + bb_hash + self.FORMAT_SEPARATOR + "bin", "", True) assert_equal(response_header.status, 200) headerLen = int(response_header.getheader('content-length')) assert_greater_than(headerLen, 80) response_header_str = response_header.read() assert_equal(response_str[0:headerLen], response_header_str) # check block hex format response_hex = http_get_call( url.hostname, url.port, '/rest/block/' + bb_hash + self.FORMAT_SEPARATOR + "hex", "", True) assert_equal(response_hex.status, 200) assert_greater_than(int(response_hex.getheader('content-length')), 160) response_hex_str = response_hex.read().strip() assert_equal(response_str.encode("hex"), response_hex_str) # compare with hex block header response_header_hex = http_get_call( url.hostname, url.port, '/rest/headers/1/' + bb_hash + self.FORMAT_SEPARATOR + "hex", "", True) assert_equal(response_header_hex.status, 200) assert_greater_than( int(response_header_hex.getheader('content-length')), 160) response_header_hex_str = response_header_hex.read().strip() headerLen = len(response_header_hex_str) assert_equal(response_hex_str[0:headerLen], response_header_hex_str) assert_equal(response_header_str.encode("hex"), response_header_hex_str) # check json format json_string = http_get_call( url.hostname, url.port, '/rest/block/' + bb_hash + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) assert_equal(json_obj['hash'], bb_hash) # do tx test tx_hash = json_obj['tx'][0]['txid'] json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + tx_hash + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) assert_equal(json_obj['txid'], tx_hash) # check hex format response hex_string = http_get_call( url.hostname, url.port, '/rest/tx/' + tx_hash + self.FORMAT_SEPARATOR + "hex", "", True) assert_equal(hex_string.status, 200) assert_greater_than(int(response.getheader('content-length')), 10) # check block tx details # let's make 3 tx and mine them on node 1 txs = [] txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) self.sync_all() # now mine the transactions newblockhash = self.nodes[1].generate(1) self.sync_all() #check if the 3 tx show up in the new block json_string = http_get_call( url.hostname, url.port, '/rest/block/' + newblockhash[0] + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) for tx in json_obj['tx']: if not 'coinbase' in tx['vin'][0]: #exclude coinbase assert_equal(tx['txid'] in txs, True) #check the same but without tx details json_string = http_get_call( url.hostname, url.port, '/rest/block/notxdetails/' + newblockhash[0] + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) for tx in txs: assert_equal(tx in json_obj['tx'], True) #test rest bestblock bb_hash = self.nodes[0].getbestblockhash() json_string = http_get_call(url.hostname, url.port, '/rest/chaininfo.json') json_obj = json.loads(json_string) assert_equal(json_obj['bestblockhash'], bb_hash) # Test name handling. self.name_tests(url)
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['chainindex'], 0) assert_equal(auxJson['merklebranch'], []) assert_equal(auxJson['chainmerklebranch'], []) 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 run_test(self): url = urlparse.urlparse(self.nodes[0].url) print "Mining blocks..." self.nodes[0].generate(1) self.sync_all() self.nodes[2].generate(100) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() self.nodes[2].generate(1) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) #balance now should be 0.1 on node 1 # load the latest 0.1 tx over the REST API json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] ###################################### # GETUTXOS: query a unspent outpoint # ###################################### json_request = '/checkmempool/'+txid+'-'+str(n) json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is one utxo assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['utxos'][0]['value'], 0.1) ################################################ # GETUTXOS: now query a already spent outpoint # ################################################ json_request = '/checkmempool/'+vintx+'-0' json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) #check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) #make sure there is no utox in the response because this oupoint has been spent assert_equal(len(json_obj['utxos']), 0) #check bitmap assert_equal(json_obj['bitmap'], "0") ################################################## # GETUTXOS: now check both with the same request # ################################################## json_request = '/checkmempool/'+txid+'-'+str(n)+'/'+vintx+'-0' json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['bitmap'], "10") #test binary response bb_hash = self.nodes[0].getbestblockhash() binaryRequest = b'\x01\x02' binaryRequest += binascii.unhexlify(txid) binaryRequest += pack("i", n); binaryRequest += binascii.unhexlify(vintx); binaryRequest += pack("i", 0); bin_response = http_get_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', binaryRequest) output = StringIO.StringIO() output.write(bin_response) output.seek(0) chainHeight = unpack("i", output.read(4))[0] hashFromBinResponse = hex(deser_uint256(output))[2:].zfill(65).rstrip("L") assert_equal(bb_hash, hashFromBinResponse) #check if getutxo's chaintip during calculation was fine assert_equal(chainHeight, 102) #chain height must be 102 ############################ # GETUTXOS: mempool checks # ############################ # do a tx and don't sync txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] json_request = '/'+txid+'-'+str(n) json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 0) #there should be a outpoint because it has just added to the mempool json_request = '/checkmempool/'+txid+'-'+str(n) json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(len(json_obj['utxos']), 1) #there should be a outpoint because it has just added to the mempool #do some invalid requests json_request = '{"checkmempool' response = http_get_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True) assert_equal(response.status, 500) #must be a 500 because we send a invalid json request json_request = '{"checkmempool' response = http_get_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True) assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request response = http_get_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True) assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request #test limits json_request = '/checkmempool/' for x in range(0, 20): json_request += txid+'-'+str(n)+'/' json_request = json_request.rstrip("/") response = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) assert_equal(response.status, 500) #must be a 500 because we exceeding the limits json_request = '/checkmempool/' for x in range(0, 15): json_request += txid+'-'+str(n)+'/' json_request = json_request.rstrip("/"); response = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) assert_equal(response.status, 200) #must be a 500 because we exceeding the limits auxpow.mineAuxpowBlock(self.nodes[0]) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() ################ # /rest/block/ # ################ # check binary format response = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"bin", "", True) assert_equal(response.status, 200) assert_greater_than(int(response.getheader('content-length')), 80) response_str = response.read() # compare with block header response_header = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"bin", "", True) assert_equal(response_header.status, 200) headerLen = int(response_header.getheader('content-length')) assert_greater_than(headerLen, 80) response_header_str = response_header.read() assert_equal(response_str[0:headerLen], response_header_str) # check block hex format response_hex = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"hex", "", True) assert_equal(response_hex.status, 200) assert_greater_than(int(response_hex.getheader('content-length')), 160) response_hex_str = response_hex.read().strip() assert_equal(response_str.encode("hex"), response_hex_str) # compare with hex block header response_header_hex = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"hex", "", True) assert_equal(response_header_hex.status, 200) assert_greater_than(int(response_header_hex.getheader('content-length')), 160) response_header_hex_str = response_header_hex.read().strip() headerLen = len (response_header_hex_str) assert_equal(response_hex_str[0:headerLen], response_header_hex_str) assert_equal(response_header_str.encode("hex"), response_header_hex_str) # check json format json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) assert_equal(json_obj['hash'], bb_hash) # do tx test tx_hash = json_obj['tx'][0]['txid']; json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json") json_obj = json.loads(json_string) assert_equal(json_obj['txid'], tx_hash) # check hex format response hex_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"hex", "", True) assert_equal(hex_string.status, 200) assert_greater_than(int(response.getheader('content-length')), 10) # check block tx details # let's make 3 tx and mine them on node 1 txs = [] txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) self.sync_all() # now mine the transactions newblockhash = self.nodes[1].generate(1) self.sync_all() #check if the 3 tx show up in the new block json_string = http_get_call(url.hostname, url.port, '/rest/block/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) for tx in json_obj['tx']: if not 'coinbase' in tx['vin'][0]: #exclude coinbase assert_equal(tx['txid'] in txs, True) #check the same but without tx details json_string = http_get_call(url.hostname, url.port, '/rest/block/notxdetails/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') json_obj = json.loads(json_string) for tx in txs: assert_equal(tx in json_obj['tx'], True) #test rest bestblock bb_hash = self.nodes[0].getbestblockhash() json_string = http_get_call(url.hostname, url.port, '/rest/chaininfo.json') json_obj = json.loads(json_string) assert_equal(json_obj['bestblockhash'], bb_hash) # Test name handling. self.name_tests(url)
def run_test(self): self.url = urllib.parse.urlparse(self.nodes[0].url) self.log.info("Mine blocks and send Bitcoin to node 1") # Random address so node1's balance doesn't increase not_related_address = "2MxqoHEdNQTyYeX1mHcbrrpzgojbosTpCvJ" self.nodes[0].generate(1) self.sync_all() self.nodes[1].generatetoaddress(100, not_related_address) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() self.nodes[1].generatetoaddress(1, not_related_address) self.sync_all() bb_hash = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) self.log.info("Load the transaction using the /tx URI") json_obj = self.test_rest_request("/tx/{}".format(txid)) spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout']) # get the vin to later check for utxo (should be spent by then) # get n of 0.1 outpoint n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1')) spending = (txid, n) self.log.info("Query an unspent TXO using the /getutxos URI") json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spending)) # Check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) # Make sure there is one utxo assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['utxos'][0]['value'], Decimal('0.1')) self.log.info("Query a spent TXO using the /getutxos URI") json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spent)) # Check chainTip response assert_equal(json_obj['chaintipHash'], bb_hash) # Make sure there is no utxo in the response because this outpoint has been spent assert_equal(len(json_obj['utxos']), 0) # Check bitmap assert_equal(json_obj['bitmap'], "0") self.log.info("Query two TXOs using the /getutxos URI") json_obj = self.test_rest_request("/getutxos/{}-{}/{}-{}".format(*(spending + spent))) assert_equal(len(json_obj['utxos']), 1) assert_equal(json_obj['bitmap'], "10") self.log.info("Query the TXOs using the /getutxos URI with a binary response") bin_request = b'\x01\x02' for txid, n in [spending, spent]: bin_request += hex_str_to_bytes(txid) bin_request += pack("i", n) bin_response = self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.BIN, body=bin_request, ret_type=RetType.BYTES) output = BytesIO(bin_response) chain_height, = unpack("i", output.read(4)) response_hash = binascii.hexlify(output.read(32)[::-1]).decode('ascii') assert_equal(bb_hash, response_hash) # check if getutxo's chaintip during calculation was fine assert_equal(chain_height, 102) # chain height must be 102 self.log.info("Test the /getutxos URI with and without /checkmempool") # Create a transaction, check that it's found with /checkmempool, but # not found without. Then confirm the transaction and check that it's # found with or without /checkmempool. # do a tx and don't sync txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) json_obj = self.test_rest_request("/tx/{}".format(txid)) # get the spent output to later check for utxo (should be spent by then) spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout']) # get n of 0.1 outpoint n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1')) spending = (txid, n) json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spending)) assert_equal(len(json_obj['utxos']), 0) json_obj = self.test_rest_request("/getutxos/checkmempool/{}-{}".format(*spending)) assert_equal(len(json_obj['utxos']), 1) json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spent)) assert_equal(len(json_obj['utxos']), 1) json_obj = self.test_rest_request("/getutxos/checkmempool/{}-{}".format(*spent)) assert_equal(len(json_obj['utxos']), 0) self.nodes[0].generate(1) self.sync_all() json_obj = self.test_rest_request("/getutxos/{}-{}".format(*spending)) assert_equal(len(json_obj['utxos']), 1) json_obj = self.test_rest_request("/getutxos/checkmempool/{}-{}".format(*spending)) assert_equal(len(json_obj['utxos']), 1) # Do some invalid requests self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.JSON, body='{"checkmempool', status=400, ret_type=RetType.OBJ) self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.BIN, body='{"checkmempool', status=400, ret_type=RetType.OBJ) self.test_rest_request("/getutxos/checkmempool", http_method='POST', req_type=ReqType.JSON, status=400, ret_type=RetType.OBJ) # Test limits long_uri = '/'.join(["{}-{}".format(txid, n_) for n_ in range(20)]) self.test_rest_request("/getutxos/checkmempool/{}".format(long_uri), http_method='POST', status=400, ret_type=RetType.OBJ) long_uri = '/'.join(['{}-{}'.format(txid, n_) for n_ in range(15)]) self.test_rest_request("/getutxos/checkmempool/{}".format(long_uri), http_method='POST', status=200) auxpow.mineAuxpowBlock(self.nodes[0]) # generate block to not affect upcoming tests self.sync_all() bb_hash = self.nodes[0].getbestblockhash() self.log.info("Test the /block and /headers URIs") bb_hash = self.nodes[0].getbestblockhash() # Check binary format response = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ) assert_greater_than(int(response.getheader('content-length')), 80) response_bytes = response.read() # Compare with block header response_header = self.test_rest_request("/headers/1/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ) headerLen = int(response_header.getheader('content-length')) assert_greater_than(headerLen, 80) response_header_bytes = response_header.read() assert_equal(response_bytes[:headerLen], response_header_bytes) # Check block hex format response_hex = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) assert_greater_than(int(response_hex.getheader('content-length')), 160) response_hex_bytes = response_hex.read().strip(b'\n') assert_equal(binascii.hexlify(response_bytes), response_hex_bytes) # Compare with hex block header response_header_hex = self.test_rest_request("/headers/1/{}".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) assert_greater_than(int(response_header_hex.getheader('content-length')), 160) response_header_hex_bytes = response_header_hex.read().strip() headerLen = len (response_header_hex_bytes) // 2 assert_equal(binascii.hexlify(response_bytes[:headerLen]), response_header_hex_bytes) # Check json format block_json_obj = self.test_rest_request("/block/{}".format(bb_hash)) assert_equal(block_json_obj['hash'], bb_hash) # Compare with json block header json_obj = self.test_rest_request("/headers/1/{}".format(bb_hash)) assert_equal(len(json_obj), 1) # ensure that there is one header in the json response assert_equal(json_obj[0]['hash'], bb_hash) # request/response hash should be the same # Compare with normal RPC block response rpc_block_json = self.nodes[0].getblock(bb_hash) for key in ['hash', 'confirmations', 'height', 'version', 'merkleroot', 'time', 'nonce', 'bits', 'difficulty', 'chainwork', 'previousblockhash']: assert_equal(json_obj[0][key], rpc_block_json[key]) # See if we can get 5 headers in one response self.nodes[1].generate(5) self.sync_all() json_obj = self.test_rest_request("/headers/5/{}".format(bb_hash)) assert_equal(len(json_obj), 5) # now we should have 5 header objects self.log.info("Test the /tx URI") tx_hash = block_json_obj['tx'][0]['txid'] json_obj = self.test_rest_request("/tx/{}".format(tx_hash)) assert_equal(json_obj['txid'], tx_hash) # Check hex format response hex_response = self.test_rest_request("/tx/{}".format(tx_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ) assert_greater_than_or_equal(int(hex_response.getheader('content-length')), json_obj['size']*2) self.log.info("Test tx inclusion in the /mempool and /block URIs") # Make 3 tx and mine them on node 1 txs = [] txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) self.sync_all() # Check that there are exactly 3 transactions in the TX memory pool before generating the block json_obj = self.test_rest_request("/mempool/info") assert_equal(json_obj['size'], 3) # the size of the memory pool should be greater than 3x ~100 bytes assert_greater_than(json_obj['bytes'], 300) # Check that there are our submitted transactions in the TX memory pool json_obj = self.test_rest_request("/mempool/contents") for i, tx in enumerate(txs): assert tx in json_obj assert_equal(json_obj[tx]['spentby'], txs[i + 1:i + 2]) assert_equal(json_obj[tx]['depends'], txs[i - 1:i]) # Now mine the transactions newblockhash = self.nodes[1].generate(1) self.sync_all() # Check if the 3 tx show up in the new block json_obj = self.test_rest_request("/block/{}".format(newblockhash[0])) non_coinbase_txs = {tx['txid'] for tx in json_obj['tx'] if 'coinbase' not in tx['vin'][0]} assert_equal(non_coinbase_txs, set(txs)) # Check the same but without tx details json_obj = self.test_rest_request("/block/notxdetails/{}".format(newblockhash[0])) for tx in txs: assert tx in json_obj['tx'] self.log.info("Test the /chaininfo URI") bb_hash = self.nodes[0].getbestblockhash() json_obj = self.test_rest_request("/chaininfo") assert_equal(json_obj['bestblockhash'], bb_hash) # Test name handling. self.log.info("Test the /name URI") self.name_tests()